贪吃蛇源代码分析
来源:互联网 发布:电视网络接收器 编辑:程序博客网 时间:2024/04/28 21:20
今天已经是农历12月16号了,用这一篇博文给今年的博客画上一个句号吧。
首先,下载一个贪吃蛇的源代码,结构如下:(网上资源很多,我这里就不给出了)
打开AndroidManifest.xml找到应用入口
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.xmobileapp.Snake" android:versionName="1.0" android:versionCode="1"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".Snake" android:label="贪吃蛇" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="3" /></manifest>可以看到入口Activity是Snake,好吧我们先进到Snake.java文件中看看onCreate方法
在onCreate方法中首先是如下两句代码:
//设置为无标题的主题样式requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.snake_layout);我们看看贪吃蛇的布局文件吧,继续打开snake_layout.xml
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"><com.xmobileapp.Snake.SnakeView android:id="@+id/snake"android:layout_width="fill_parent" android:layout_height="fill_parent" tileSize="12" android:background="@color/teneight"/><RelativeLayoutandroid:layout_width="fill_parent"android:layout_height="fill_parent" ><TextView android:id="@+id/text"android:visibility="visible"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_centerInParent="true"android:gravity="center_horizontal"android:textColor="#FF0033"android:textSize="24sp"/> <Button android:id="@+id/play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_marginTop="10px" android:gravity="center_horizontal" android:text="点击这里开始哦"/></RelativeLayout><AbsoluteLayout android:layout_width="fill_parent"android:layout_height="fill_parent"><ImageButtonandroid:id="@+id/left" android:layout_width="100px" android:layout_height="100px" style="?android:attr/buttonStyleSmall" android:src="@drawable/left" android:layout_x="75px" android:layout_y="100px"/> <ImageButton android:id="@+id/right" android:layout_width="100px" android:layout_height="100px" style="?android:attr/buttonStyleSmall" android:src="@drawable/right" android:layout_x="175px" android:layout_y="100px"/><ImageButtonandroid:id="@+id/up" android:layout_width="100px" android:layout_height="100px" style="?android:attr/buttonStyleSmall" android:src="@drawable/up" android:layout_x="125px" android:layout_y="50px"/> <ImageButton android:id="@+id/down" android:layout_width="100px" android:layout_height="100px" style="?android:attr/buttonStyleSmall" android:src="@drawable/down" android:layout_x="125px" android:layout_y="150px"/> </AbsoluteLayout></FrameLayout>
从布局源码和上图可以看出最外面是一个帧布局(层布局)FrameLayout
接下来上面是一个叫做SnakeView的视图
再上面是一个相对布局,该布局中放置了开始按钮和说明文字
最上面是一个绝对布局,该不居中放置了四个ImageButton
这个界面布局很容易理解,唯独里面的com.xmobileapp.Snake.SnakeView是一个自定义View.好吧下面我们来看看这个自定义的视图。
刚进去就发现它继承自TileView,这个貌似没有见过,原来也是一个自定义的View啊,我们先看看这个TileView是个什么吧,回头再看SnakeView类
@Overridepublic 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方法http://developer.android.com/reference/android/os/Bundle.html
大概意思是通过一个键返回一个值,其中的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;}@Overridepublic 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。
通过上面的分析,对基本的结构和原理有了一个认识,下面我们来具体看一下各个类的作用及实现过程。
这部分分析发现有人已经做过,就不重复劳动了:http://blog.csdn.net/biaobiaoqi/article/details/6618313
代码运行如下:
- 贪吃蛇源代码分析
- 贪吃蛇源代码
- 贪吃蛇源代码
- opengl贪吃蛇源代码
- python贪吃蛇源代码
- C++贪吃蛇源代码
- MFC贪吃蛇+源代码
- java贪吃蛇源代码
- 贪吃蛇源代码
- C++贪吃蛇源代码
- C++贪吃蛇源代码
- java贪吃蛇源代码
- 贪吃蛇java源代码
- 贪吃蛇源代码
- 贪吃蛇java源代码
- 贪吃蛇js源代码
- android游戏开发入门: 贪吃蛇 源代码分析
- android游戏开发入门: 贪吃蛇 源代码分析
- 随风而逝的青春
- 如何修改AOSP以加入自己的设备,应用,工具等
- memcache和memcached的区别
- ubuntu 开机黑屏处理办法
- 我对面向对象思想的感觉。。。。
- 贪吃蛇源代码分析
- 什么是“门”
- 图像分割之 Efficient Graph-Based Image Segmentation
- Linux修改安装时创建的分区名称
- Red Hat 9.0安装proftpd
- iOS6和iOS7代码的适配(5)——popOver
- 梦开始的地方
- tomcat通过conf-Catalina-localhost目录发布项目详解
- iOS中arc的设置与使用