1.如圖
2.代碼(純手打):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>canvas教程</title>
<style>
button
{
border:4px gray;
padding:10px 10px;
background:#15288fa1;
width:100px;
border-radius:10px;
box-shadow:10px 10px 10px #a7afd99c;
color:white;
}
button:hover {
background-color: #155aafa1; /* Green */
color: white;
}
</style>
<script type="text/javascript">
</script>
</head>
<body>
<canvas id="game" width="440" height="440"></canvas>
<div>
<button onclick="drawGame()">生成</button>
<button onclick="changeForm()">旋轉</button>
<br>
<br>
<button onclick="left()"><</button>
<button onclick="right()">></button>
<button onclick="down()">V</button>
</div>
<script>
var n = [
[0,0,0,0],
[0,0,0,0],
[0,0,0,0],
[0,0,0,0]
];
var startX =0;
var startY =0;
var width = 10;
var square = this.width*4 + this.width*0.1*4;
var len= 44*10;
var pan = new Array();//底部
for(var i=0;i < len/(this.width*1.1);i++){
pan[i] = 0;
}
var pannel = new Array(); //先聲明一維
for(var i=0;i < len/(this.width*1.1);i++){ //一維長度
pannel[i]=new Array(); //在聲明二維
for(var j=0;j< len/(this.width*1.1);j++){ //二維長度
pannel[i][j] =0;
}
}
/*創建底面*/
let canvasGame = document.querySelector("#game");
let ctx = canvasGame.getContext("2d");
function drawGame() {
//清零
for(var i = 0; i < this.n.length; i++) {
for(var j = 0; j < this.n[i].length; j++) {
this.n[i][j] = 0;
}
}
drawForm(ctx, this.n);
}
initGame();
function initGame() {
drawGame();
requestAnimationFrame(function step(){
setTimeout(function(){
fall();
panClear();
gameOver();
requestAnimationFrame(step);
}, 1000);
});
}
/*變出小方塊*/
function drawForm(ctx, n){
this.startX = 0;
this.startY = 0;
//隨機生成小方塊
var i = parseInt(Math.random()*4/1);
if(i==0) {
//生成方塊
n[2][2] = 1;
n[2][1] = 1;
n[1][2] = 1;
n[1][1] = 1;
}else if(i==1){
//生成“1”
var I = parseInt(Math.random()*2/1);
if(I == 0) {
//生成豎着的1
n[0][1] = 1;
n[1][1] = 1;
n[2][1] = 1;
n[3][1] = 1;
}else{
//生成橫着的一
n[1][0] = 1;
n[1][1] = 1;
n[1][2] = 1;
n[1][3] = 1;
}
}else if(i==2){
//生成“Z”
var z = parseInt(Math.random()*4/1);
switch(z) {
case 0 : //Z
n[0][1] = 1;
n[1][1] = 1;
n[2][1] = 1;
n[2][2] = 1;
break;
case 1 : //反Z
n[0][1] = 1;
n[0][2] = 1;
n[1][0] = 1;
n[1][1] = 1;break;
case 2 : //順時針旋轉90度的Z
n[0][1] = 1;
n[1][1] = 1;
n[1][0] = 1;
n[2][0] = 1;break;
case 3 : //順時針旋轉90度的反Z
n[0][0] = 1;
n[1][0] = 1;
n[1][1] = 1;
n[2][1] = 1;break;
}
}else {
var L = parseInt(Math.random()*8/1);
switch(L) {
case 0 : //Z
//生成L
/**
* #
* #
* # #
*/
n[0][0] = 1;
n[1][0] = 1;
n[2][0] = 1;
n[2][1] = 1;break;
case 1 : //Z
//生成對稱L
/**
* #
* #
* # #
*/
n[0][1] = 1;
n[1][1] = 1;
n[2][1] = 1;
n[2][0] = 1;break;
case 2 : //7
/**
* # #
* #
* #
*/
n[0][1] = 1;
n[1][1] = 1;
n[2][1] = 1;
n[0][0] = 1;break;
case 3 :
/**
* # #
* #
* #
*/
n[0][0] = 1;
n[1][0] = 1;
n[2][0] = 1;
n[0][1] = 1;break;
case 4 :
/**
* # # #
* #
*/
n[0][0] = 1;
n[0][1] = 1;
n[0][2] = 1;
n[1][2] = 1;break;
case 5 :
/**
* # # #
* #
*/
n[0][0] = 1;
n[0][1] = 1;
n[0][2] = 1;
n[1][0] = 1;break;
case 6 :
/**
* #
* # # #
*/
n[1][0] = 1;
n[1][1] = 1;
n[1][2] = 1;
n[0][2] = 1;break;
case 7 :
/**
* #
* # # #
*/
n[1][0] = 1;
n[1][1] = 1;
n[1][2] = 1;
n[0][0] = 1;break;
}
}
this.n = n;
drawNset();
}
/**
* [changeForm 順時針旋轉90°]
* @return {[type]} [先轉置,後顛倒列]
*/
function changeForm(){
clearRectForm();
/**
* 0 1 2 3
* 1 4 5 6
* 2 7 8 9
* 3 2 1 0
*/
//轉置
/**
* 0 1 2 3
* 1 4 7 2
* 2 5 8 1
* 3 6 9 0
*/
for(var i = 1; i < this.n.length; i++) {
for(var j = 0; j < i; j++) {
var temp = this.n[i][j];
this.n[i][j] = this.n[j][i];
this.n[j][i] = temp;
}
}
//顛倒列
/**
* 3 2 1 0
* 2 7 4 1
* 1 8 5 2
* 0 9 6 3
*/
for(var i = 0; i < this.n.length; i++) {
for(var j = 0; j < this.n.length/2; j++) {
var temp = this.n[i][j];
this.n[i][j] = this.n[i][this.n.length-1-j];
this.n[i][this.n.length-1-j] = temp;
}
}
drawNset();
}
function drawNset(){
var gap = this.width * 0.1;
//畫方塊
for(var i = 0; i < n.length; i++) {
for(var j = 0; j < n[i].length; j++) {
if(n[i][j] > 0) {
//ctx.moveTo(x,y);
x = (this.startX + j)*(this.width+gap);
y = (this.startY + i)*(this.width+gap);
ctx.fillRect(x, y, this.width, this.width);
}
}
}
}
function clearRectForm(){
var gap = this.width * 0.1;
//清除方塊
for(var i = 0; i < n.length; i++) {
for(var j = 0; j < n[i].length; ) {
if(n[i][j] > 0) {
//ctx.moveTo(x,y);
x = (this.startX + j)*(this.width+gap);
y = (this.startY + i)*(this.width+gap);
ctx.clearRect(x, y, this.width, this.width);
}
j++;
}
}
}
/**
* [fall 下移]
* @return {[type]} [description]
*/
function fall() {
clearRectForm();
this.startY = this.startY + 1;
drawNset();
}
/**
* [right 向右]
* @return {[type]} [description]
*/
function right() {
var find = 0;
for(var i = 0; i < this.n.length && find == 0; i++){
for(var j = this.n.length - 1; j > 0; ){
if(this.n[i][j] == 1) {
find = 1;
break;
}
j--;
}
}
if(this.startX + j < this.pan.length - 1) {
clearRectForm();
this.startX = this.startX + 1;
drawNset();
}
}
/**
* [left 向左]
* @return {[type]} [description]
*/
function left() {
var find = 0;
for(var i = 0; i < this.n.length && find == 0; i++){
for(var j = 0; j < this.n.length; j++){
if(this.n[j][i] == 1) {
find = 1;
break;
}
}
}
if(startX + i > 1) {
clearRectForm();
this.startX = this.startX - 1;
drawNset();
}
}
/**
* [getMaxHeight 當前城牆底部距離上部的高度]
* @return {[type]} [description]
*/
function getMaxHeight(){
return this.len;
}
/**
* [getFormHeight 實心方塊的底部距離底部的高度]
* @return {[type]} [description]
*/
function getFormBottom(){
var bottom = 0;
for(var i = 0; i < this.n.length; i++) {
for(var j = 0; j < this.n[i].length; j++) {
if(this.n[i][j] > 0){
if(j > bottom) {
bottom = j;
}
}
}
}
return getMaxHeight() - (bottom*1.1*this.width + this.startY);
}
/**
* [getPoint 獲取某個實心方塊在整個遊戲桌面的座標]
* @param {[type]} x [數組n中]
* @param {[type]} y [數組n中]
* @return {[type]} [description]
*/
function getPoint(x,y) {
console.log('startX,startY',startX + "," + startY);
return [this.startX + x,this.startY + y];
}
/**
* [changePan 方塊降落過程底部城牆變化]
* @return {[type]} [description]
*/
function changePan(){
console.log(distence());
this.startY = this.startY + distence() - 1 ;
if(this.startY < 0) {
this.startY = 0;
}
for(var j = 0; j < this.n.length; j++) {
for(var i = 0; i < this.n.length; i++) {
if(n[i][j] > 0) {
console.log('j,i',j + "," + i);
xy = getPoint(j,i);//i行 對應y座標;j列對應x/座標
console.log(xy);
this.pannel[xy[0]][this.pannel.length - xy[1]] = 1;//城牆變化
this.pan[xy[0]] = this.pannel.length - xy[1] ;
}
}
}
drawNset();
}
function distence(){
var min = this.len;
var temp = 0 ;
var xy = new Array();
for(var i = 0; i < this.n.length; i++) {
for(var j = 0; j < this.n[i].length; j++) {
if(n[i][j] > 0) {
xy = getPoint(j,i);//i行 對應y座標;j列對應x/座標
temp = this.pan.length - xy[1] - this.pan[xy[0]];
if (temp < min) {
//距離城牆最短距離
min = temp;
}
}
}
}
return min;
}
/**
* [getFormHeight 實心方塊距離左邊]
* @return {[type]} [description]
*/
function getFormLeft(){
// var count = 0;
// for(var i = 0; i < this.n.length; i++) {
// for(var j = 0; j < this.n[i].length; j++) {
// if(this.n[i][j] > 0){
// count++;
// continue;
// }
// }
// }
// return count * this.width*1.1 + this.startX;
}
function down(){
clearRectForm();
changePan();
panClear();
}
function panClear(){
if(distence()<=1) {
console.log("oooooooooook");
var topSet = new Array();
var minCount = this.pan.length;
for(var i = 0; i < this.pan.length; i++) {
var top = 0;
//從上往下找第一個實心塊
for(var j = this.pannel.length - 1; j > 0; j--) {
if(this.pannel[i][j]!=0) {
top = j;
break;
}
}
topSet[i] = top;
//再往下找一個空心塊
while(j > 0 &&this.pannel[i][j--]==1){
}
var tempCount = top - j;//得到當前列高度
if(tempCount < minCount) {
minCount = tempCount;
}
}
if(minCount > 0) {
//城牆下降
for(var i = 0; i < this.pan.length; i++){
var index = 0;
for(var j = topSet[i] ; tempCount > index && j > 0; j--){
this.pannel[i][j] = 0;
this.pan[i] = this.pan[i]--;
//清除正方塊
var gap = this.width * 0.1;
//清除方塊
//ctx.moveTo(x,y);
var x = (i - 1)*(this.width+gap);
var y = (this.pannel.length - j -1 )*(this.width+gap);
ctx.clearRect(x, y, this.width, this.width);
index++;
}
}
}
drawGame();
}
}
function gameOver(){
for(var i = 0; i < this.pannel.length; i++) {
if(this.pannel[i][this.pannel.length - 1] == 1) {
alert("game over !");
window.location.reload();
}
}
}
</script>
</body>
</html>