Android編寫(xiě)2048小游戲
先來(lái)說(shuō)說(shuō)2048游戲規(guī)則:
開(kāi)始時(shí)棋盤(pán)內(nèi)隨機(jī)出現(xiàn)兩個(gè)數(shù)字,出現(xiàn)的數(shù)字僅可能為2或4
玩家可以選擇上下左右四個(gè)方向,若棋盤(pán)內(nèi)的數(shù)字出現(xiàn)位移或合并,視為有效移動(dòng)
玩家選擇的方向上若有相同的數(shù)字則合并,每次有效移動(dòng)可以同時(shí)合并,但不可以連續(xù)合并
合并所得的所有新生成數(shù)字想加即為該步的有效得分
玩家選擇的方向行或列前方有空格則出現(xiàn)位移
每有效移動(dòng)一步,棋盤(pán)的空位(無(wú)數(shù)字處)隨機(jī)出現(xiàn)一個(gè)數(shù)字(依然可能為2或4)
棋盤(pán)被數(shù)字填滿(mǎn),無(wú)法進(jìn)行有效移動(dòng),判負(fù),游戲結(jié)束
棋盤(pán)上出現(xiàn)2048,判勝,游戲結(jié)束
下面代碼
MainActivity類(lèi)
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(new GameView(this)); } }
定義一個(gè)卡片類(lèi)顯示數(shù)據(jù)
/卡片類(lèi)型 public class Card extends FrameLayout { //2 TextView tv; private int number = 0; int width; public Card(Context context, int width) { super(context); this.width = width; init(); } private void init() { tv = new TextView(getContext()); setPadding(5, 5, 5, 5); FrameLayout.LayoutParams lp = new LayoutParams(width - 10, width - 10); tv.setLayoutParams(lp); tv.setGravity(Gravity.CENTER); tv.setTextColor(Color.WHITE); tv.setTextSize(48); this.addView(tv); setColor(); } public void setNumber(int number) { this.number = number; if (number == 0) tv.setText(""); else tv.setText(number + ""); setColor(); } @Override public String toString() { return "Card{" + "tv=" + tv + ", number=" + number + ", width=" + width + '}'; } private void setColor() { switch (number) { case 0: tv.setBackgroundColor(getResources().getColor(R.color.c0)); break; case 2: tv.setBackgroundColor(getResources().getColor(R.color.c2)); break; case 4: tv.setBackgroundColor(getResources().getColor(R.color.c4)); break; case 8: tv.setBackgroundColor(getResources().getColor(R.color.c8)); break; case 16: tv.setBackgroundColor(getResources().getColor(R.color.c16)); break; case 32: tv.setBackgroundColor(getResources().getColor(R.color.c32)); break; case 64: tv.setBackgroundColor(getResources().getColor(R.color.c64)); break; case 128: tv.setBackgroundColor(getResources().getColor(R.color.c128)); break; case 256: tv.setBackgroundColor(getResources().getColor(R.color.c256)); break; case 512: tv.setBackgroundColor(getResources().getColor(R.color.c512)); break; case 1024: tv.setBackgroundColor(getResources().getColor(R.color.c1024)); break; case 2048: tv.setBackgroundColor(getResources().getColor(R.color.c2048)); break; } } public int getNumber() { return number; } }
自己定義一下上面的幾種顏色 在values下的colors中
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3F51B5</color> <color name="colorPrimaryDark">#303F9F</color> <color name="colorAccent">#FF4081</color> <color name="c0">#43382a</color> <color name="c2">#2a8618</color> <color name="c4">#3d6319</color> <color name="c8">#F2B179</color> <color name="c16">#F59563</color> <color name="c32">#F57C5F</color> <color name="c64">#5b69b7</color> <color name="c128">#b37d3e</color> <color name="c256">#3a9096</color> <color name="c512">#d7882c</color> <color name="c1024">#5c1b78</color> <color name="c2048">#640548</color> </resources>
布局類(lèi) 和里面的運(yùn)算方法
public class GameView extends GridLayout { int[][] values = new int[4][4]; Card[][] cards = new Card[4][4]; // Integer -128-127 == 大于這個(gè)數(shù) 兩個(gè)對(duì)象 public GameView(Context context) { super(context); init(); } public GameView(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { setColumnCount(4); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); newGame(); } private void newGame() { //ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams((int) (getResources().getDisplayMetrics().widthPixels / 4), (int) (getResources().getDisplayMetrics().widthPixels / 4)); GridLayout.LayoutParams params = new GridLayout.LayoutParams(); // params.width = getResources().getDisplayMetrics().widthPixels / 4; // params.height = getResources().getDisplayMetrics().widthPixels / 4; //Log.e("TAG", params.width + " " + params.height); this.removeAllViews(); // GridLayout.LayoutParams lpa = new GridLayout.LayoutParams(lp); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { values[i][j] = 0; cards[i][j] = new Card(getContext(), getResources().getDisplayMetrics().widthPixels / 4); // cards[i][j].setLayoutParams(params); //cards[i][j].upLv(); this.addView(cards[i][j]); } } //創(chuàng)建初始的兩張卡 int i = (int) (Math.random() * 16); int j = 0; do { j = (int) (Math.random() * 16);//0-15 15 3 3 } while (j == i); Log.e("TAG", i + " " + j); values[i / 4][i % 4] = Math.random() * 20 < 1 ? 4 : 2; values[j / 4][j % 4] = Math.random() * 20 < 1 ? 4 : 2; setValues(); } float oldx, oldy; int move = -1; @Override public boolean onTouchEvent(MotionEvent event) { float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: move = -1; oldx = x; oldy = y; break; case MotionEvent.ACTION_MOVE: if (Math.abs(oldx - x) > Math.abs(oldy - y)) { if (oldx - x > 15) { //左 Log.e("TAG", "---------->>>"); move = 1; } else if (oldx - x < -15) {//右 Log.e("TAG", "---------->>>"); move = 2; } } else { if (oldy - y > 15) { move = 3; } else if (oldy - y < -15) { move = 4; } } break; case MotionEvent.ACTION_UP: //記錄之前的數(shù)組 int[][] temp = new int[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { temp[i][j] = values[i][j]; } } switch (move) { case 1: left(); break; case 2: right(); break; case 3: up(); break; case 4: down(); break; } setValues(); if (move != -1) { //比對(duì)當(dāng)前的數(shù)組 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (values[i][j] != temp[i][j]) { addCard(); return true; } } } } //判斷游戲勝利還是結(jié)束4 if (isWin()) { Toast.makeText(getContext(), "游戲勝利", Toast.LENGTH_SHORT).show(); } if (isOver()) { this.removeAllViews(); TextView tv = new TextView(getContext()); tv.setText("游戲結(jié)束,點(diǎn)擊從新開(kāi)始"); this.addView(tv); tv.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { newGame(); } }); } break; } return true; } private void addCard() { while (true) { int j = (int) (Math.random() * 16); if (values[j / 4][j % 4] == 0) { values[j / 4][j % 4] = 2; cards[j / 4][j % 4].setNumber(2); return; } } } public void left() { //取出 4個(gè) 集合 for (int i = 0; i < 4; i++) { List<Integer> list = new ArrayList<>(); for (int j = 0; j < 4; j++) { int value = values[i][j]; if (value != 0) list.add(value); } //比較 Log.e("TAG", list.toString()); if (list.size() == 0) continue; else if (list.size() == 1) { values[i][0] = list.get(0); for (int j = 0; j < 3; j++) { values[i][j + 1] = 0; } } else if (list.size() == 2) { if (list.get(0).equals(list.get(1))) { values[i][0] = list.get(0) * 2; //三個(gè)值補(bǔ)0 for (int j = 0; j < 3; j++) { values[i][j + 1] = 0; } } else { values[i][0] = list.get(0); values[i][1] = list.get(1); values[i][2] = 0; values[i][3] = 0; } } else if (list.size() == 3) { if (list.get(0).equals(list.get(1))) { values[i][0] = list.get(0) * 2; values[i][1] = list.get(2); values[i][2] = 0; values[i][3] = 0; } else if (list.get(1).equals(list.get(2))) { values[i][0] = list.get(0); values[i][1] = list.get(2) * 2; values[i][2] = 0; values[i][3] = 0; } else { values[i][0] = list.get(0); values[i][1] = list.get(1); values[i][2] = list.get(2); values[i][3] = 0; } } else { if (list.get(0).equals(list.get(1))) { if (list.get(3).equals(list.get(2))) { values[i][0] = list.get(0) * 2; values[i][1] = list.get(2) * 2; values[i][2] = 0; values[i][3] = 0; } else { values[i][0] = list.get(0) * 2; values[i][1] = list.get(2); values[i][2] = list.get(3); values[i][3] = 0; } } else { //1和2不相等 //先比對(duì)2 3 相等,不等 if (list.get(1).equals(list.get(2))) { values[i][0] = list.get(0); values[i][1] = list.get(1) * 2; values[i][2] = list.get(3); values[i][3] = 0; } else { if (list.get(2).equals(list.get(3))) { values[i][0] = list.get(0); values[i][1] = list.get(1); values[i][2] = list.get(2) * 2; values[i][3] = 0; } } } } } } private void delete() { // Log.e("TAG", "--------------------執(zhí)行"); // //遍歷 // for (int i = 0; i < 4; i++) { // for (int j = 0; j < 3; j++) { // Card card = cards[i][j]; // Log.e("TAG", "i:" + i + " j:" + j + " num:" + card.getNumber()); // if (card.getNumber() == 0) { // boolean isSub = false; // for (int k = j; k < 3; k++) { // cards[i][k].setNumber(cards[i][k + 1].getNumber()); // if (cards[i][k + 1].getNumber() != 0) { // isSub = true; // } // } // if (isSub) // j--; // cards[i][3].setNumber(0); // } else if (card.getNumber() == cards[i][j + 1].getNumber()) { // card.upLv(); // cards[i][j + 1].setNumber(0); // //后面的往前搬 // for (int k = j + 1; k < 3; k++) { // cards[i][k].setNumber(cards[i][k + 1].getNumber()); // } // cards[i][3].setNumber(0); // j--; // } // } // } // for (int j = 0; j < 4; j++) { //列 // for (int i = 3; i >= 1; i--) { // Card card = cards[j][i]; // if (card.getNumber() == 0) { // //全行左移 // //要將 // //如果是最后一個(gè),不需要理會(huì) // continue; // } else { // //判斷左邊一個(gè) // if (cards[j][i - 1].getNumber() == 0) { // //從i --》i-1 // for (int k = i - 1; k < 3; k++) { // cards[j][k].setNumber(cards[j][k + 1].getNumber()); // } // cards[j][3].setNumber(0); // // } else if (cards[j][i - 1].getNumber() == card.getNumber()) { // cards[j][i - 1].upLv(); // card.setNumber(0); // for (int k = i; k < 3; k++) { // cards[j][k].setNumber(cards[j][k + 1].getNumber()); // } // cards[j][3].setNumber(0); // } // } // } // } } public void right() { mirrorH(); left(); mirrorH(); } private void mirrorH() { for (int i = 0; i < 4; i++) { int temp = values[i][0]; values[i][0] = values[i][3]; values[i][3] = temp; temp = values[i][1]; values[i][1] = values[i][2]; values[i][2] = temp; } } public void down() { //左旋 int[][] temp = new int[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { temp[i][j] = values[3 - j][i]; } } values = temp; left(); temp = new int[4][4]; for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { temp[i][j] = values[j][3 - i]; } } values = temp; } public void up() { mirrorV(); down(); mirrorV(); } private void mirrorV() { for (int j = 0; j < 4; j++) { int temp = values[0][j]; values[0][j] = values[3][j]; values[3][j] = temp; temp = values[1][j]; values[1][j] = values[2][j]; values[2][j] = temp; } } public void setValues() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { System.out.print(values[i][j] + " "); cards[i][j].setNumber(values[i][j]); } System.out.println(); } } public boolean isWin() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (values[i][j] == 2048) return true; } } return false; } public boolean isOver() { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (values[i][j] == 0) return false; } } //滿(mǎn)了 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { int value = values[i][j]; if (i > 1 && value == values[i - 1][j]) return false; else if (i < 3 && value == values[i + 1][j]) return false; else if (j > 1 && value == values[i][j - 1]) return false; else if (j < 3 && value == values[i][j + 1]) return false; } } return true; } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android高仿2048小游戲?qū)崿F(xiàn)代碼
- Android實(shí)現(xiàn)2048小游戲
- Android游戲源碼分享之2048
- 打飛機(jī)游戲終極BOSS Android實(shí)戰(zhàn)打飛機(jī)游戲完結(jié)篇
- Android實(shí)戰(zhàn)打飛機(jī)游戲之子彈生成與碰撞以及爆炸效果(5)
- Android實(shí)戰(zhàn)打飛機(jī)游戲之無(wú)限循環(huán)的背景圖(2)
- Android實(shí)戰(zhàn)打飛機(jī)游戲之菜單頁(yè)面設(shè)計(jì)(1)
- Android五子棋游戲程序完整實(shí)例分析
- Android下SDL2實(shí)現(xiàn)五子棋游戲
- Android 游戲開(kāi)發(fā)之Canvas畫(huà)布的介紹及方法
相關(guān)文章
Android Studio生成 Flutter 模板代碼技巧詳解
這篇文章主要為大家介紹了Android Studio生成 Flutter 模板代碼技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10Android EditText限制輸入整數(shù)和小數(shù)的位數(shù)的方法示例
這篇文章主要介紹了Android EditText限制輸入整數(shù)和小數(shù)的位數(shù)的方法示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08Android刮刮卡實(shí)現(xiàn)原理與代碼講解
這篇文章主要為大家詳細(xì)介紹了Android刮刮卡實(shí)現(xiàn)原理、實(shí)現(xiàn)原理步驟以及代碼講解,感興趣的小伙伴們可以參考一下2016-04-04Android程序開(kāi)發(fā)ListView+Json+異步網(wǎng)絡(luò)圖片加載+滾動(dòng)翻頁(yè)的例子(圖片能緩存,圖片不錯(cuò)亂)
這篇文章主要介紹了Android程序開(kāi)發(fā)ListView+Json+異步網(wǎng)絡(luò)圖片加載+滾動(dòng)翻頁(yè)的例子(圖片能緩存,圖片不錯(cuò)亂) 的相關(guān)資料,需要的朋友可以參考下2016-01-01Android錄音功能的實(shí)現(xiàn)以及踩坑實(shí)戰(zhàn)記錄
在Android 開(kāi)發(fā)過(guò)程中,有些功能是通用的,或者是多個(gè)業(yè)務(wù)方都需要使用的,下面這篇文章主要給大家介紹了關(guān)于Android錄音功能的實(shí)現(xiàn)以及踩坑的相關(guān)資料,需要的朋友可以參考下2022-06-06Android實(shí)現(xiàn)繪畫(huà)板功能
這是一款android的畫(huà)圖板實(shí)現(xiàn)代碼,基本功能齊全,適合初學(xué)者開(kāi)發(fā)的例子程序,感興趣的朋友就來(lái)看看吧2021-05-05Android編程之基于Log演示一個(gè)activity生命周期實(shí)例詳解
這篇文章主要介紹了Android編程之基于Log演示一個(gè)activity生命周期,結(jié)合完整實(shí)例形式較為詳細(xì)的分析總結(jié)了Log演示activity生命周期的具體用法及Log的具體使用方法,需要的朋友可以參考下2015-12-12Android webview與js交換JSON對(duì)象數(shù)據(jù)示例
js主動(dòng)調(diào)用android的對(duì)象方式,android也無(wú)法返回給js一個(gè)jsonobject,需要js做一下轉(zhuǎn)換,具體代碼如下,感興趣的朋友可以參考下哈2013-06-06