博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
贪吃蛇源代码分析
阅读量:7059 次
发布时间:2019-06-28

本文共 5194 字,大约阅读时间需要 17 分钟。

今天已经是农历12月16号了,用这一篇博文给今年的博客画上一个句号吧。

首先,下载一个贪吃蛇的源代码,结构如下:(网上资源很多,我这里就不给出了)

打开AndroidManifest.xml找到应用入口

可以看到入口Activity是Snake,好吧我们先进到Snake.java文件中看看onCreate方法

在onCreate方法中首先是如下两句代码:

//设置为无标题的主题样式requestWindowFeature(Window.FEATURE_NO_TITLE);		setContentView(R.layout.snake_layout);
我们看看贪吃蛇的布局文件吧,继续打开snake_layout.xml

从布局源码和上图可以看出最外面是一个帧布局(层布局)FrameLayout

接下来上面是一个叫做SnakeView的视图

再上面是一个相对布局,该布局中放置了开始按钮和说明文字

最上面是一个绝对布局,该不居中放置了四个ImageButton

这个界面布局很容易理解,唯独里面的com.xmobileapp.Snake.SnakeView是一个自定义View.好吧下面我们来看看这个自定义的视图。

刚进去就发现它继承自TileView,这个貌似没有见过,原来也是一个自定义的View啊,我们先看看这个TileView是个什么吧,回头再看SnakeView类

@Override	public void onDraw(Canvas canvas) {		super.onDraw(canvas);		for (int x = 0; x < mXTileCount; x += 1) {			for (int y = 0; y < mYTileCount; y += 1) {				if (mTileGrid[x][y] > 0) {					canvas.drawBitmap(mTileArray[mTileGrid[x][y]], mXOffset + x							* mTileSize, mYOffset + y * mTileSize, mPaint);				}			}		}	}
可以看到这个TileView继承自View并重写了onDraw方法,猜想应该是画贪吃蛇中的每个方块的。这个疑问暂且留在这里,我们再回到Snake.java中的onCreate方法中。

mSnakeView = (SnakeView) findViewById(R.id.snake);mSnakeView.setTextView((TextView) findViewById(R.id.text));
将界面中的TextView对象注入到了SnakeView类中。

if (savedInstanceState == null) {			mSnakeView.setMode(mSnakeView.READY);		} else {			Bundle map = savedInstanceState.getBundle(ICICLE_KEY);			if (map != null) {				mSnakeView.restoreState(map);			} else {				mSnakeView.setMode(SnakeView.PAUSE);			}		}
如果刚启动的时候saveInstanceState == null 则设置状态为准备就绪,否则执行下面的方法。

先查看Bundle对象的getBundle方法

大概意思是通过一个键返回一个值,其中的ICICLE_KEY是一个常量key

private static String ICICLE_KEY = "snake-view";
下面我们再来看看restoreState方法

public void restoreState(Bundle icicle) {		setMode(PAUSE);		mAppleList = coordArrayToArrayList(icicle.getIntArray("mAppleList"));		mDirection = icicle.getInt("mDirection");		mNextDirection = icicle.getInt("mNextDirection");		mMoveDelay = icicle.getLong("mMoveDelay");		mScore = icicle.getLong("mScore");		mSnakeTrail = coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));	}
现在也看不懂,但是大概能知道这是保存状态的方法。

setMode方法我们就不进去看了,估计也看不懂,这个从方法名上我们猜测是一个设置游戏状态的方法。

下面我们再看看开始游戏的按钮监听函数

case PLAY:			play.setVisibility(View.GONE);			left.setVisibility(View.VISIBLE);			right.setVisibility(View.VISIBLE);			up.setVisibility(View.VISIBLE);			down.setVisibility(View.VISIBLE);			if (mSnakeView.mMode == mSnakeView.READY					| mSnakeView.mMode == mSnakeView.LOSE) {				mSnakeView.initNewGame();				mSnakeView.setMode(mSnakeView.RUNNING);				mSnakeView.update();				updateStatus = new UpdateStatus();				updateStatus.start();				break;			}			if (mSnakeView.mMode == mSnakeView.PAUSE) {				mSnakeView.setMode(mSnakeView.RUNNING);				mSnakeView.update();				break;			}			if (mSnakeView.mDirection != mSnakeView.SOUTH) {				mSnakeView.mNextDirection = mSnakeView.NORTH;				break;			}			break;

