2048最近彷佛熱度已過,可是並不影響我山寨一個它。週末閒來無事,終於付諸實現,包含winform和js版本。有圖有真相數組
實現思路:dom
一、經過二維數組data=int[4][4]來存儲遊戲數據,初始所有爲0ide
二、遊戲初始在4X4佈局中隨機位置產生2個隨機數(只隨機2,4)佈局
//初始化遊戲數據 void InitGame() { ClearGame(); Random rand = new Random(); int pos1 = Convert.ToInt32(rand.Next(16)); SetData(pos1, rand.NextDouble() < 0.8 ? 2 : 4); int pos2 = GetRandPos(); SetData(pos2, rand.NextDouble() < 0.8 ? 2 : 4); }
分解:spa
a、隨意位置產生一個隨機數.net
b、在剩下的隨機空白位置產生一個隨機數,此方法在遊戲移動後產生一個隨機數時也要用到。隨機空白位置的產生:遍歷數據數組data,取得全部位置爲空的集合pos,data中數據爲0的即對應位置爲空,可產生隨機數;在pos中產生隨機位置。3d
//隨機產生空格處的座標位置 int GetRandPos() { List<int> pos = new List<int>(); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (data[i,j] == 0) pos.Add(4 * i + j);//數組座標恰好能夠經過pos/4,pos%4獲得 } } Random r = new Random(); int rand = r.Next(pos.Count); return pos[rand]; }
這裏要注意data[i][j]和佈局位置的對應關係:data[i][j]=>pos[4*i+j],pos[i]=>data[i/4][i%4];code
三、移動操做:先合併再移動,以左移爲例orm
a)、查找可合併的元素合併,以一次合併爲例:blog
0 | 1 | 2 | 3 |
1) data1=從左到右第一個不爲0的元素,假設是第j位置pos[j]
2) data2=pos[j+1]
3) a. data1==data2則進行合併操做
b. data2==0,data2下移一個
c. data2!=0&&data1!=data2,不能合併
//先合併元素 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int tb = data[i,j];//取一個元素值 if (tb != 0) { for (int k = j + 1; k < 4; k++) { int nexttb = data[i,k];//下一元素值 if (nexttb != 0) { if (tb == nexttb) {//相等合併,計算分數,設置移動狀態 data[i,j] = tb * 2; data[i,k] = 0; totalscore += tb * 2; moveflag = true; } break; } } } } }
b)、合併完成後移動元素至最左端
前面的元素爲空就依次把後面不爲空的元素往前移,移動後後面元素置爲空
//合併以後移動元素 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int tb = data[i,j];//取一個元素值 if (tb == 0) {//取得元素值爲0表示當前位置爲空 for (int k = j + 1; k < 4; k++) { int nexttb = data[i,k];//下一個元素值 if (nexttb != 0) {//下一元素值不爲0移動,設置移動標誌 data[i,j] = nexttb; data[i,k] = 0; moveflag = true; break; } } } } }
四、判斷遊戲是否結束,未結束則產生一個隨機數
判斷遊戲是否結束:有元素爲0或者有可合併的元素可繼續,不然結束
//產生單個隨機數 void GetRandNum() { if (IsGameOver()) { if (MessageBox.Show("失敗,是否從新開始?", "GameOver", MessageBoxButtons.YesNo)== DialogResult.Yes) { InitGame(); } else return; } Random rand=new Random (); if(moveflag) SetData(GetRandPos(), rand.NextDouble() < 0.8 ? 2 : 4); moveflag = false;//重置是否移動標識 }
五、經過data數據更新界面
//根據data更新td內容,並設置樣式 void InitData() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { var td = btns.Find(m => m.Name == "btn" + (4 * i + j).ToString()); //btns[4 * i + j]; string tdval = td.Text.Length == 0 ? "0" : td.Text; if (data[i, j].ToString() != tdval) td.Text = data[i, j] == 0 ? "" : data[i, j].ToString(); //此處可設置數字樣式 } } lblscore.Text = totalscore.ToString(); }
其餘方向移動操做依葫蘆畫瓢,至此,一個簡略山寨版2048完成。
須要注意的是Winform版本中要注意鍵盤上下左右事件方法要重寫:
//重寫上下左右鍵響應方法 protected override bool ProcessDialogKey(Keys keyData) { switch (keyData) { case Keys.Up: MoveUp(); break; case Keys.Down: MoveDown(); break; case Keys.Left: MoveLeft(); break; case Keys.Right: MoveRight(); break; default: break; } return base.ProcessDialogKey(keyData); }
經過下面的KeyDown事件監控沒有效果,本人對winform不熟悉,期待大神解答緣由
private void Form1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Left) MoveLeft(); }
參考文章:http://blog.csdn.net/touchsnow/article/details/22985527