Android小游戏2048的简单实现

今天无聊自己写了个简单的2048,并没有经过什么仔细的设计,只是想自己实现游戏功能,一切以实现功能为主,能最快做出自己想做的东西获得小小的成就感,才有动力继续学习。所以代码很烂,都写在一个类里面了,很显然这并不是一种好的做法。


下面来看看这个游戏


4*4的地图,很明显,一看到这张图就想到使用二维数组来保存每个分值:

		int[][] map = {
				{8, 32, 64, 512},
				{4, 8, 16, 256},
				{2, 4, 8, 32},
				{0, 0, 4, 8}
		};
就是这样,游戏里面直接对数组进行操作就行了


整个游戏区域我是直接用canvas画出来的,建立一个类GameView继承View,看代码

package com.houjian.game.my2048;

import java.util.Random;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

/**
 * @author HouJian
 * @date 2015年5月27日
 */
public class GameView extends View {
	/**
	 * 默认模式4*4的地图
	 */
	public static final int COUNT = 4;

	/**
	 * 对应分值方块的颜色
	 */
	private static SparseIntArray colors;
	static {
		colors = new SparseIntArray();
		colors.put(2, Color.parseColor("#EEE4DA"));
		colors.put(4, Color.parseColor("#EDE0C8"));
		colors.put(8, Color.parseColor("#F2B179"));
		colors.put(16, Color.parseColor("#F59563"));
		colors.put(32, Color.parseColor("#F67C5F"));
		colors.put(64, Color.parseColor("#F65E3B"));
		colors.put(128, Color.parseColor("#DCBF65"));
		colors.put(256, Color.parseColor("#EDCC61"));
		colors.put(512, Color.parseColor("#EDC850"));
		colors.put(1024, Color.parseColor("#DBB732"));
		colors.put(2048, Color.parseColor("#EFC329"));
		colors.put(4096, Color.parseColor("#FF3C39"));
	}
	/**
	 * 屏幕宽度
	 */
	private int screenWidth;
	/**
	 * 屏幕高度
	 */
	private int screenHeight;
	/**
	 * 画笔
	 */
	private Paint paint;
	/**
	 * 画笔宽度
	 */
	private float paintWidth;
	/**
	 * 游戏区域开始点x坐标
	 */
	private int areaStartX;
	/**
	 * 游戏区域开始点y坐标
	 */
	private int areaStartY;
	/**
	 * 分值方块的大小
	 */
	private int cellSize;
	/**
	 * 游戏方块分值保存数组
	 */
	private int[][] map;
	/**
	 * 手指按下x坐标
	 */
	private float xDown;
	/**
	 * 手指按下y坐标
	 */
	private float yDown;
	/**
	 * 手指移动x坐标
	 */
	private float xMove;
	/**
	 * 手指移动y坐标
	 */
	private float yMove;
	/**
	 * 手指是否按下
	 */
	private boolean isPressed;
	/**
	 * 游戏地图是否已经移动过了
	 */
	private boolean isMoved;
	/**
	 * 随机数生成器
	 */
	private Random random;
	/**
	 * 当前得分
	 */
	private int score;

	public GameView(Context context) {
		this(context, null);
	}

	public GameView(Context context, AttributeSet attrs) {
		super(context, attrs);

		this.paint = new Paint();
		this.paintWidth = 15f;
		this.random = new Random();
		this.map = new int[COUNT][COUNT];

		// 默认初始化3个方块
		for (int i = 0; i < 3; i++) {
			createRandomRect();
		}

		WindowManager windowManager = (WindowManager) context
				.getSystemService(Context.WINDOW_SERVICE);
		DisplayMetrics outMetrics = new DisplayMetrics();
		windowManager.getDefaultDisplay().getMetrics(outMetrics);
		screenWidth = outMetrics.widthPixels;
		screenHeight = outMetrics.heightPixels;

		areaStartY = (screenHeight - screenWidth) >> 1;
		areaStartX = 0;

		cellSize = screenWidth / COUNT;
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		drawGameArea(canvas, areaStartX, areaStartY);
		drawGameRect(canvas, map);
		drawScore(canvas);
	}

