Android中正火的2048游戏开发,赶紧开发一个自己的2048吧
1.游戏中的几个关键点
1)界面
2048游戏的操作界面就是一个4X4的方格。如下图所示:
游戏首先要绘制出该界面。
@1 界面布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.example.game2048.MainActivity" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/score"/> <TextView android:id="@+id/tvScore" android:layout_width="wrap_content" android:layout_height="wrap_content"/> </LinearLayout> <com.example.game2048.GameView android:id="@+id/gameView" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> </com.example.game2048.GameView> </LinearLayout>
从布局文件中可以看出,总体采用线性布局的方式,最上面是计分板,下面为界面中主要的部分,是自定义的View--(GameView)。
@2 自定义组件GameView
<span style="font-size:14px;">package com.example.game2048; import java.util.ArrayList; import java.util.List; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.graphics.Point; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.GridLayout; public class GameView extends GridLayout { public GameView(Context context) { super(context); initGameView(); } public GameView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initGameView(); } public GameView(Context context, AttributeSet attrs) { super(context, attrs); initGameView(); } //初始化Game界面 private void initGameView(){ setColumnCount(4); setBackgroundColor(0Xffbbada0); setOnTouchListener(new OnTouchListener() { // 定义变量 private float startX,startY,offsetX,offsetY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = event.getX(); startY = event.getY(); break; case MotionEvent.ACTION_UP: offsetX = event.getX() - startX; offsetY = event.getY() - startY; if(Math.abs(offsetX) > Math.abs(offsetY)){ if(offsetX < -5){ // System.out.println("left"); slipLeft(); } else if(offsetX > 5){ // System.out.println("right"); slipRight(); } } else{ if(offsetY < -5){ // System.out.println("up"); slipUp(); } else if(offsetY > 5){ // System.out.println("down"); slipDown(); } } break; } return true; } }); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); int cardWidth = (Math.min(w, h)-10)/4; addCards(cardWidth,cardWidth); startGame(); } private void addCards(int cardWidth, int cardHeight){ Card c; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { c = new Card(getContext()); c.setNum(0); cardsMap[x][y] = c; addView(c, cardWidth, cardHeight); } } } private void startGame(){ MainActivity.getMainActivity().clearScore(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { cardsMap[x][y].setNum(0); } } addRandomNum(); addRandomNum(); } //添加随机数 private void addRandomNum(){ emptyPoints.clear(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if(cardsMap[x][y].getNum() <= 0){ emptyPoints.add(new Point(x,y)); } } } Point p = emptyPoints.remove((int)(Math.random()*emptyPoints.size())); //随机移除一个点 cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4); } private void checkComplete(){ boolean complete = true; ALL: for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if(cardsMap[x][y].getNum() == 0 || (x>0 && cardsMap[x][y].equals(cardsMap[x-1][y])) || (x<3 && cardsMap[x][y].equals(cardsMap[x+1][y])) || (y>0 && cardsMap[x][y].equals(cardsMap[x][y-1])) || (y<3 && cardsMap[x][y].equals(cardsMap[x][y+1]))){ complete = false; break ALL; } } } if(complete){ AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("哎呦,不好了").setMessage("游戏被你玩完了哦。"); builder.setPositiveButton(R.string.play_again, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startGame(); } }); builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { MainActivity.getMainActivity().quitGame(); } }); builder.create().show(); } } private void slipLeft(){ boolean merge = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x+1; x1 < 4; x1++) { //横轴上比较 if(cardsMap[x1][y].getNum() > 0){ //只对有数的进行操作 if(cardsMap[x][y].getNum() <= 0){ //有空格,则把右边的放到左边来 cardsMap[x][y].setNum(cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); merge = true; x--; } else if(cardsMap[x][y].equals(cardsMap[x1][y])){ // 如果两个相等,则合并 cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); merge = true; MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); } break; } } } } if(merge){ addRandomNum(); checkComplete(); } } private void slipRight(){ boolean merge = false; for (int y = 0; y < 4; y++) { for (int x = 3; x >= 0; x--) { for (int x1 = x-1; x1 >= 0; x1--) { if(cardsMap[x1][y].getNum() > 0){ if(cardsMap[x][y].getNum() <= 0){ cardsMap[x][y].setNum(cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); merge = true; x++; } else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); merge = true; MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); } break; } } } } if(merge){ addRandomNum(); checkComplete(); } } private void slipUp(){ boolean merge = false; for (int x = 0; x < 4; x++) { for (int y = 0; y < 4; y++) { for (int y1 = y+1; y1 < 4; y1++) { if(cardsMap[x][y1].getNum() > 0){ if(cardsMap[x][y].getNum() <= 0){ cardsMap[x][y].setNum(cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); merge = true; y--; } else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); merge = true; MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); } break; } } } } if(merge){ addRandomNum(); checkComplete(); } } private void slipDown(){ boolean merge = false; for (int x = 0; x < 4; x++) { for (int y = 3; y >= 0; y--) { for (int y1 = y-1; y1 >=0; y1--) { if(cardsMap[x][y1].getNum() > 0){ if(cardsMap[x][y].getNum() <= 0){ cardsMap[x][y].setNum(cardsMap[x][y1].getNum()); cardsMap[x][y1].setNum(0); merge = true; y++; } else if(cardsMap[x][y].equals(cardsMap[x][y1])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y1].setNum(0); merge = true; MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); } break; } } } } if(merge){ addRandomNum(); checkComplete(); } } private Card[][] cardsMap = new Card[4][4]; private List<Point> emptyPoints = new ArrayList<Point>(); }</span><span style="font-size:24px;"> </span>
从代码中可以看出,自定义的GameView组件继承自GridLayout,初始化时设置为4列,设置背景,设置手势监听。
注意:当第一次进入游戏的时候,会调用GamaView的onSizeChanged()方法。如果屏幕横竖切换也会调用,此处为了防止屏幕切换,在配置中添加 android:screenOrientation="portrait"。
2)格子元素
<span style="font-size:14px;">package com.example.game2048; import android.content.Context; import android.view.Gravity; import android.widget.FrameLayout; import android.widget.TextView; public class Card extends FrameLayout { private int num; private TextView label; public Card(Context context) { super(context); label = new TextView(getContext()); label.setTextSize(32); label.setBackgroundColor(0X33ffffff); label.setGravity(Gravity.CENTER); LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); lp.setMargins(10, 10, 0, 0); addView(label, lp); setNum(0); } public int getNum() { return num; } public void setNum(int num) { this.num = num; if(num <= 0){ label.setText(""); } else{ label.setText(num+""); } } public boolean equals(Card c){ return getNum() == c.getNum(); } } </span>
格子负责显示数字,用TextView将数字显示出来。
整体界面效果如下所示:
2. 游戏逻辑
1) 左右上下移动时,格子该怎么办?
<span style="font-size:14px;">private void slipLeft(){ boolean merge = false; for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { for (int x1 = x+1; x1 < 4; x1++) { //横轴上比较 if(cardsMap[x1][y].getNum() > 0){ //只对有数的进行操作 if(cardsMap[x][y].getNum() <= 0){ //有空格,则把右边的放到左边来 cardsMap[x][y].setNum(cardsMap[x1][y].getNum()); cardsMap[x1][y].setNum(0); merge = true; x--; } else if(cardsMap[x][y].equals(cardsMap[x1][y])){ // 如果两个相等,则合并 cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x1][y].setNum(0); merge = true; MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); } break; } } } } if(merge){ addRandomNum(); checkComplete(); } }</span>
从左滑动代码可以看出:逐行检查,看是否有空格,有的话则向左覆盖;有相同的进行合并。右划、上划、下划与此类似。
2) 随机产生一个2或4的格子添加到界面中
<span style="font-size:14px;">//添加随机数 private void addRandomNum(){ emptyPoints.clear(); for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if(cardsMap[x][y].getNum() <= 0){ emptyPoints.add(new Point(x,y)); } } } Point p = emptyPoints.remove((int)(Math.random()*emptyPoints.size())); //随机移除一个点 cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4); }</span>
从代码可以看出: 要做到随机,首先是把所有的没有数字的空格放到一起,加入到ArrayList中,然后随机的从这个ArrayList中取出一个空格,按照百分比添加2或者4.
3) 什么情况下,要添加一个带数字的格子到游戏中
游戏刚进入的时候,需要添加2个随机数,然后,每次当格子有移动,或者有合并,都需要添加一个新的随机数格子到游戏中。
3 游戏结束的判断
<span style="font-size:14px;">private void checkComplete(){ boolean complete = true; ALL: for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { if(cardsMap[x][y].getNum() == 0 || (x>0 && cardsMap[x][y].equals(cardsMap[x-1][y])) || (x<3 && cardsMap[x][y].equals(cardsMap[x+1][y])) || (y>0 && cardsMap[x][y].equals(cardsMap[x][y-1])) || (y<3 && cardsMap[x][y].equals(cardsMap[x][y+1]))){ complete = false; break ALL; } } } if(complete){ AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); builder.setTitle("哎呦,不好了").setMessage("游戏被你玩完了哦。"); builder.setPositiveButton(R.string.play_again, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { startGame(); } }); builder.setNegativeButton(R.string.exit, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { MainActivity.getMainActivity().quitGame(); } }); builder.create().show(); } }</span>
从代码中可以看出:如果游戏中无空格,或者上下左右没有可以合并的格子,那么游戏结束,弹出提示框。
至此游戏的开发已经大体完成,后面需要润色完善。
本程序的代码如下:http://download.csdn.net/detail/adayabetter/8873769 大家可以下载学习。
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 05:50:24