上面的几句是游戏开始的时候上面的四个方向按钮显示,开始按钮隐藏。

游戏中有如下几种状态在SnakeView类中定义

public static final int PAUSE = 0; //暂停	public static final int READY = 1;  //准备开始	public static final int RUNNING = 2;  //运行状态	public static final int LOSE = 3;  //游戏结束,也就是输了
如果刚进入游戏,然后开始游戏就执行如下几句代码

mSnakeView.initNewGame();mSnakeView.setMode(mSnakeView.RUNNING);mSnakeView.update();updateStatus = new UpdateStatus();updateStatus.start();
进入initNewGam()方法看看

void initNewGame() {		mSnakeTrail.clear();		mAppleList.clear();		mSnakeTrail.add(new Coordinate(7, 7));		mSnakeTrail.add(new Coordinate(6, 7));		mSnakeTrail.add(new Coordinate(5, 7));		mSnakeTrail.add(new Coordinate(4, 7));		mSnakeTrail.add(new Coordinate(3, 7));		mSnakeTrail.add(new Coordinate(2, 7));		mNextDirection = NORTH;		addRandomApple();		addRandomApple();		mMoveDelay = 600;		mScore = 0;	}
其他的参数不用管,我们现在可以明白了,里面的Coordinate其实就是贪吃蛇游戏开始的时候的小方块,在这里创建了6个小方块

private class Coordinate {		public int x;		public int y;		public Coordinate(int newX, int newY) {			x = newX;			y = newY;		}		public boolean equals(Coordinate other) {			if (x == other.x && y == other.y) {				return true;			}			return false;		}		@Override		public String toString() {			return "Coordinate: [" + x + "," + y + "]";		}	}
再看看update方法

public void update() {		if (mMode == RUNNING) {			long now = System.currentTimeMillis();			if (now - mLastMove > mMoveDelay) {				clearTiles();				updateWalls();				updateSnake();				updateApples();				mLastMove = now;			}			mRedrawHandler.sleep(mMoveDelay);		}	}
明白了,我们可以调节mMoveDelay控制贪吃蛇移动的速度,详细控制就不看了,改变坐标位置就可以实现了。

再来看看这两句代码的作用

updateStatus = new UpdateStatus();updateStatus.start();
点进去一看,原来这是一个线程,用来监听游戏是否结束,如果结束则通过Handle将控制方向按钮隐藏,将开始游戏按钮显示。

接下来我们看看前后左右四个按钮是怎么控制贪吃蛇的方向的。由于四个方向原理一样,我们就看LEFT吧

case LEFT:			if (mSnakeView.mDirection != mSnakeView.EAST) {				mSnakeView.mNextDirection = mSnakeView.WEST;			}			break;
上面代码的意思是,假如说现在正在向右移动则我们按向左的按钮无效,如果不是向右移动则按向右按钮改变方向。

这里它用到了两个变量一个是当前的方向mDirection另一个是下一次刷新时候的方向(也就是改变的方向)mNextDirection.可以在updateSnake方法中看到实际上在下次刷新的时候会将mNextDirection的值赋给mDirection。

通过上面的分析,对基本的结构和原理有了一个认识,下面我们来具体看一下各个类的作用及实现过程。

这部分分析发现有人已经做过,就不重复劳动了:

代码运行如下:

转载于:https://www.cnblogs.com/lanzhi/p/6469247.html

你可能感兴趣的文章
三星2610打印机故障INTERNAL ERROR - Incomplete Session by time out
查看>>
马哥2016全新Linux+Python高端运维班第五周作业
查看>>
thinkphp 跨模块调用配置文件信息
查看>>
nohup命令在后台自动执行程序
查看>>
MAVEN项目后 jar包无法发布到eclipse的web服务器
查看>>
选择结构与循环结构
查看>>
Linux系统生成随机密码的10种方法
查看>>
puppet初体验
查看>>
oracle安装前环境检查
查看>>
ansible出错
查看>>
linux内核中的信号机制--一个简单的例子
查看>>
【Java】File.createTempFile创建临时文件
查看>>
ldap bdb_db_open 错误解决办法
查看>>
根据菜单查找构建的窗体、流程、报表
查看>>
判断某年是否是闰年
查看>>
初探 C++ 标准库(二十六)
查看>>
安装SP3后不能进入系统的办法
查看>>
20150905日课程作业(计划任务mail,at,cron,)
查看>>
shell训练营Day15
查看>>
MySQL常用语句命令
查看>>