怎样设计一个算法可以高效的完成2048游戏算法

关注我们:
无需注册,以下账号可直接登录!
最新专区热门专区
2048作为一款益智类的游戏,游戏的方式有点像是中国古代的九宫格,但是比九宫格要稍微简单一些,越后面的关卡越难度越是大,很多玩家都很好奇,2048的最高分是多少呢?这是游戏中玩家非常关心的一点,下面就跟手心攻略网小编一起来看看2048得出最高分解算法演示视频吧,希望能够对大家有所帮助。2048得出最高分解算法......
2048的游戏规则很简单,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块。下面小编带来的这则视频......
2048这款游戏非常受玩家的欢迎,游戏规则很简单,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块......
2048可以说是第二个flappybird游戏,游戏非常的简单,而且被衍生出了很多的山寨游戏,同时也很难让玩家释怀。那么作为数字合并游戏,其数值合并有上限吗?最高分是多少呢?这个很值得我们来思考。现在手心攻略网的小编就来给玩家们解答一下。问:2048游戏数值合并有上限吗?最高分是多少?手心攻略网小编解答:由于游戏......
2048这款游戏非常受玩家的欢迎,游戏规则很简单,每次可以选择上下左右其中一个方向去滑动,每滑动一次,所有的数字方块都会往滑动的方向靠拢外,系统也会在空白的地方乱数出现一个数字方块,相同数字的方块在靠拢、相撞时会相加。系统给予的数字方块不是2就是4,玩家要想办法在这小小的16格范围中凑出“2048”这个数字方块......
2048作为一款益智类的游戏,游戏的方式有点像是中国古代的九宫格,但是比九宫格要稍微简单一些,越后面的关卡越难度越是大,现在小编总结出了一些适合新手的进阶攻略,让新手玩家迅速进阶,跟手心攻略网小编一起来看看2048教科书式通关视频吧。2048教科书式通关视频指的就是玩家过关的方式非常的正规,基本上没有什么失误。......
2048攻略标签
游戏版权归原作者享有,如无意之中侵犯了您的版权,请联系我们,本站将应您的要求删除。所有的游戏都由网友上传提供。
手心网健康游戏提示:抵制不良游戏,拒绝盗版游戏,注意自我保护,谨防受骗上当,适度游戏益脑,沉迷游戏伤身,合理安排时间,享受健康生活
. Some rights reserved 湘ICP备号-2怎样设计一个算法可以高效的完成2048游戏怎样设计一个算法可以高效的完成2048游戏八木彩子?2015-知识宝库
你可能对下面的信息感兴趣Android 带你玩转实现游戏2048 其实2048只是个普通的控件 - 安卓 - 伯乐在线
& Android 带你玩转实现游戏2048 其实2048只是个普通的控件
博主本想踏入游戏开放行业,无奈水太深,不会游泳;于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048、像素鸟、别踩什么来着;今天给大家带来一篇2048的开发篇,别怕不分上下文,或者1、2、3、4,一篇包你能玩happy~虽然我从来没有玩到过2048!!!其实大家也可以当作自定义控件来看~~~
特别说明一下,游戏2048里面的方块各种颜色来源于:http://download.csdn.net/detail/qq/7155467,这个2048的代码中,其他代码,太多,未参考;特此感谢分享;大家也可以下载下,对比学习下;
接下来贴个我们项目的效果图:
ok 看完效果图,我就准备带领大家征服这款游戏了~~~
2、实现分析
贴一张静态图,开始对我们游戏的设计:
可以看到,游戏其实就是一个容器,里面很多个方块,触摸容器,里面的方块的形态会发生变化。那么:
1、容器我们准备自定义ViewGroup ,叫做Game2048L 里面的块块自定义View ,叫做Game2048Item
接下来从简单的开始:
2、Game2048Item
Game2048Item是个View,并且需要哪些属性呢?
首先得有个number,显示数字嘛,然后绘制的时候根据number绘制背景色;还需要呢?嗯,需要正方形边长,再考虑下,这个边长应该Item自己控制么?显然不是的,Game2048Layout 是个n*n的面板,这个n是不确定的,所以Item的边长肯定是Game2048Layout 计算好传入的。这样必须的属性就这两个。
3、Game2048Layout
Game2048Layout是个容器,我们观察下,里面View是个 n*n的排列,我们准备让其继承RelativeLayout ; 这样可以通过设置Item的RIGHT_OF之类的属性进行定位;
我们在onMeasure里面得到Layout的宽和高,然后根据n*n,生成一定数目的Item,为其设置宽和高,放置到Layout中,这样整个游戏的布局就做好了;绘制的细节上:Item间有横向与纵向的间距,所以需要设置这个值,叫做mMargin。然后Item的边长 =
( Layout边长 – (n-1)*mMagin ) /
剩下的就是onTouchEvent里面去判断用户手势了,然后就行各种逻辑操作了~
3、代码之旅
首先来看看我们的Game2048Item
1、Game2048Item
package com.zhy.game2048.
import android.content.C
import android.graphics.C
import android.graphics.C
import android.graphics.P
import android.graphics.Paint.S
import android.graphics.R
import android.util.AttributeS
import android.util.L
import android.view.V
* 2048的每个Item
* @author zhy
public class Game2048Item extends View
* 该View上的数字
private int mN
private String mNumberV
private Paint mP
* 绘制文字的区域
private Rect mB
public Game2048Item(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
mPaint = new Paint();
public Game2048Item(Context context)
this(context, null);
public Game2048Item(Context context, AttributeSet attrs)
this(context, attrs, 0);
public void setNumber(int number)
mNumberVal = mNumber + "";
mPaint.setTextSize(30.0f);
mBound = new Rect();
mPaint.getTextBounds(mNumberVal, 0, mNumberVal.length(), mBound);
invalidate();
public int getNumber()
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
String mBgColor = "";
switch (mNumber)
mBgColor = "#CCC0B3";
mBgColor = "#EEE4DA";
mBgColor = "#EDE0C8";
mBgColor = "#F2B179";// #F2B179
mBgColor = "#F49563";
mBgColor = "#F5794D";
mBgColor = "#F55D37";
mBgColor = "#EEE863";
mBgColor = "#EDB04D";
mBgColor = "#ECB04D";
case 1024:
mBgColor = "#EB9437";
case 2048:
mBgColor = "#EA7821";
mBgColor = "#EA7821";
mPaint.setColor(Color.parseColor(mBgColor));
mPaint.setStyle(Style.FILL);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
if (mNumber != 0)
drawText(canvas);
* 绘制文字
* @param canvas
private void drawText(Canvas canvas)
mPaint.setColor(Color.BLACK);
float x = (getWidth() - mBound.width()) / 2;
float y = getHeight() / 2 + mBound.height() / 2;
canvas.drawText(mNumberVal, x, y, mPaint);
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
package com.zhy.game2048.view;&import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Paint.Style;import android.graphics.Rect;import android.util.AttributeSet;import android.util.Log;import android.view.View;&/** * 2048的每个Item *
* @author zhy *
*/public class Game2048Item extends View{ /**
* 该View上的数字
*/ private int mNumber; private String mNumberVal; private Paint mPaint; /**
* 绘制文字的区域
*/ private Rect mBound;& public Game2048Item(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();& }& public Game2048Item(Context context) {
this(context, null); }& public Game2048Item(Context context, AttributeSet attrs) {
this(context, attrs, 0); }& public void setNumber(int number) {
mNumber = number;
mNumberVal = mNumber + "";
mPaint.setTextSize(30.0f);
mBound = new Rect();
mPaint.getTextBounds(mNumberVal, 0, mNumberVal.length(), mBound);
invalidate(); }
& public int getNumber() {
return mNumber; }& @Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
String mBgColor = "";
switch (mNumber)
mBgColor = "#CCC0B3";
mBgColor = "#EEE4DA";
mBgColor = "#EDE0C8";
mBgColor = "#F2B179";// #F2B179
mBgColor = "#F49563";
mBgColor = "#F5794D";
mBgColor = "#F55D37";
mBgColor = "#EEE863";
mBgColor = "#EDB04D";
mBgColor = "#ECB04D";
case 1024:
mBgColor = "#EB9437";
case 2048:
mBgColor = "#EA7821";
mBgColor = "#EA7821";
mPaint.setColor(Color.parseColor(mBgColor));
mPaint.setStyle(Style.FILL);
canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);&
if (mNumber != 0)
drawText(canvas);& }& /**
* 绘制文字
* @param canvas
*/ private void drawText(Canvas canvas) {
mPaint.setColor(Color.BLACK);
float x = (getWidth() - mBound.width()) / 2;
float y = getHeight() / 2 + mBound.height() / 2;
canvas.drawText(mNumberVal, x, y, mPaint); }&}
很简单,基本就一个onDraw通过number来绘制背景和数字;number通过调用setNumer进行设置;它的宽和高都是固定值,所以我们并不需要自己进行测量~~
2、Game2048Layout
1、成员变量
这就是我们最主要的一个类了,首先我们看看这个类的成员变量,先看看各个成员变量的作用:
* 设置Item的数量n*n;默认为4
private int mColumn = 4;
* 存放所有的Item
private Game2048Item[] mGame2048I
* Item横向与纵向的边距
private int mMargin = 10;
* 面板的padding
private int mP
* 检测用户滑动的手势
private GestureDetector mGestureD
// 用于确认是否需要生成一个新的值
private boolean isMergeHappen =
private boolean isMoveHappen =
* 记录分数
private int mS
123456789101112131415161718192021222324252627282930
* 设置Item的数量n*n;默认为4
*/ private int mColumn = 4; /**
* 存放所有的Item
*/ private Game2048Item[] mGame2048Items;& /**
* Item横向与纵向的边距
*/ private int mMargin = 10; /**
* 面板的padding
*/ private int mPadding; /**
* 检测用户滑动的手势
*/ private GestureDetector mGestureDetector;& // 用于确认是否需要生成一个新的值 private boolean isMergeHappen = true; private boolean isMoveHappen = true;& /**
* 记录分数
*/ private int mScore;
主要的成员变量就这些,直接看注释也比较容易理解~~
了解了成员变量,接下来我们需要在构造方法里面得到一些值和初始化一些变量
2、构造方法
public Game2048Layout(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
mMargin = (int) TypedValue.PLEX_UNIT_DIP,
mMargin, getResources().getDisplayMetrics());
// 设置Layout的内边距,四边一致,设置为四内边距中的最小值
mPadding = min(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
getPaddingBottom());
mGestureDetector = new GestureDetector(context , new MyGestureDetector());
12345678910111213
public Game2048Layout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);&
mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
mMargin, getResources().getDisplayMetrics());
// 设置Layout的内边距,四边一致,设置为四内边距中的最小值
mPadding = min(getPaddingLeft(), getPaddingTop(), getPaddingRight(),
getPaddingBottom());&
mGestureDetector = new GestureDetector(context , new MyGestureDetector());& }
我们在构造方法里面得到Item间的边距(margin)和我们容器的内边距(padding,),这个值应该四边一致,于是我们取四边的最小值;这两个属性可以抽取为自定义的属性;然后初始化了我们的mGestureDetector
有了margin和padding,我们就可以计算我们item的边长了。这个计算过程肯定在onMeasure里面,因为我们需要在onMeasure获取容器的宽和高
3、onMeasure
* 测量Layout的宽和高,以及设置Item的宽和高,这里忽略wrap_content 以宽、高之中的最小值绘制正方形
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获得正方形的边长
int length = Math.min(getMeasuredHeight(), getMeasuredWidth());
// 获得Item的宽度
int childWidth = (length - mPadding * 2 - mMargin * (mColumn - 1))
if (!once)
if (mGame2048Items == null)
mGame2048Items = new Game2048Item[mColumn * mColumn];
// 放置Item
for (int i = 0; i & mGame2048Items. i++)
Game2048Item item = new Game2048Item(getContext());
mGame2048Items[i] =
item.setId(i + 1);
RelativeLayout.LayoutParams lp = new LayoutParams(childWidth,
childWidth);
// 设置横向边距,不是最后一列
if ((i + 1) % mColumn != 0)
lp.rightMargin = mM
// 如果不是第一列
if (i % mColumn != 0)
lp.addRule(RelativeLayout.RIGHT_OF,//
mGame2048Items[i - 1].getId());
// 如果不是第一行,//设置纵向边距,非最后一行
if ((i + 1) & mColumn)
lp.topMargin = mM
lp.addRule(RelativeLayout.BELOW,//
mGame2048Items[i - mColumn].getId());
addView(item, lp);
generateNum();
setMeasuredDimension(length, length);
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
private boolean once;& /**
* 测量Layout的宽和高,以及设置Item的宽和高,这里忽略wrap_content 以宽、高之中的最小值绘制正方形
*/ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// 获得正方形的边长
int length = Math.min(getMeasuredHeight(), getMeasuredWidth());
// 获得Item的宽度
int childWidth = (length - mPadding * 2 - mMargin * (mColumn - 1))
/ mColumn;&
if (!once)
if (mGame2048Items == null)
mGame2048Items = new Game2048Item[mColumn * mColumn];
// 放置Item
for (int i = 0; i & mGame2048Items.length; i++)
Game2048Item item = new Game2048Item(getContext());&
mGame2048Items[i] = item;
item.setId(i + 1);
RelativeLayout.LayoutParams lp = new LayoutParams(childWidth,
childWidth);
// 设置横向边距,不是最后一列
if ((i + 1) % mColumn != 0)
lp.rightMargin = mMargin;
// 如果不是第一列
if (i % mColumn != 0)
lp.addRule(RelativeLayout.RIGHT_OF,//
mGame2048Items[i - 1].getId());
// 如果不是第一行,//设置纵向边距,非最后一行
if ((i + 1) & mColumn)
lp.topMargin = mMargin;
lp.addRule(RelativeLayout.BELOW,//
mGame2048Items[i - mColumn].getId());
addView(item, lp);
generateNum();
once = true;&
setMeasuredDimension(length, length); }
首先设置容器的边长为宽高中的最小值;然后(length – mPadding * 2 – mMargin * (mColumn – 1)) / mC 去计算Item的边长;
拿到以后,根据我们的mColumn初始化我们的Item数组,然后遍历生成Item,设置Item的LayoutParams以及Rule(RIGHT_OF , BELOW),最后添加到我们的容器中;
最后我们通过setMeasuredDimension(length, length);改变我们布局占据的空间;
到此,我们整个面板绘制完成了;
接下来,就是根据用户的手势,去进行游戏逻辑操作了,手势那么肯定是onTouchEvent了:
4、onTouchEvent
public boolean onTouchEvent(MotionEvent event)
mGestureDetector.onTouchEvent(event);
@Override public boolean onTouchEvent(MotionEvent event) {
mGestureDetector.onTouchEvent(event);
return true; }
我们把触摸事件交给了mGestureDetector,我们去看看我们的mGestureDetector,在构造方法中有这么一句:
mGestureDetector = new GestureDetector(context , new MyGestureDetector());
so,我们需要去看看MyGestureDetector:
class MyGestureDetector extends GestureDetector.SimpleOnGestureListener
final int FLING_MIN_DISTANCE = 50;
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
float x = e2.getX() - e1.getX();
float y = e2.getY() - e1.getY();
if (x & FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.RIGHT);
} else if (x & -FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.LEFT);
} else if (y & FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.DOWM);
} else if (y & -FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.UP);
12345678910111213141516171819202122232425262728293031323334353637
class MyGestureDetector extends GestureDetector.SimpleOnGestureListener {&
final int FLING_MIN_DISTANCE = 50;&
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY)
float x = e2.getX() - e1.getX();
float y = e2.getY() - e1.getY();&
if (x & FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.RIGHT);&
} else if (x & -FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.LEFT);&
} else if (y & FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.DOWM);&
} else if (y & -FLING_MIN_DISTANCE
&& Math.abs(velocityX) & Math.abs(velocityY))
action(ACTION.UP);
return true;&
很简单,就是判读用户上、下、左、右滑动;然后去调用action(ACTION)方法;ACTION是个枚举:
* 运动方向的枚举
* @author zhy
private enum ACTION
LEFT, RIGHT, UP, DOWM
12345678910
* 运动方向的枚举
* @author zhy
*/ private enum ACTION {
LEFT, RIGHT, UP, DOWM }
这么看,核心代码都在action方法里面了:
5、根据用户手势重绘Item
看代码前,先考虑下,用户从右向左滑动时,面板应该如何变化;取其中一行,可能性为:
0 0 0 2 -& 2 0 0 0
2 0 4 0 -& 2 4 0 0
2 2 4 0 -& 4 4 0 0
大概就这3中可能;
我们算法是这么做的:
拿2 2 4 0 来说:
1、首先把每行有数字的取出来,临时存储下来,即[ 2, 2, 4 ];
2、然后遍历合并第一个相遇的相同的,即[ 4, 4 ,0 ]
3、然后直接放置到原行,不足补0,即[ 4, 4, 0 ,0 ];
中间还有几个操作:
1、生成一个新的数字,游戏在每次用户滑动时,可能会生成一个数字;我们的生成策略:如果发生移动或者合并,则生成一个数字;
移动的判断,拿原数据,即【 2 ,2,4,0】和我们第一步临时存储的做比较,一一对比(遍历临时表),发现不同,则认为移动了;
合并的判断,在合并的时候会设置合并的标志位为true;
2、加分,如果发生合并,则加分,分值为合并得到的数字,比如 4,4 -& 8 ,即加8分 ; 也只需要在合并的时候进行相加就行了;
介绍完了,来看我们的代码:
* 根据用户运动,整体进行移动合并值等
private void action(ACTION action)
for (int i = 0; i & mC i++)
List&Game2048Item& row = new ArrayList&Game2048Item&();
for (int j = 0; j & mC j++)
// 得到下标
int index = getIndexByAction(action, i, j);
Game2048Item item = mGame2048Items[index];
// 记录不为0的数字
if (item.getNumber() != 0)
row.add(item);
for (int j = 0; j & mColumn && j & row.size(); j++)
int index = getIndexByAction(action, i, j);
Game2048Item item = mGame2048Items[index];
if (item.getNumber() != row.get(j).getNumber())
isMoveHappen =
// 合并相同的
mergeItem(row);
// 设置合并后的值
for (int j = 0; j & mC j++)
int index = getIndexByAction(action, i, j);
if (row.size() & j)
mGame2048Items[index].setNumber(row.get(j).getNumber());
mGame2048Items[index].setNumber(0);
generateNum();
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
* 根据用户运动,整体进行移动合并值等
*/ private void action(ACTION action) {
for (int i = 0; i & mColumn; i++)
List&Game2048Item& row = new ArrayList&Game2048Item&();
for (int j = 0; j & mColumn; j++)
// 得到下标
int index = getIndexByAction(action, i, j);&
Game2048Item item = mGame2048Items[index];
// 记录不为0的数字
if (item.getNumber() != 0)
row.add(item);
for (int j = 0; j & mColumn && j & row.size(); j++)
int index = getIndexByAction(action, i, j);
Game2048Item item = mGame2048Items[index];&
if (item.getNumber() != row.get(j).getNumber())
isMoveHappen = true;
// 合并相同的
mergeItem(row);
// 设置合并后的值
for (int j = 0; j & mColumn; j++)
int index = getIndexByAction(action, i, j);
if (row.size() & j)
mGame2048Items[index].setNumber(row.get(j).getNumber());
mGame2048Items[index].setNumber(0);
generateNum();& }
大体上是两层循环,外层循环代码循环次数,内层有3个for循环;
第一个for循环,对应上述:首先把每行有数字的取出来,临时存储下来,即[ 2, 2, 4 ];
第二个for循环,判断是否发生移动;
// 合并相同的
mergeItem(row); 是去进行合并操作,对应上述:然后遍历合并第一个相遇的相同的,即[ 4, 4 ,0 ];以及加分和设置合并标志位都在方法中;
第三个for循环:设置合并后的值,对应上述:然后直接放置到原行,不足补0,即[ 4, 4, 0 ,0 ];
最后生成数字,方法内部会进行判断游戏是否结束,是否需要生成数字;
那么先看mergeItem的代码:
* 合并相同的Item
* @param row
private void mergeItem(List&Game2048Item& row)
if (row.size() & 2)
for (int j = 0; j & row.size() - 1; j++)
Game2048Item item1 = row.get(j);
Game2048Item item2 = row.get(j + 1);
if (item1.getNumber() == item2.getNumber())
isMergeHappen =
int val = item1.getNumber() + item2.getNumber();
item1.setNumber(val);
if (mGame2048Listener != null)
mGame2048Listener.onScoreChange(mScore);
// 向前移动
for (int k = j + 1; k & row.size() - 1; k++)
row.get(k).setNumber(row.get(k + 1).getNumber());
row.get(row.size() - 1).setNumber(0);
123456789101112131415161718192021222324252627282930313233343536373839404142
* 合并相同的Item
* @param row
*/ private void mergeItem(List&Game2048Item& row) {
if (row.size() & 2)
for (int j = 0; j & row.size() - 1; j++)
Game2048Item item1 = row.get(j);
Game2048Item item2 = row.get(j + 1);&
if (item1.getNumber() == item2.getNumber())
isMergeHappen = true;&
int val = item1.getNumber() + item2.getNumber();
item1.setNumber(val);&
mScore += val;
if (mGame2048Listener != null)
mGame2048Listener.onScoreChange(mScore);
// 向前移动
for (int k = j + 1; k & row.size() - 1; k++)
row.get(k).setNumber(row.get(k + 1).getNumber());
row.get(row.size() - 1).setNumber(0);
也比较简单,循环查找相同的number,发现合并数字,加分;
加分我们设置了一个回调,把分数回调出去:
if (mGame2048Listener != null)
mGame2048Listener.onScoreChange(mScore);
if (mGame2048Listener != null){mGame2048Listener.onScoreChange(mScore);}
最后看我们生成数字的代码:
* 产生一个数字
public void generateNum()
if (checkOver())
Log.e("TAG", "GAME OVER");
if (mGame2048Listener != null)
mGame2048Listener.onGameOver();
if (!isFull())
if (isMoveHappen || isMergeHappen)
Random random = new Random();
int next = random.nextInt(16);
Game2048Item item = mGame2048Items[next];
while (item.getNumber() != 0)
next = random.nextInt(16);
item = mGame2048Items[next];
item.setNumber(Math.random() & 0.75 ? 4 : 2);
isMergeHappen = isMoveHappen =
12345678910111213141516171819202122232425262728293031323334353637
* 产生一个数字
*/ public void generateNum() {&
if (checkOver())
Log.e("TAG", "GAME OVER");
if (mGame2048Listener != null)
mGame2048Listener.onGameOver();
if (!isFull())
if (isMoveHappen || isMergeHappen)
Random random = new Random();
int next = random.nextInt(16);
Game2048Item item = mGame2048Items[next];&
while (item.getNumber() != 0)
next = random.nextInt(16);
item = mGame2048Items[next];
item.setNumber(Math.random() & 0.75 ? 4 : 2);&
isMergeHappen = isMoveHappen = false;
首先判断是否结束,如果结束了,依然是回调出去,得让玩的人知道结束了;
然后判断当然面板是有木有空的格子,如果没有,在判断需要生成新的数字么,需要则随机生成一个新的2或4;
那么如何判断是否结束呢?
首先肯定是没有空格了,然后四个方向上没有相同的数字就结束了:
* 检测当前所有的位置都有数字,且相邻的没有相同的数字
private boolean checkOver()
// 检测是否所有位置都有数字
if (!isFull())
for (int i = 0; i & mC i++)
for (int j = 0; j & mC j++)
int index = i * mColumn +
// 当前的Item
Game2048Item item = mGame2048Items[index];
if ((index + 1) % mColumn != 0)
Log.e("TAG", "RIGHT");
// 右边的Item
Game2048Item itemRight = mGame2048Items[index + 1];
if (item.getNumber() == itemRight.getNumber())
if ((index + mColumn) & mColumn * mColumn)
Log.e("TAG", "DOWN");
Game2048Item itemBottom = mGame2048Items[index + mColumn];
if (item.getNumber() == itemBottom.getNumber())
if (index % mColumn != 0)
Log.e("TAG", "LEFT");
Game2048Item itemLeft = mGame2048Items[index - 1];
if (itemLeft.getNumber() == item.getNumber())
if (index + 1 & mColumn)
Log.e("TAG", "UP");
Game2048Item itemTop = mGame2048Items[index - mColumn];
if (item.getNumber() == itemTop.getNumber())
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
* 检测当前所有的位置都有数字,且相邻的没有相同的数字
*/ private boolean checkOver() {
// 检测是否所有位置都有数字
if (!isFull())
return false;
for (int i = 0; i & mColumn; i++)
for (int j = 0; j & mColumn; j++)
int index = i * mColumn + j;&
// 当前的Item
Game2048Item item = mGame2048Items[index];
if ((index + 1) % mColumn != 0)
Log.e("TAG", "RIGHT");
// 右边的Item
Game2048Item itemRight = mGame2048Items[index + 1];
if (item.getNumber() == itemRight.getNumber())
return false;
if ((index + mColumn) & mColumn * mColumn)
Log.e("TAG", "DOWN");
Game2048Item itemBottom = mGame2048Items[index + mColumn];
if (item.getNumber() == itemBottom.getNumber())
return false;
if (index % mColumn != 0)
Log.e("TAG", "LEFT");
Game2048Item itemLeft = mGame2048Items[index - 1];
if (itemLeft.getNumber() == item.getNumber())
return false;
if (index + 1 & mColumn)
Log.e("TAG", "UP");
Game2048Item itemTop = mGame2048Items[index - mColumn];
if (item.getNumber() == itemTop.getNumber())
return false;
return true;& }
* 是否填满数字
private boolean isFull()
// 检测是否所有位置都有数字
for (int i = 0; i & mGame2048Items. i++)
if (mGame2048Items[i].getNumber() == 0)
1234567891011121314151617
* 是否填满数字
*/ private boolean isFull() {
// 检测是否所有位置都有数字
for (int i = 0; i & mGame2048Items.length; i++)
if (mGame2048Items[i].getNumber() == 0)
return false;
return true; }
到此,我们的代码介绍完毕~~~完成了我们的Game2048Layout ; 接下来看如何使用呢?
写游戏的过程很艰辛,但是用起来,看看什么叫 当成普通的View即可:
1、布局文件:
&RelativeLayout xmlns:android="/apk/res/android"
xmlns:tools="/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent" &
&com.zhy.game2048.view.Game2048Layout
android:id="@+id/id_game2048"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_centerInParent="true"
android:background="#ffffff"
android:padding="10dp" &
&/com.zhy.game2048.view.Game2048Layout&
&LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/id_game2048"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp"
android:background="#EEE4DA"
android:orientation="horizontal" &
android:id="@+id/id_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="4dp"
android:text="Score: 0"
android:textColor="#EA7821"
android:textSize="30sp"
android:textStyle="bold" /&
&/LinearLayout&
&/RelativeLayout&
1234567891011121314151617181920212223242526272829303132333435
&RelativeLayout xmlns:android="/apk/res/android"&&&&xmlns:tools="/tools"&&&&android:layout_width="fill_parent"&&&&android:layout_height="fill_parent" &&&&&&&com.zhy.game2048.view.Game2048Layout&&&&&&&&android:id="@+id/id_game2048"&&&&&&&&android:layout_width="fill_parent"&&&&&&&&android:layout_height="fill_parent"&&&&&&&&android:layout_centerInParent="true"&&&&&&&&android:background="#ffffff"&&&&&&&&android:padding="10dp" &&&&&&/com.zhy.game2048.view.Game2048Layout&&&&&&&LinearLayout&&&&&&&&android:layout_width="wrap_content"&&&&&&&&android:layout_height="wrap_content"&&&&&&&&android:layout_above="@id/id_game2048"&&&&&&&&android:layout_centerHorizontal="true"&&&&&&&&android:layout_marginBottom="20dp"&&&&&&&&android:background="#EEE4DA"&&&&&&&&android:orientation="horizontal" &&&&&&&&&&&TextView&&&&&&&&&&&&android:id="@+id/id_score"&&&&&&&&&&&&android:layout_width="wrap_content"&&&&&&&&&&&&android:layout_height="wrap_content"&&&&&&&&&&&&android:padding="4dp"&&&&&&&&&&&&android:text="Score: 0"&&&&&&&&&&&&android:textColor="#EA7821"&&&&&&&&&&&&android:textSize="30sp"&&&&&&&&&&&&android:textStyle="bold" /&&&&&&/LinearLayout&&&/RelativeLayout&
2、MainActivity
package com.zhy.game2048;
import android.app.A
import android.app.AlertD
import android.content.DialogI
import android.content.DialogInterface.OnClickL
import android.os.B
import android.widget.TextV
import com.zhy.game2048.view.Game2048L
import com.zhy.game2048.view.Game2048Layout.OnGame2048L
public class MainActivity extends Activity implements OnGame2048Listener
private Game2048Layout mGame2048L
private TextView mS
protected void onCreate(Bundle savedInstanceState)
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mScore = (TextView) findViewById(R.id.id_score);
mGame2048Layout = (Game2048Layout) findViewById(R.id.id_game2048);
mGame2048Layout.setOnGame2048Listener(this);
public void onScoreChange(int score)
mScore.setText("SCORE: " + score);
public void onGameOver()
new AlertDialog.Builder(this).setTitle("GAME OVER")
.setMessage("YOU HAVE GOT " + mScore.getText())
.setPositiveButton("RESTART", new OnClickListener()
public void onClick(DialogInterface dialog, int which)
mGame2048Layout.restart();
}).setNegativeButton("EXIT", new OnClickListener()
public void onClick(DialogInterface dialog, int which)
}).show();
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
package com.zhy.game2048;&import android.app.Activity;import android.app.AlertDialog;import android.content.DialogInterface;import android.content.DialogInterface.OnClickListener;import android.os.Bundle;import android.widget.TextView;&import com.zhy.game2048.view.Game2048Layout;import com.zhy.game2048.view.Game2048Layout.OnGame2048Listener;&public class MainActivity extends Activity implements OnGame2048Listener{ private Game2048Layout mGame2048Layout;& private TextView mScore;& @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);&
mScore = (TextView) findViewById(R.id.id_score);
mGame2048Layout = (Game2048Layout) findViewById(R.id.id_game2048);
mGame2048Layout.setOnGame2048Listener(this); }& @Override public void onScoreChange(int score) {
mScore.setText("SCORE: " + score); }& @Override public void onGameOver() {
new AlertDialog.Builder(this).setTitle("GAME OVER")
.setMessage("YOU HAVE GOT " + mScore.getText())
.setPositiveButton("RESTART", new OnClickListener()
public void onClick(DialogInterface dialog, int which)
mGame2048Layout.restart();
}).setNegativeButton("EXIT", new OnClickListener()
public void onClick(DialogInterface dialog, int which)
}).show(); }&}
很简单,代码主要就是设置个接口,当发生加分已经游戏结束时会交给Activity去处理~~~如果喜欢,你可以在一个界面放4个游戏~~~
当然了游戏Item的个数也可以动态设置~~~最后贴一个5*5游戏的截图~~
好了,2048到此结束,拿只笔开始设计,然后根据自定义View的经验去写,相信你可以学会不少东西~~~
并且我们的View是抽取出来的,其实换成图片也很简单~~
今天又看了war3十大经典战役,献上war3版,代码就不贴了,改动也就几行代码,贴个截图,纪念我们曾经的war3~~~:
额,咋都弄成5*5了~大家可以把mColumn改为4~~~
可能感兴趣的话题
关于安卓频道
安卓频道分享Android开发文章,精选工具和安卓相关的行业动态。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线

我要回帖

更多关于 2048游戏算法 的文章

 

随机推荐