	/**
	 * 从屏幕的(x,y)点开始画出游戏区域
	 * 
	 * @param canvas
	 * @param x
	 * @param y
	 */
	private void drawGameArea(Canvas canvas, int x, int y) {
		// 画游戏区域背景
		paint.reset();
		paint.setColor(Color.parseColor("#CDC7BB"));
		canvas.drawRect(x, y, screenWidth, y + screenWidth, paint);

		// 画出分割线
		paint.reset();
		paint.setColor(Color.parseColor("#CDB599"));
		paint.setStrokeWidth(paintWidth);
		for (int i = 0; i <= COUNT; i++) {
			canvas.drawLine(x + i, cellSize * i + y, screenWidth, cellSize * i + y, paint);
		}
		for (int i = 0; i <= COUNT; i++) {
			canvas.drawLine(cellSize * i, i + y, cellSize * i, screenWidth + y, paint);
		}
	}

	/**
	 * 画出游戏方块
	 * 
	 * @param canvas
	 * @param map
	 */
	private void drawGameRect(Canvas canvas, int[][] map) {
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (map[i][j] != 0) {
					drawEachRect(canvas, i, j);
				}
			}
		}
	}

	/**
	 * 画出每一个小方块
	 * 
	 * @param canvas
	 * @param i
	 * @param j
	 */
	private void drawEachRect(Canvas canvas, int i, int j) {
		// 画游戏方块背景
		paint.reset();
		paint.setColor(colors.get(map[i][j], colors.get(4096)));
		canvas.drawRect(cellSize * j + areaStartX + paintWidth / 2, cellSize * i + areaStartY
				+ paintWidth / 2, cellSize * j + areaStartX - paintWidth / 2 + cellSize, cellSize
				* i + areaStartY - paintWidth / 2 + cellSize, paint);

		// 画出方块分值
		paint.reset();
		if (map[i][j] <= 4) {
			paint.setColor(Color.BLACK);
		} else {
			paint.setColor(Color.WHITE);
		}
		paint.setTextAlign(Align.CENTER);
		paint.setStrokeWidth(paintWidth);
		paint.setTextSize(cellSize * 5 / 12);
		canvas.drawText(String.valueOf(map[i][j]), cellSize * j + areaStartX + cellSize / 2,
				cellSize * i + areaStartY + cellSize * 2 / 3, paint);
	}

	/**
	 * 显示得分
	 * 
	 * @param canvas
	 */
	private void drawScore(Canvas canvas) {
		paint.reset();
		paint.setColor(Color.GRAY);
		paint.setTextSize(cellSize * 5 / 12);
		paint.setTextAlign(Align.CENTER);
		paint.setStrokeWidth(paintWidth);
		canvas.drawText("得分:" + score, screenWidth / 2, areaStartY / 2, paint);
	}

	/**
	 * 处理触摸事件
	 */
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			isPressed = true;
			xDown = event.getRawX();
			yDown = event.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			xMove = event.getRawX();
			yMove = event.getRawY();

			// 移动距离
			int distanceX = (int) (xMove - xDown);
			int distanceY = (int) (yMove - yDown);

			// 移动距离绝对值
			int absX = Math.abs(distanceX);
			int absY = Math.abs(distanceY);

			// 如果移动距离大于屏幕宽度的1/4就算作有效移动
			if (absX > (screenWidth >> 2) || absY > (screenWidth >> 2)) {
				if (absX > absY) {
					if (distanceX < 0) {
						moveToLeft();
					} else {
						moveToRight();
					}
				} else {
					if (distanceY < 0) {
						moveToUp();
					} else {
						moveToDown();
					}
				}
			}
			break;
		case MotionEvent.ACTION_UP:
			isPressed = false;
			isMoved = false;
			break;
		default:
			break;
		}
		return super.onTouchEvent(event);
	}

	/**
	 * 不能移动?
	 * 
	 * @return
	 */
	private boolean canNotMove() {
		// 手指按下状态,并且已经掉用过移动方法了,就不继续调用了,防止按下多次调用移动方法
		return isPressed && isMoved;
	}

	/**
	 * 上移
	 */
	private void moveToUp() {
		if (canNotMove()) {
			return;
		}
		// 保存移动前状态
		int[][] mapTemp = copyMap(map);

		// 先消除中间空白方块
		int k;
		int temp;
		for (int j = 0; j < COUNT; j++) {
			for (int i = 0; i < COUNT - 1; i++) {
				k = i;
				while (k < COUNT - 1 && map[k][j] == 0) {
					temp = map[k][j];
					map[k][j] = map[k + 1][j];
					map[k + 1][j] = temp;
					k++;
				}
			}
		}

		// 合并能够相加的方块
		for (int j = 0; j < COUNT; j++) {
			for (int i = 0; i < COUNT - 1; i++) {
				if (map[i][j] == map[i + 1][j]) {
					map[i][j] *= 2;
					score += map[i + 1][j];
					map[i + 1][j] = 0;
				}
			}
		}

		// 再消除一遍中间空白方块
		for (int j = 0; j < COUNT; j++) {
			for (int i = 0; i < COUNT - 1; i++) {
				k = i;
				while (k < COUNT - 1 && map[k][j] == 0) {
					temp = map[k][j];
					map[k][j] = map[k + 1][j];
					map[k + 1][j] = temp;
					k++;
				}
			}
		}

		// 如果移动过后方块数据不相等,说明移动成功,应该创建一个新的方块
		if (!isEquals(mapTemp, map)) {
			createRandomRect();
		}

		// 刷新画面
		invalidate();
		isMoved = true;
	}

	/**
	 * 下移
	 */
	private void moveToDown() {
		if (canNotMove()) {
			return;
		}

		int[][] mapTemp = copyMap(map);

		int k;
		int temp;
		for (int j = 0; j < COUNT; j++) {
			for (int i = COUNT - 1; i > 0; i--) {
				k = i;
				while (k > 0 && map[k][j] == 0) {
					temp = map[k][j];
					map[k][j] = map[k - 1][j];
					map[k - 1][j] = temp;
					k--;
				}
			}
		}

		for (int j = 0; j < COUNT; j++) {
			for (int i = COUNT - 1; i > 0; i--) {
				if (map[i][j] == map[i - 1][j]) {
					map[i][j] *= 2;
					score += map[i - 1][j];
					map[i - 1][j] = 0;
				}
			}
		}

		for (int j = 0; j < COUNT; j++) {
			for (int i = COUNT - 1; i > 0; i--) {
				k = i;
				while (k > 0 && map[k][j] == 0) {
					temp = map[k][j];
					map[k][j] = map[k - 1][j];
					map[k - 1][j] = temp;
					k--;
				}
			}
		}
		if (!isEquals(mapTemp, map)) {
			createRandomRect();
		}
		invalidate();
		isMoved = true;
	}

	/**
	 * 左移
	 */
	private void moveToLeft() {
		if (canNotMove()) {
			return;
		}
		int[][] mapTemp = copyMap(map);

		int k;
		int temp;
		for (int i = 0; i < COUNT; i++) {
			for (int j = 0; j < map[i].length - 1; j++) {
				k = j;
				while (k < COUNT - 1 && map[i][k] == 0) {
					temp = map[i][k];
					map[i][k] = map[i][k + 1];
					map[i][k + 1] = temp;
					k++;
				}
			}
		}

		for (int i = 0; i < COUNT; i++) {
			for (int j = 0; j < map[i].length - 1; j++) {
				if (map[i][j] == map[i][j + 1]) {
					map[i][j] *= 2;
					score += map[i][j + 1];
					map[i][j + 1] = 0;
				}
			}
		}

		for (int i = 0; i < COUNT; i++) {
			for (int j = 0; j < map[i].length - 1; j++) {
				k = j;
				while (k < COUNT - 1 && map[i][k] == 0) {
					temp = map[i][k];
					map[i][k] = map[i][k + 1];
					map[i][k + 1] = temp;
					k++;
				}
			}
		}
		if (!isEquals(mapTemp, map)) {
			createRandomRect();
		}
		invalidate();
		isMoved = true;
	}

	/**
	 * 右移
	 */
	private void moveToRight() {
		if (canNotMove()) {
			return;
		}
		int[][] mapTemp = copyMap(map);

		int k;
		int temp;
		for (int i = 0; i < COUNT; i++) {
			for (int j = map[i].length - 1; j > 0; j--) {
				k = j;
				while (k > 0 && map[i][k] == 0) {
					temp = map[i][k];
					map[i][k] = map[i][k - 1];
					map[i][k - 1] = temp;
					k--;
				}
			}
		}

		for (int i = 0; i < COUNT; i++) {
			for (int j = map[i].length - 1; j > 0; j--) {
				if (map[i][j] == map[i][j - 1]) {
					map[i][j] *= 2;
					score += map[i][j - 1];
					map[i][j - 1] = 0;
				}
			}
		}

		for (int i = 0; i < COUNT; i++) {
			for (int j = map[i].length - 1; j > 0; j--) {
				k = j;
				while (k > 0 && map[i][k] == 0) {
					temp = map[i][k];
					map[i][k] = map[i][k - 1];
					map[i][k - 1] = temp;
					k--;
				}
			}
		}
		if (!isEquals(mapTemp, map)) {
			createRandomRect();
		}
		invalidate();
		isMoved = true;
	}

	/**
	 * 创建随机方块
	 */
	private void createRandomRect() {
		int num = Math.random() < 0.9 ? 2 : 4; // 随机出现一个2或者4

		int x;
		int y;
		do {
			x = random.nextInt(COUNT);
			y = random.nextInt(COUNT);
		} while (map[x][y] != 0); // 随机找一点,直到该点没有方块为止

		map[x][y] = num; // 把新生成的数加到地图里面
	}

	/**
	 * 判断两份方块数据是否一致
	 * 
	 * @param tempMap
	 * @param map
	 * @return
	 */
	private boolean isEquals(int[][] tempMap, int[][] map) {
		for (int i = 0; i < COUNT; i++) {
			for (int j = 0; j < COUNT; j++) {
				if (tempMap[i][j] != map[i][j]) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * 复制一份游戏方块数据
	 * 
	 * @param map
	 * @return
	 */
	private int[][] copyMap(int[][] map) {
		int[][] tempMap = new int[COUNT][COUNT];
		for (int i = 0; i < COUNT; i++) {
			tempMap[i] = map[i].clone(); // 数组克隆
		}
		return tempMap;
	}
}

就这一个类就实现了所有的功能,核心就是事件处理和那几个moveToXXX函数。

直接在MainActivity里面构造这个类就行了

package com.houjian.game.my2048;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.os.Bundle;
import android.view.MotionEvent;

/**
 * @author HouJian
 * @date 2015年5月27日
 */
public class MainActivity extends Activity {
	private GameView gameView;
	private AlertDialog dialog;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		gameView = new GameView(this);
		setContentView(gameView);

		dialog = new AlertDialog.Builder(this).setTitle("确认消息").setMessage("你确定要退出游戏吗?")
				.setPositiveButton("确认", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						finish();
					}
				}).setNegativeButton("取消", new OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						return;
					}
				}).create();
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		return gameView.onTouchEvent(event);
	}

	@Override
	public void onBackPressed() {
		dialog.show();
	}
}

好了,这就是全部代码了,并没有使用布局文件,看看这个游戏的逻辑也挺简单的,主要是对二维数组的运用。


添加积分功能  项目源码,点击下载


  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值