我也来开发2048之终极奥义

本次教程跟之前隔了不少时间哈,有点忘记了的建议先看看前面的熟悉下,今天我准备把这个2048给结束了,拖了这么久。

按照惯例,我们已经把准备工作都做好了,今天这一部分信息量比较大,也是整个游戏的核心所在,所以我准备分功能来讲,最后大家结合源码来看就不会感觉太吃力了。

1、初始化游戏

初始化的时候,我们要干嘛呢,首先要看配置,配置了几行,然后先画好面板,然后要给在面板上随机生成2个数字Item,这涉及到2个方法,一个是初始化面板,一个是添加随机数字

private void initGameView(int cardSize) {
	removeAllViews();
	GameItem card;
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		card = new GameItem(getContext(), 0);
		addView(card, cardSize, cardSize);
		// 初始化GameMatrix全部为0 空格List为所有
		gameMatrix[i][j] = card;
		blanks.add(new Point(i, j));
	    }
	}
	// 添加随机数字
	addRandomNum();
	addRandomNum();
    }

private void addRandomNum() {
	getBlanks();
	if (blanks.size() > 0) {
	    int randomNum = (int) (Math.random() * blanks.size());
	    Point randomPoint = blanks.get(randomNum);
	    gameMatrix[randomPoint.x][randomPoint.y].setNum(Math.random() > 0.2d ? 2 : 4);
	    Game.getGameActivity().getAnimationLayer().animcreate(gameMatrix[randomPoint.x][randomPoint.y]);
	}
    }

在判断生成2、4的时候,我们使用了通常产生范围随机数的方法,同时指定2和4的比例在1:4,当然这个大家可以根据需要更改

2、具体参数等初始化

这个比较简单了,直接上代码,大家应该都看得懂

private void initGameMatrix() {
	// 初始化矩阵
	removeAllViews();
	scoreHistory = 0;
	Config.Scroe = 0;
	Config.GameLines = Config.sp.getInt(Config.KEY_GameLines, 4);
	gameLines = Config.GameLines;
	gameMatrix = new GameItem[gameLines][gameLines];
	gameMatrixHistory = new int[gameLines][gameLines];
	calList = new ArrayList<Integer>();
	blanks = new ArrayList<Point>();
	highScore = Config.sp.getInt(Config.KEY_HighScore, 0);
	setColumnCount(gameLines);
	setRowCount(gameLines);
	setOnTouchListener(this);
	// 初始化View参数
	DisplayMetrics metrics = new DisplayMetrics();
	WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
	Display display = wm.getDefaultDisplay();
	display.getMetrics(metrics);
	Config.ItemSize = metrics.widthPixels / Config.GameLines;
	initGameView(Config.ItemSize);
    }

这部分最好还是结合源码看比较好,注释清晰

3、触摸事件

触摸的时候判断4个方向,这个基本也是通用的写法了,不多说了

public boolean onTouch(View v, MotionEvent event) {
	switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN:
	    saveHistoryMatrix();
	    startX = (int) event.getX();
	    startY = (int) event.getY();
	    break;
	case MotionEvent.ACTION_MOVE:
	    break;
	case MotionEvent.ACTION_UP:
	    endX = (int) event.getX();
	    endY = (int) event.getY();
	    judgeDirection(endX - startX, endY - startY);
	    if (isMoved()) {
		addRandomNum();
		// 修改显示分数
		Game.getGameActivity().setScore(Config.Scroe, 0);
	    }
	    int result = checkCompleted();
	    if (result == 0) {
		if (Config.Scroe > highScore) {
		    Editor editor = Config.sp.edit();
		    editor.putInt(Config.KEY_HighScore, Config.Scroe);
		    editor.commit();
		}
		Toast.makeText(getContext(), "lose", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    } else if (result == 2) {
		Toast.makeText(getContext(), "success", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    }
	    break;
	default:
	    break;
	}
	return true;
    }

其中判断偏移的方法

private void judgeDirection(int offsetX, int offsetY) {
	if (Math.abs(offsetX) > Math.abs(offsetY)) {
	    if (offsetX > 10) {
		swipeRight();
	    } else {
		swipeLeft();
	    }
	} else {
	    if (offsetY > 10) {
		swipeDown();
	    } else {
		swipeUp();
	    }
	}
    }

下面我们来讲2048的终极奥义了,就是算法的实现,具体的算法在第一篇中已经讲解了大概的过程,点我去看,下面我们选一个方向来讲如何实现

private void swipeLeft() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		int currentNum = gameMatrix[i][j].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < calList.size(); j++) {
		gameMatrix[i][j].setNum(calList.get(j));
	    }
	    for (int m = calList.size(); m < gameLines; m++) {
		gameMatrix[i][m].setNum(0);
	    }
	    // 重置行参数
	    keyItemNum = -1;
	    calList.clear();
	}
    }

