1、游戏布局(activity_main.xml) 首先在xml文件中实现游戏的整体布局 (1)添加两个TextView用来显示分数
<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>(2)2048游戏界面的布局,游戏界面是通过代码来实现的,所以应该用包名加类名的方式来引用
<com.jxl.game2048.GameView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:id="@+id/gameView"> </com.jxl.game2048.GameView>2、新建游戏运行的主要类(GameView.java),该类继承GridLayout (1)在构造方法中,需要对游戏进行初始化( 调用initGameView()方法 ) initGameView()主要用来初始化游戏,该方法中需要实现OnTouchListener,通过坐标值判断用户滑动的方式,响应不同的事件 在initGameView()指定列数,设定背景: setColumnCount(4); setBackgroundColor(0xffbbada0);
setOnTouchListener(new OnTouchListener() { PRivate float startX,startY,offsetX,offsetY; @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub 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){ swipeLeft(); //向右滑动 }else if(offsetX>5){ swipeRight(); } }else{ //向上滑动 if(offsetY<-5){ swipeUp(); //向下滑动 }else if(offsetY>5){ swipeDown(); } } break; default: break; } return true; } });3、将2048的界面看做由4*4的小方块组成,将这些方块抽象为Card类,该类继承自FrameLayout (1)游戏进行时小方块中的数字为2、4、8、16.……初始化所有小方块,将数字设为0,即数字为0时表示这一格为空 setNum(0);
private int num = 0; public int getNum() { return num; } public void setNum(int num) { this.num = num; }(2)在构造方法中,需要对小方块进行初始化,为小方块添加TextView保存数字,并设置字体大小,数字对应的颜色等
private TextView label; public Card(Context context) { super(context); label = new TextView(getContext()); label.setTextSize(32); label.setGravity(Gravity.CENTER); setNum(0); } public void setBGColor(int num){ switch (num) { case 2: label.setBackgroundColor(0xffFFF68F); break; case 4: label.setBackgroundColor(0xffFFEC8B); break; case 8: label.setBackgroundColor(0xffFFD700); break; case 16: label.setBackgroundColor(0xffFFC125); break; case 32: label.setBackgroundColor(0xffFF890F); break; case 64: label.setBackgroundColor(0xffFFA500); break; case 128: label.setBackgroundColor(0xffFF8C00); break; case 256: label.setBackgroundColor(0xffFF7F24); break; case 512: label.setBackgroundColor(0xffFF4500); break; case 1024: label.setBackgroundColor(0xffFF0000); break; case 2048: label.setBackgroundColor(0xff7FF00); break; case 4096: label.setBackgroundColor(0xff68228B); break; default: label.setBackgroundColor(0x33ffffff); break; } }(3)添加一个布局参数,宽高为-1,表示填充满整个父类容器:
LayoutParams lp = new LayoutParams(-1,-1); //设置小方块之间的间距 lp.setMargins(10, 10, 0, 0); //然后将label添加进布局中: addView(label, lp)(4)在setNum()方法中,将数字转换成字符串并添加到对应的TextView中
public void setNum(int num) { this.num = num; if(num<=0){ label.setText(""); }else{ label.setText(num+""); } }(5)添加equals()方法判断两个卡片上的数字是否相等:
public boolean equals(Card o) { // TODO Auto-generated method stub return getNum()==o.getNum(); }4、将16个方块抽象化为4*4的二维数组,并将这些小方块添加到布局中
private Card[][] cardsMap = new Card[4][4]; 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); c.setBGColor(c.getNum()); addView(c, cardWidth, cardHeight); cardsMap[x][y] = c; } } }5、新建emptyPoint List来存放空的小方块
private List<Point> emptyPoints = new ArrayList<Point>();游戏中新生成的数字在这些空的小方块中随机出现
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())); //随机产生2或4,生成2的概率大于4 cardsMap[p.x][p.y].setNum(Math.random()>0.1?2:4); cardsMap[p.x][p.y].setBGColor(cardsMap[p.x][p.y].getNum()); }6、开始游戏,实现startGame()方法
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(); }7、实现游戏中最重要的部分—用户滑动后需要调用的方法,以向左滑动为例
private void swipeLeft(){ 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++){ //当前位置上的值不为0 if(cardsMap[x1][y].getNum()>0){ //当前方块左边的方块为空,则将当前方块的值传到左边,直到左边是不为空的方块为止 if(cardsMap[x][y].getNum()<=0){ cardsMap[x][y].setNum(cardsMap[x1][y].getNum()); cardsMap[x][y].setBGColor(cardsMap[x][y].getNum()); cardsMap[x1][y].setNum(0); cardsMap[x1][y].setBGColor(cardsMap[x1][y].getNum()); x--; merge = true; //左边卡片的值不为空且与当前值当等 }else if(cardsMap[x][y].equals(cardsMap[x1][y])){ cardsMap[x][y].setNum(cardsMap[x][y].getNum()*2); cardsMap[x][y].setBGColor(cardsMap[x][y].getNum()); cardsMap[x1][y].setNum(0); cardsMap[x1][y].setBGColor(cardsMap[x1][y].getNum()); MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum()); merge = true; } break; } } } } if(merge){ //完成后再添加一个随机数字 addRandomNum(); //并判断游戏是否结束 checkComplete(); } } 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){ new AlertDialog.Builder(getContext()).setTitle("2048"). setMessage("游戏结束").setPositiveButton("重来", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { // TODO Auto-generated method stub startGame(); } }).show(); } }8、在GameView中重写onSizeChanged()方法,动态地计算每个方块的宽、高: 在AndroidManifest.xml中修改屏幕布局为垂直: android:screenOrientation=”portrait”
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); //对宽、高求最小值,然后求出每一个小方块的宽度 int cardWidth = (Math.min(w,h)-10)/4; //将小方块添加到布局中 addCards(cardWidth, cardWidth); startGame(); }9、在MainActivity中添加addScore()、showScore()、clearScore()方法,实现计分功能
public class MainActivity extends Activity { private TextView tvScore; private int score = 0; public MainActivity(){ mainActivity = this; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); tvScore = (TextView) findViewById(R.id.tvScore); } public void clearScore(){ score = 0; showScore(); } public void showScore(){ tvScore.setText(score+""); } public void addScore(int s){ score+=s; showScore(); } private static MainActivity mainActivity = null; public static MainActivity getMainActivity(){ return mainActivity; }}源码: https://github.com/jiangxingling/Game2048
注:该文章根据“极客学院”中2048游戏视频教程总结而来
新闻热点
疑难解答