Android游戏开发入门: 贪吃蛇 源代码分析
贪吃蛇是一款足够经典的游戏。它的经典,在于用户操作的简单,在于技术实现的简介,在于他的经久不衰。
这里的贪吃蛇的Android实现,是SDK Samples中的开源例程。可能各位都有看过~界面如下图啦~
作为一个刚入门或者还没入门的新手,着实花了我一些力气来理解这段代码。
对于各种不懂的地方,慢慢查询资料,对于新的方法,通过修改代码尝试效果。到现在终于能算个一知半解。
在代码中,对于自己有所收获的地方,我都做了相应的注释。
回过头来,觉得从这段代码中,能学到不少东西~~
包括android应用的基本架构,他的面向对象的思想,以及代码的简洁明了。
于是,我想到,何不将这些东西分享出来,如果碰巧对感兴趣的朋友们有搜帮助,那就更好了~
好了,闲话不说~代码和注释如下(处于对源码的敬意,原本的英文注释部分都没有删去~大家可以配合理解):
PS:最近我正在写自己的“贪吃蛇”,说事贪吃蛇,其实完全颠覆了这个经典版本的设计理念和操作方式。具体细节先卖一个关子,作品准备参加这次第二届大学生android应用开发大赛。
Snake工程中,总共有三个文件: *TileView是基于Android的View类实现的方块图类,用来支撑上层类的调用,绘制方块图的显示界面。通过这些代码,能打之了解如何 扩展View,实现特色的界面效果。 *SnakeView调用了TileView,实现了游戏逻辑 和 具体的显示。 *Snake为主Activity类。
建议大家按照上面的顺序看三个文件,可能逻辑上更舒服一点~~
下面贴上代码和注释。
PS: 调试版本为android2.2。 其他版本应该也没问题吧,不过得用虚拟机。因为它是上下左右按键操作,现在大多数android机是没有方向键的吧。
TileView.java
- package com.example.android.snake;
- import android.content.Context;
- import android.content.res.TypedArray;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Paint;
- import android.graphics.drawable.Drawable;
- import android.util.AttributeSet;
- import android.view.View;
- /**
- * TileView: a View-variant designed for handling arrays of "icons" or other
- * drawables.
- *
- */
- public class TileView extends View {
- /**
- * Parameters controlling the size of the tiles and their range within view.
- * Width/Height are in pixels, and Drawables will be scaled to fit to these
- * dimensions. X/Y Tile Counts are the number of tiles that will be drawn.
- */
- protected static int mTileSize; //每个tile的边长的像素数量
- protected static int mXTileCount; //屏幕内能容纳的 X方向上方块的总数量
- protected static int mYTileCount;//屏幕内能容纳的 Y方向上方块的总数量
- private static int mXOffset; //原点坐标,按pixel计。
- private static int mYOffset;
- /**
- * A hash that maps integer handles specified by the subclasser to the
- * drawable that will be used for that reference
- * 存储着不同种类的bitmap图。通过resetTiles,loadTile,将游戏中的方块加载到这个数组。
- * 可以理解为 砖块字典
- */
- private Bitmap[] mTileArray;
- /**
- * A two-dimensional array of integers in which the number represents the
- * index of the tile that should be drawn at that locations
- * 存储整个界面内每个tile位置应该绘制的tile。
- * 可看作是我们直接操作的画布。
- * 通过setTile、clearTile 进行图形显示的修改操作。
- *
- */
- private int[][] mTileGrid;
- //画笔,canvas的图形绘制,需要画笔Paint实现。
- private final Paint mPaint = new Paint();
- public TileView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- //使用TypedArray,获取在attrs.xml中为TileView定义的新属性tileSize 。参考: http://weizhulin.blog.51cto.com/1556324/311453
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
- mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
- a.recycle();
- }
- public TileView(Context context, AttributeSet attrs) {
- super(context, attrs);
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
- mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
- a.recycle();
- }
- /**
- * Rests the internal array of Bitmaps used for drawing tiles, and
- * sets the maximum index of tiles to be inserted
- * 重置清零mTileArray,在游戏初始的时候使用。
- * 即清空砖块字典
- * @param tilecount
- */
- public void resetTiles(int tilecount) {
- mTileArray = new Bitmap[tilecount];
- }
- /*
- * 当改变屏幕大小尺寸时,同时修改tile的相关计数指标。
- */
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- mXTileCount = (int) Math.floor(w / mTileSize);
- mYTileCount = (int) Math.floor(h / mTileSize);
- //mXOffset mYOffset是绘图的起点坐标。
- mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
- mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
- mTileGrid = new int[mXTileCount][mYTileCount];
- clearTiles();
- }
- /**
- * Function to set the specified Drawable as the tile for a particular
- * integer key.
- * 加载具体的砖块图片 到 砖块字典。
- * 即将对应的砖块的图片 对应的加载到 mTileArray数组中
- * @param key
- * @param tile
- */
- public void loadTile(int key, Drawable tile) {
- //这里做了一个 Drawable 到 bitmap 的转换。由于外部程序使用的时候是直接读取资源文件中的图片,
- //是drawable格式,而我们的数组是bitmap格式,方便最终的绘制。所以,需要进行一次到 bitmap的转换。
- Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- tile.setBounds(0, 0, mTileSize, mTileSize);
- tile.draw(canvas);
- mTileArray[key] = bitmap;
- }
- /**
- * Used to indicate that a particular tile (set with loadTile and referenced
- * by an integer) should be drawn at the given x/y coordinates during the
- * next invalidate/draw cycle.
- * 在相应的坐标位置绘制相应的砖块
- * 记得哦,mTileGrid其实就是我们直接操作的画布。
- * @param tileindex
- * @param x
- * @param y
- */
- public void setTile(int tileindex, int x, int y) {
- mTileGrid[x][y] = tileindex;
- }
- /**
- * Resets all tiles to 0 (empty)
- * 清空图形显示。
- * 用以更新画面。
- * 调用了绘图的setTile()。
- */
- public void clearTiles() {
- for (int x = 0; x < mXTileCount; x++) {
- for (int y = 0; y < mYTileCount; y++) {
- setTile(0, x, y);
- }
- }
- }
- /*
- * 将我们直接操作的画布绘制到手机界面上!
- * @see android.view.View#onDraw(android.graphics.Canvas)
- */
- @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);
- }
- }
- }
- }
- }