概括来说,就是选取基准,挨个比较,重新排列

代码很清晰,大家看看就知道了,关键是如何总结出这个算法。

4、下面就是判断游戏什么时候需要新加入一个数字Item

当当前的数字矩阵结构域上次的结构发生差别的时候,我们就要add一个新的数字Item了

private boolean isMoved() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrixHistory[i][j] != gameMatrix[i][j].getNum()) {
		    return true;
		}
	    }
	}
	return false;
    }

这个地方我们使用了一个历史矩阵来存储上一次的数字矩阵

5、最后就是如何判断结束了

如果当前还有空格的Item,则必定没有结束,若相邻的数字都没有相同的数字,则必定结束,若出现配置的Goal,则赢了

private int checkCompleted() {
	getBlanks();
	if (blanks.size() == 0) {
	    for (int i = 0; i < gameLines; i++) {
		for (int j = 0; j < gameLines; j++) {
		    if (j < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i][j + 1].getNum()) {
			    return 1;
			}
		    }
		    if (i < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i + 1][j].getNum()) {
			    return 1;
			}
		    }
		}
	    }
	    return 0;
	}
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrix[i][j].getNum() == 2048) {
		    return 2;
		}
	    }
	}
	return 1;
    }

下面放出一些最终的图片:

由于刚换了工作,上下班时间倍增,所以写代码的时间也少了,其实关于这个游戏我还有很多想法没做,这个版本的2048,比网上的版本,多了撤销上次移动功能,多了可以定制游戏维数的功能,多了配置目标值的功能,我这个版本的2048,配置要求极低,相比cocos2dx版本的来说,极大的降低了电量消耗,可配置性更强。这些都是我在玩的过程中,觉得不爽的地方,然后改进的,还有一些想法,目前还没有去做,平时工作去做android的framework了,应用层也就研究的少了,希望大家能改进我的代码,做出更好的2048。

1、添加debug功能,也称作弊后门,我原来是想,当手指滑动超过多少距离后,调用一个新方法,设置添加的随机数的位置和大小,这个用我现在的代码是很好实现的,只要把addRandom方法改下,写一个debugRandom方法就OK了

2、分享功能,这个用ShareSdk就可以了,玩游戏嘛,就是要大家一起玩才好玩,无社交不游戏

3、更换2、4、8、16……数字的背景,这个网上很多了,我们也可以自定义一套背景,这个实现也是比较简单的,只要把GameItem这个类里面的Item的背景添加一个set方法就ok了

以上,终了

以下,刷代码

package com.xys.game2048.view;

import java.util.ArrayList;
import java.util.List;

import android.content.Context;
import android.content.SharedPreferences.Editor;
import android.graphics.Point;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.GridLayout;
import android.widget.Toast;

import com.xys.game2048.activity.Game;
import com.xys.game2048.bean.GameItem;
import com.xys.game2048.config.Config;

public class GameView extends GridLayout implements OnTouchListener {

    // GameView对应矩阵
    private GameItem[][] gameMatrix;
    // 空格List
    private List<Point> blanks;
    // 矩阵行列数
    private int gameLines;
    // 记录坐标
    private int startX, startY, endX, endY;
    // 辅助数组
    private List<Integer> calList;
    private int keyItemNum = -1;
    // 历史记录数组
    private int[][] gameMatrixHistory;
    // 历史记录分数
    private int scoreHistory;
    // 最高记录
    private int highScore;

    public GameView(Context context) {
	super(context);
	initGameMatrix();
    }

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

    public void startGame() {
	initGameMatrix();
	initGameView(Config.ItemSize);
    }

