Blackbing Playground

Tetris Game(javascript 俄羅斯方塊)

今天被問到俄羅斯方塊的作法,於是動手實做了一下,簡單介紹一下大概的概念:

1. css layout 設計

Tetris_layout
利用div建立每一塊Block,這裡重要的屬性是display:inline-block,建立浮動的方塊元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.stage{
border:2px solid #CCC;
padding:5px;
margin:0px;
width:316px;

}
.stage .grid{
display:inline-block;
border: 0px;
width:16px;
height:16px;
outline:1px solid #000;
margin:0px;
padding:0px;
}
.stage .grid.blue{
background-color:blue;
}
.stage .grid.grey{
background-color:grey;
}

2. 資料結構設計

每一個grid的結構

1
2
3
4
5
6
7
8
var blockStructure = function(){
//代表是否填滿,用來判斷是否要著色。
this.fill = false;
//代表是否為堆疊,用來判斷是否可以移動。
this.stacked = false;
//判斷顏色
this.color = '';
};

3. stage Canvas的設計

用一個一維array代表stage矩陣,例如(3, 4) => 4*Xcount + 3

4. shape形狀方塊

shape 用二維array表示,較好理解,例如這是我定義的幾個形狀

1
2
3
4
5
6
7
8
9
10
11
12
Tetris.prototype.getShape = (function(){
var shape = [
[[1,1], [1,1]],
[[0,1,1], [1,1,0]],
[[0,0,1], [1,1,1]],
[[1,1,1,1,1]]
];
return function(){
var rand = Math.floor(Math.random()*shape.length);
return shape[rand];
};
})();

5. 碰撞偵測

碰撞偵測部份是較複雜的部份,我利用兩個檢查函式來做檢查,為了理解容易,底下的判斷程式碼有點重複。

  1. 檢查是否到達邊界
  2. 檢查是否碰到堆積的grid
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    var collision = _self.chkCollision(x, y);
    var chkStacked = _self.chkStacked(x, y);
    //collision dectection
    if(collision){
    //若已到達底,則更新狀態為堆積狀態
    if(chkStacked){
    status.stacked = true;
    return;
    }else{

    return;
    }
    }else{
    if(chkStacked){
    //若碰到堆積的grid,先檢查是否可以往下,若可以往下,則退回,若否,則更新為堆積狀態
    var chkStackedDown = _self.chkStacked(status.shapeX, status.shapeY+1);
    if(chkStackedDown){
    status.stacked = true;
    return;
    }else{
    return;
    }
    }
    }

6. 狀態更新

Game 的基本觀念是狀態的更新,每一次重新渲染畫面時都是在更新狀態,因此狀態的表示非常重要,在此我用shape來儲存現在動作的形狀,並紀錄目前shape的x, y,以及是否要進入堆疊狀態。

1
2
3
4
5
6
var status = {
shape:null,
shapeX:0,
shapeY:0,
stacked:false
};

7. refresh 渲染畫面

1
2
3
4
5
6
7
8
9
10
11
12

Tetris.prototype.refresh = function(){
var _self = this;
//取得目前狀態
var status = _self.getStatus();
//清除畫布,判斷是否已經堆積
_self.clear();
//設定shape的狀態
_self.setShape(status.shape, status.shapeX, status.shapeY);
//重新繪製
_self.draw();
};

以上是我的基本概念,實做上其實code有點醜,而且也還有很多bug,不過因為是實驗性質的,也沒打算要產品化,就在這兒野人獻曝了。
DEMO

Update

俄羅斯方塊 Canvas 版本