实现效果 :
代码结构:
完整代码:
MainActivity:
package com.next.next2048;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
//全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(new GameView(this));
}
}
Tile:
package com.next.next2048;
/**
* Created by Next on 2016/3/17 0017.
*/
public class Tile {
private int number;
private int x,y;
public Tile(int x,int y,int number){
this.x = x;
this.y = y;
this.number = number;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
GameView:
package com.next.next2048;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.Random;
/**
* Created by Next on 2016/3/17 0017.
*/
public class GameView extends View {
enum GameState {
Menu,
Playing,
Over
}
GameState gameState = GameState.Menu;
public static final int MAX_X = 4;
public static final int MAX_Y = 4;
int tWidth;//tile宽度
int scrW;//屏幕宽
int scrH;//屏幕高
int offsetX;//偏移x
int offsetY;//偏移y,用于调整游戏区域在屏幕中的位置
Paint paint;
Tile[][] tiles;//Tile集合
Random random;
ArrayList<Tile> zeroList;
float downX, downY, upX, upY;
public GameView(Context context) {
super(context);
scrW = ((MainActivity) context).getWindowManager().getDefaultDisplay().getWidth();
scrH = ((MainActivity) context).getWindowManager().getDefaultDisplay().getHeight();
offsetX = 30;
offsetY = (scrH - scrW) / 2;//使棋盘位于屏幕中央
tWidth = (scrW - offsetX * 2) / MAX_X;
paint = new Paint();
tiles = new Tile[MAX_X][MAX_Y];
setKeepScreenOn(true);//保持屏幕常亮
random = new Random();
zeroList = new ArrayList<Tile>();
}
private void newGame() {
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
tiles[x][y] = new Tile(x, y, 0);
}
}
newTile();
newTile();
}
private void newTile() {
zeroList.removeAll(zeroList);
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() == 0) {
zeroList.add(tiles[x][y]);
}
}
}
int size = zeroList.size();
if (size > 0) {
//出现4的概率是20%,出现2的概率是80%
if (random.nextInt(5) == 0) {
zeroList.get(random.nextInt(size)).setNumber(4);
} else {
zeroList.get(random.nextInt(size)).setNumber(2);
}
} else {
return;
}
}
@Override
protected void onDraw(Canvas canvas) {
switch (gameState) {
case Menu:
menuDraw(canvas);
break;
case Playing:
playingDraw(canvas);
break;
case Over:
overDraw(canvas);
break;
default:
break;
}
}
private void menuDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
paint.setColor(Color.BLACK);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(tWidth / 2);
canvas.drawText("2048", scrW / 2, scrH / 4, paint);
canvas.drawText("Touch me", scrW / 2, scrH / 2, paint);
}
private void playingDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
//画主游戏区域
paint.setColor(Color.BLACK);
paint.setStrokeWidth(10);
for (int x = 0; x < MAX_X + 1; x++) {
canvas.drawLine(offsetX + x * tWidth, offsetY, offsetX + x * tWidth, offsetY + tWidth * MAX_Y, paint);
}
for (int y = 0; y < MAX_Y + 1; y++) {
canvas.drawLine(offsetX, offsetY + y * tWidth, offsetX + MAX_X * tWidth, offsetY + y * tWidth, paint);
}
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() != 0) {
switch (tiles[x][y].getNumber()){
case 2:
paint.setColor(0xffff6666);
break;
case 4:
paint.setColor(0xffff9900);
break;
case 8:
paint.setColor(0xff99CC33);
break;
case 16:
paint.setColor(0xff33CC99);
break;
case 32:
paint.setColor(0xff666699);
break;
case 64:
paint.setColor(0xff339933);
break;
case 128:
paint.setColor(0xff0099CC);
break;
case 256:
paint.setColor(0xff660033);
break;
case 512:
paint.setColor(0xff006633);
break;
case 1024:
paint.setColor(0xff660099);
break;
case 2048:
paint.setColor(0xffff0033);
break;
case 4096:
paint.setColor(0xff333333);
break;
case 8192:
paint.setColor(0xff000000);
break;
default:
paint.setColor(0xff000000);
break;
}
canvas.drawText(tiles[x][y].getNumber() + "", offsetX + x * tWidth + tWidth / 2, offsetY + y * tWidth + tWidth * 3 / 4, paint);
}
}
}
}
private void overDraw(Canvas canvas) {
int max = 0;
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() > max) {
max = tiles[x][y].getNumber();
}
}
}
canvas.drawColor(Color.WHITE);
paint.setColor(Color.BLACK);
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(tWidth / 2);
canvas.drawText("Top:" + max, scrW / 2, scrH / 4, paint);
canvas.drawText("Try again", scrW / 2, scrH / 2, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (gameState) {
case Menu:
menuLogic(event);
break;
case Playing:
playingLoic(event);
break;
case Over:
overLogic(event);
break;
}
return true;
}
private void menuLogic(MotionEvent event) {
if (event.getX() > 0) {
gameState = GameState.Playing;
newGame();
invalidate();
}
}
private void playingLoic(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
downX = event.getX();
downY = event.getY();
} else if (event.getAction() == MotionEvent.ACTION_UP) {
upX = event.getX();
upY = event.getY();
float moveX = upX - downX;
float moveY = upY - downY;
if (Math.abs(moveX) > Math.abs(moveY)) {
if (moveX > 50) {
//右滑
//合并
boolean isMove = false;//判断是否有tile移动
for (int y = 0; y < MAX_Y; y++) {
for (int x = MAX_X - 1; x >= 0; x--) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int x0 = x - 1; x0 >= 0; x0--) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x0][y].getNumber()) {
tiles[x][y].setNumber(tiles[x][y].getNumber() * 2);
tiles[x0][y].setNumber(0);
isMove = true;
break;
} else {
break;
}
}
}
}
//移动
for (int y = 0; y < MAX_Y; y++) {
for (int x = MAX_X - 1; x >= 0; x--) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int x0 = x - 1; x0 >= 0; x0--) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else {
tiles[x][y].setNumber(tiles[x0][y].getNumber());
tiles[x0][y].setNumber(0);
isMove = true;
break;
}
}
}
}
//有tile移动才添加新的tile
if (isMove) {
newTile();
invalidate();
judgeOver();
}
} else if (moveX < -50) {
//左滑
//合并
boolean isMove = false;
for (int y = 0; y < MAX_Y; y++) {
for (int x = 0; x < MAX_X; x++) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int x0 = x + 1; x0 < MAX_X; x0++) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x0][y].getNumber()) {
tiles[x][y].setNumber(tiles[x][y].getNumber() * 2);
tiles[x0][y].setNumber(0);
isMove = true;
break;
} else {
break;
}
}
}
}
//移动
for (int y = 0; y < MAX_Y; y++) {
for (int x = 0; x < MAX_X; x++) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int x0 = x + 1; x0 < MAX_X; x0++) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else {
tiles[x][y].setNumber(tiles[x0][y].getNumber());
tiles[x0][y].setNumber(0);
isMove = true;
break;
}
}
}
}
if (isMove) {
newTile();
invalidate();
judgeOver();
}
}
} else {
if (moveY > 50) {
//下滑
//合并
boolean isMove = false;
for (int x = 0; x < MAX_X; x++) {
for (int y = MAX_Y - 1; y >= 0; y--) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int y0 = y - 1; y0 >= 0; y0--) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x][y0].getNumber()) {
tiles[x][y].setNumber(tiles[x][y].getNumber() * 2);
tiles[x][y0].setNumber(0);
isMove = true;
break;
} else {
break;
}
}
}
}
//移动
for (int x = 0; x < MAX_X; x++) {
for (int y = MAX_Y - 1; y >= 0; y--) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int y0 = y - 1; y0 >= 0; y0--) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else {
tiles[x][y].setNumber(tiles[x][y0].getNumber());
tiles[x][y0].setNumber(0);
isMove = true;
break;
}
}
}
}
if (isMove) {
newTile();
invalidate();
judgeOver();
}
} else if (moveY < -50) {
//上滑
//合并
boolean isMove = false;
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int y0 = y + 1; y0 < MAX_Y; y0++) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x][y0].getNumber()) {
tiles[x][y].setNumber(tiles[x][y].getNumber() * 2);
tiles[x][y0].setNumber(0);
isMove = true;
break;
} else {
break;
}
}
}
}
//移动
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int y0 = y + 1; y0 < MAX_Y; y0++) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else {
tiles[x][y].setNumber(tiles[x][y0].getNumber());
tiles[x][y0].setNumber(0);
isMove = true;
break;
}
}
}
}
if (isMove) {
newTile();
invalidate();
judgeOver();
}
}
}
}
}
private void overLogic(MotionEvent event) {
if (event.getX() > 0) {
newGame();
gameState = GameState.Playing;
}
}
private void judgeOver() {
//右滑
//合并
for (int y = 0; y < MAX_Y; y++) {
for (int x = MAX_X - 1; x >= 0; x--) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int x0 = x - 1; x0 >= 0; x0--) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x0][y].getNumber()) {
return;
} else {
break;
}
}
}
}
//移动
for (int y = 0; y < MAX_Y; y++) {
for (int x = MAX_X - 1; x >= 0; x--) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int x0 = x - 1; x0 >= 0; x0--) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else {
return;
}
}
}
}
//左滑
//合并
for (int y = 0; y < MAX_Y; y++) {
for (int x = 0; x < MAX_X; x++) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int x0 = x + 1; x0 < MAX_X; x0++) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x0][y].getNumber()) {
return;
} else {
break;
}
}
}
}
//移动
for (int y = 0; y < MAX_Y; y++) {
for (int x = 0; x < MAX_X; x++) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int x0 = x + 1; x0 < MAX_X; x0++) {
if (tiles[x0][y].getNumber() == 0) {
continue;
} else {
return;
}
}
}
}
//下滑
//合并
for (int x = 0; x < MAX_X; x++) {
for (int y = MAX_Y - 1; y >= 0; y--) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int y0 = y - 1; y0 >= 0; y0--) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x][y0].getNumber()) {
return;
} else {
break;
}
}
}
}
//移动
for (int x = 0; x < MAX_X; x++) {
for (int y = MAX_Y - 1; y >= 0; y--) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int y0 = y - 1; y0 >= 0; y0--) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else {
return;
}
}
}
}
//上滑
//合并
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() == 0) {
continue;
}
for (int y0 = y + 1; y0 < MAX_Y; y0++) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else if (tiles[x][y].getNumber() == tiles[x][y0].getNumber()) {
return;
} else {
break;
}
}
}
}
//移动
for (int x = 0; x < MAX_X; x++) {
for (int y = 0; y < MAX_Y; y++) {
if (tiles[x][y].getNumber() != 0) {
continue;
}
for (int y0 = y + 1; y0 < MAX_Y; y0++) {
if (tiles[x][y0].getNumber() == 0) {
continue;
} else {
return;
}
}
}
}
gameState = GameState.Over;
invalidate();
}
}
说两句:
这次跟上次的五子棋用的一样的游戏框架,应该很容易理解游戏的主题逻辑,当然最重要的是游戏算法,我实现的算法可能有些麻烦,但还算达到了效果,欢迎提意见。
关于主体算法:
我分了两个步骤:1.合并。2.移动
哎呀,不写了,有兴趣的人自己看代码吧,好像也没多少人看我写这个东西。。。囧
下次写个能动的游戏,就贪吃蛇吧,感觉自己帅的人请加我的公众微信号:xinshouit 更新会在里面通知