    private void initGameView(int cardSize) {
	removeAllViews();
	GameItem card;
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		card = new GameItem(getContext(), 0);
		addView(card, cardSize, cardSize);
		// 初始化GameMatrix全部为0 空格List为所有
		gameMatrix[i][j] = card;
		blanks.add(new Point(i, j));
	    }
	}
	// 添加随机数字
	addRandomNum();
	addRandomNum();
    }

    /**
     * 撤销上次移动
     */
    public void revertGame() {
	if (gameMatrixHistory.length != 0) {
	    Game.getGameActivity().setScore(scoreHistory, 0);
	    Config.Scroe = scoreHistory;
	    for (int i = 0; i < gameLines; i++) {
		for (int j = 0; j < gameLines; j++) {
		    gameMatrix[i][j].setNum(gameMatrixHistory[i][j]);
		}
	    }
	}
    }

    /**
     * 添加随机数字
     */
    private void addRandomNum() {
	getBlanks();
	if (blanks.size() > 0) {
	    int randomNum = (int) (Math.random() * blanks.size());
	    Point randomPoint = blanks.get(randomNum);
	    gameMatrix[randomPoint.x][randomPoint.y].setNum(Math.random() > 0.2d ? 2 : 4);
	    Game.getGameActivity().getAnimationLayer().animcreate(gameMatrix[randomPoint.x][randomPoint.y]);
	}
    }

    /**
     * 获取空格Item数组
     */
    private void getBlanks() {
	blanks.clear();
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrix[i][j].getNum() == 0) {
		    blanks.add(new Point(i, j));
		}
	    }
	}
    }

    /**
     * 初始化View
     */
    private void initGameMatrix() {
	// 初始化矩阵
	removeAllViews();
	scoreHistory = 0;
	Config.Scroe = 0;
	Config.GameLines = Config.sp.getInt(Config.KEY_GameLines, 4);
	gameLines = Config.GameLines;
	gameMatrix = new GameItem[gameLines][gameLines];
	gameMatrixHistory = new int[gameLines][gameLines];
	calList = new ArrayList<Integer>();
	blanks = new ArrayList<Point>();
	highScore = Config.sp.getInt(Config.KEY_HighScore, 0);
	setColumnCount(gameLines);
	setRowCount(gameLines);
	setOnTouchListener(this);
	// 初始化View参数
	DisplayMetrics metrics = new DisplayMetrics();
	WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
	Display display = wm.getDefaultDisplay();
	display.getMetrics(metrics);
	Config.ItemSize = metrics.widthPixels / Config.GameLines;
	initGameView(Config.ItemSize);
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
	switch (event.getAction()) {
	case MotionEvent.ACTION_DOWN:
	    saveHistoryMatrix();
	    startX = (int) event.getX();
	    startY = (int) event.getY();
	    break;
	case MotionEvent.ACTION_MOVE:
	    break;
	case MotionEvent.ACTION_UP:
	    endX = (int) event.getX();
	    endY = (int) event.getY();
	    judgeDirection(endX - startX, endY - startY);
	    if (isMoved()) {
		addRandomNum();
		// 修改显示分数
		Game.getGameActivity().setScore(Config.Scroe, 0);
	    }
	    int result = checkCompleted();
	    if (result == 0) {
		if (Config.Scroe > highScore) {
		    Editor editor = Config.sp.edit();
		    editor.putInt(Config.KEY_HighScore, Config.Scroe);
		    editor.commit();
		}
		Toast.makeText(getContext(), "lose", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    } else if (result == 2) {
		Toast.makeText(getContext(), "success", Toast.LENGTH_LONG).show();
		Config.Scroe = 0;
	    }
	    break;
	default:
	    break;
	}
	return true;
    }

    /**
     * 保存历史记录
     */
    private void saveHistoryMatrix() {
	scoreHistory = Config.Scroe;
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		gameMatrixHistory[i][j] = gameMatrix[i][j].getNum();
	    }
	}
    }

    /**
     * 根据偏移量判断移动方向
     *
     * @param offsetX
     * @param offsetY
     */
    private void judgeDirection(int offsetX, int offsetY) {
	if (Math.abs(offsetX) > Math.abs(offsetY)) {
	    if (offsetX > 10) {
		swipeRight();
	    } else {
		swipeLeft();
	    }
	} else {
	    if (offsetY > 10) {
		swipeDown();
	    } else {
		swipeUp();
	    }
	}
    }

    /**
     * 判断是否结束
     *
     * @return 0:结束 1:正常 2:成功
     */
    private int checkCompleted() {
	getBlanks();
	if (blanks.size() == 0) {
	    for (int i = 0; i < gameLines; i++) {
		for (int j = 0; j < gameLines; j++) {
		    if (j < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i][j + 1].getNum()) {
			    return 1;
			}
		    }
		    if (i < gameLines - 1) {
			if (gameMatrix[i][j].getNum() == gameMatrix[i + 1][j].getNum()) {
			    return 1;
			}
		    }
		}
	    }
	    return 0;
	}
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrix[i][j].getNum() == 2048) {
		    return 2;
		}
	    }
	}
	return 1;
    }

    /**
     * 判断是否移动过(是否需要新增Item)
     *
     * @return
     */
    private boolean isMoved() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		if (gameMatrixHistory[i][j] != gameMatrix[i][j].getNum()) {
		    return true;
		}
	    }
	}
	return false;
    }

    /**
     * 滑动事件:上
     */
    private void swipeUp() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		int currentNum = gameMatrix[j][i].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < calList.size(); j++) {
		gameMatrix[j][i].setNum(calList.get(j));
	    }
	    for (int m = calList.size(); m < gameLines; m++) {
		gameMatrix[m][i].setNum(0);
	    }
	    // 重置行参数
	    keyItemNum = -1;
	    calList.clear();
	}
    }

    /**
     * 滑动事件:下
     */
    private void swipeDown() {
	for (int i = gameLines - 1; i >= 0; i--) {
	    for (int j = gameLines - 1; j >= 0; j--) {
		int currentNum = gameMatrix[j][i].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < gameLines - calList.size(); j++) {
		gameMatrix[j][i].setNum(0);
	    }
	    int index = calList.size() - 1;
	    for (int m = gameLines - calList.size(); m < gameLines; m++) {
		gameMatrix[m][i].setNum(calList.get(index));
		index--;
	    }
	    // 重置行参数
	    keyItemNum = -1;
	    calList.clear();
	    index = 0;
	}
    }

    /**
     * 滑动事件:左
     */
    private void swipeLeft() {
	for (int i = 0; i < gameLines; i++) {
	    for (int j = 0; j < gameLines; j++) {
		int currentNum = gameMatrix[i][j].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < calList.size(); j++) {
		gameMatrix[i][j].setNum(calList.get(j));
	    }
	    for (int m = calList.size(); m < gameLines; m++) {
		gameMatrix[i][m].setNum(0);
	    }
	    // 重置行参数
	    keyItemNum = -1;
	    calList.clear();
	}
    }

    /**
     * 滑动事件:右
     */
    private void swipeRight() {
	for (int i = gameLines - 1; i >= 0; i--) {
	    for (int j = gameLines - 1; j >= 0; j--) {
		int currentNum = gameMatrix[i][j].getNum();
		if (currentNum != 0) {
		    if (keyItemNum == -1) {
			keyItemNum = currentNum;
		    } else {
			if (keyItemNum == currentNum) {
			    calList.add(keyItemNum * 2);
			    Config.Scroe += keyItemNum * 2;
			    keyItemNum = -1;
			} else {
			    calList.add(keyItemNum);
			    keyItemNum = currentNum;
			}
		    }
		} else {
		    continue;
		}
	    }
	    if (keyItemNum != -1) {
		calList.add(keyItemNum);
	    }
	    // 改变Item值
	    for (int j = 0; j < gameLines - calList.size(); j++) {
		gameMatrix[i][j].setNum(0);
	    }
	    int index = calList.size() - 1;
	    for (int m = gameLines - calList.size(); m < gameLines; m++) {
		gameMatrix[i][m].setNum(calList.get(index));
		index--;
	    }
	    // 重置行参数
	    keyItemNum = -1;
	    calList.clear();
	    index = 0;
	}
    }
}

PS 需要源码的请留言

PS 需要源码的请留言

时间: 2024-09-17 03:39:17

我也来开发2048之终极奥义的相关文章

阿里正式发布《Java开发手册》终极版!

本文讲的是阿里正式发布<Java开发手册>终极版!,别人都说我们是码农,但我们知道,自己是个艺术家.也许我们不过多在意自己的外表和穿着,但我们不羁的外表下,骨子里追求着代码的美.质量的美.而代码规约其实就是一个对美的定义. <阿里巴巴Java开发手册>系统性地从编程.数据库.异常日志.工程结构.安全.单元测试六大方面,总结出优秀Java开发者必备的技术素养.时值手册发布一周年之际,阿里官方对外正式公开<阿里巴巴Java开发手册>终!极!版!!! 该版本将是阿里官方对外释

千呼万唤始出来—阿里正式发布《Java开发手册》终极版!

摘要: 本文讲的是阿里正式发布<Java开发手册>终极版!,别人都说我们是码农,但我们知道,自己是个艺术家.也许我们不过多在意自己的外表和穿着,但我们不羁的外表下,骨子里追求着代码的美.质量的美.而代码规约其实就是一个对美的定义. 经过阿里开发工程师的不断完善,改进.<JAVA开发手册>终极版终于发布了! 前言 <阿里巴巴Java开发手册>是阿里巴巴集团技术团队的集体智慧结晶和经验总结,经历了多次大规模一线实战的检验及不断的完善,系统化地整理成册,反馈给广大开发者.现代

【Java编码规范】《阿里巴巴Java开发手册》终极版更新,在线代码检测及IDE插件发布

        -------------- 2017.10.14更新 -------------- <阿里巴巴Java开发手册(终极版)>正式发布,这是史上内容最全.修正最为彻底的一个版本,并且增加了单元测试规约内容,这也是阿里官方对外发布的最后一个PDF版本,值得收藏.   <阿里巴巴Java开发手册>是阿里内部Java工程师所遵循的开发规范,涵盖编程规约.单元测试规约.异常日志规约.MySQL规约.工程规约.安全规约等,这是近万名阿里Java技术精英的经验总结,并经历了多次大

我也来开发2048之确定思路

以下内容拔自百度: 2048是比较流行的一款数字游戏.原版2048首先在github上发布,原作者是Gabriele Cirulli.它是基于<1024>和<小3传奇>的玩法开发 而成的新型数字游戏.随后2048便出现各种版本,走各大平台.由Ketchapp公司移植到IOS的版本最为火热,现在约有1000万下载,其名字跟 原版一模一样.衍生版中最出名的是<2048六边形>版本,先后在全球81个国家中的board game中排进了前200.安卓版非常火爆的有<挑战2

创建和发布 Android 开发库的终极指南

相关术语介绍 在我们开始之前,还有一些术语,需要熟悉下. 项目Project  –  在 Android Studio 中,一个 项目 就是一个完整的 Android app.Android Studio 项目包含了一个或多个模块. 在 Android Studio 中,一个 项目 类似于在 Eclipse 的一个工作区间workspace. 模块Module – 一个 模块 是 app 中的一个组件,它可以单独的进行构建.测试和调试.模块包含了 app 的源代码和资源文件.在 Android

我也来开发2048之方块设计

这次我们的任务是实现游戏面板上的一个个小方块,我们的主面板是一个GridLayout,我们把小方块一个个加到GridLayout中,就形成了我们现在的这个游戏面板. 小方块还是比较简单的,关键是,如何做才能最有效率呢?这是我们一直考虑的,也算是职业强迫症吧,我们的小方块上其实就是显示一个数字,所以,我们可以用一个TextView或者ImageView,这个随意了,看以后的打算,是否需要自定义图片呀等等,我们暂时就用一个TextView吧,简单. 父布局选择什么呢?其实因为我们就一个子View,所

我也来开发2048之配置界面设计

我们的程序当然不像现在市面上的2048那样死板,一辈子4X4的面板,现在的人,讲究的就是随心所欲,所有的东西都在我的掌控中,这才爽. 所以我们的程序也得有个配置界面,国际惯例,上图: 这个配置界面主要完成以下几个功能: 1.可配置游戏面板的维数,即4X4,5X5,6X6,其实继续写下去也是可以的,但是,欲望也是要有限度的啊,差不多就够了 2.要达到的目标,你可以选择到1024就爽了呢,还是2048才爽,还是4096才爽,其实也是可以一直写下去的,老规矩,不要把自己逼的太紧了,差不多就行了,虐自己

使用 AngularJS 开发 2048 游戏

我频繁地被问及到的一个问题之一,就是什么时候使用Angular框架是一个糟糕的选择.我的默认答复是编写游戏的时候,尽管Angular有它自己的事 件循环处理 ($digest循环) ,并且游戏通常需要很多底层DOM操作.如果说有Angular能支持很多类型的游戏,那这个说法可不准确.即使游戏需要大量的DOM操作,这可能会用到 angular框架处理静态部分,如记录最高分和游戏菜单. 文章转载自 开源中国社区 [http://www.oschina.net]

微信小程序开发(5) 2048游戏

在这篇微信小程序开发教程中,我们将介绍如何使用微信小程序开发2048小游戏. 本文主要分为两个部分,小程序主体部分及小游戏页面部分   一.小程序主体部分 一个小程序主体部分由三个文件组成,必须放在项目的根目录,如下:   1. 小程序逻辑 App({ onLaunch: function() { // Do something initial when launch. }, onShow: function() { // Do something when show. }, onHide: f