Android游戏开发入门: 贪吃蛇 源代码分析

贪吃蛇是一款足够经典的游戏。它的经典,在于用户操作的简单,在于技术实现的简介,在于他的经久不衰。

这里的贪吃蛇的Android实现,是SDK Samples中的开源例程。可能各位都有看过~界面如下图啦~

Android游戏开发入门: 贪吃蛇 源代码分析

作为一个刚入门或者还没入门的新手,着实花了我一些力气来理解这段代码。

对于各种不懂的地方,慢慢查询资料,对于新的方法,通过修改代码尝试效果。到现在终于能算个一知半解。

在代码中,对于自己有所收获的地方,我都做了相应的注释。

回过头来,觉得从这段代码中,能学到不少东西~~

包括android应用的基本架构,他的面向对象的思想,以及代码的简洁明了。

于是,我想到,何不将这些东西分享出来,如果碰巧对感兴趣的朋友们有搜帮助,那就更好了~

好了,闲话不说~代码和注释如下(处于对源码的敬意,原本的英文注释部分都没有删去~大家可以配合理解):

PS:最近我正在写自己的“贪吃蛇”,说事贪吃蛇,其实完全颠覆了这个经典版本的设计理念和操作方式。具体细节先卖一个关子,作品准备参加这次第二届大学生android应用开发大赛。

Snake工程中,总共有三个文件: *TileView是基于Android的View类实现的方块图类,用来支撑上层类的调用,绘制方块图的显示界面。通过这些代码,能打之了解如何 扩展View,实现特色的界面效果。 *SnakeView调用了TileView,实现了游戏逻辑 和 具体的显示。 *Snake为主Activity类。

建议大家按照上面的顺序看三个文件,可能逻辑上更舒服一点~~

下面贴上代码和注释。

PS:  调试版本为android2.2。 其他版本应该也没问题吧,不过得用虚拟机。因为它是上下左右按键操作,现在大多数android机是没有方向键的吧。

TileView.java

  1. package com.example.android.snake;  
  2.   
  3. import android.content.Context;  
  4. import android.content.res.TypedArray;  
  5. import android.graphics.Bitmap;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Paint;  
  8. import android.graphics.drawable.Drawable;  
  9. import android.util.AttributeSet;  
  10. import android.view.View;  
  11.   
  12.   
  13. /** 
  14.  * TileView: a View-variant designed for handling arrays of "icons" or other 
  15.  * drawables. 
  16.  *  
  17.  */  
  18.   
  19. public class TileView extends View {  
  20.   
  21.     /** 
  22.      * Parameters controlling the size of the tiles and their range within view. 
  23.      * Width/Height are in pixels, and Drawables will be scaled to fit to these 
  24.      * dimensions. X/Y Tile Counts are the number of tiles that will be drawn. 
  25.      */  
  26.   
  27.     protected static int mTileSize; //每个tile的边长的像素数量   
  28.   
  29.     protected static int mXTileCount; //屏幕内能容纳的 X方向上方块的总数量   
  30.     protected static int mYTileCount;//屏幕内能容纳的 Y方向上方块的总数量   
  31.   
  32.     private static int mXOffset; //原点坐标,按pixel计。   
  33.     private static int mYOffset;  
  34.   
  35.   
  36.     /** 
  37.      * A hash that maps integer handles specified by the subclasser to the 
  38.      * drawable that will be used for that reference 
  39.      * 存储着不同种类的bitmap图。通过resetTiles,loadTile,将游戏中的方块加载到这个数组。 
  40.      * 可以理解为 砖块字典 
  41.      */  
  42.     private Bitmap[] mTileArray;      
  43.   
  44.     /** 
  45.      * A two-dimensional array of integers in which the number represents the 
  46.      * index of the tile that should be drawn at that locations 
  47.      * 存储整个界面内每个tile位置应该绘制的tile。 
  48.      * 可看作是我们直接操作的画布。 
  49.      * 通过setTile、clearTile 进行图形显示的修改操作。  
  50.      *  
  51.      */  
  52.     private int[][] mTileGrid;   
  53.   
  54.     //画笔,canvas的图形绘制,需要画笔Paint实现。   
  55.     private final Paint mPaint = new Paint();  
  56.   
  57.       
  58.     public TileView(Context context, AttributeSet attrs, int defStyle) {  
  59.         super(context, attrs, defStyle);  
  60.         //使用TypedArray,获取在attrs.xml中为TileView定义的新属性tileSize 。参考: http://weizhulin.blog.51cto.com/1556324/311453   
  61.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);  
  62.         mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);  
  63.         a.recycle();  
  64.     }  
  65.   
  66.     public TileView(Context context, AttributeSet attrs) {  
  67.         super(context, attrs);  
  68.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);  
  69.         mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);  
  70.         a.recycle();  
  71.     }  
  72.   
  73.       
  74.       
  75.     /** 
  76.      * Rests the internal array of Bitmaps used for drawing tiles, and 
  77.      * sets the maximum index of tiles to be inserted 
  78.      * 重置清零mTileArray,在游戏初始的时候使用。 
  79.      * 即清空砖块字典 
  80.      * @param tilecount 
  81.      */  
  82.     public void resetTiles(int tilecount) {  
  83.         mTileArray = new Bitmap[tilecount];  
  84.     }  
  85.   
  86.       
  87.     /* 
  88.      * 当改变屏幕大小尺寸时,同时修改tile的相关计数指标。 
  89.      */  
  90.       
  91.     @Override  
  92.     protected void onSizeChanged(int w, int h, int oldw, int oldh) {  
  93.         mXTileCount = (int) Math.floor(w / mTileSize);  
  94.         mYTileCount = (int) Math.floor(h / mTileSize);  
  95.   
  96.         //mXOffset mYOffset是绘图的起点坐标。   
  97.         mXOffset = ((w - (mTileSize * mXTileCount)) / 2);  
  98.         mYOffset = ((h - (mTileSize * mYTileCount)) / 2);  
  99.   
  100.         mTileGrid = new int[mXTileCount][mYTileCount];  
  101.         clearTiles();  
  102.     }  
  103.   
  104.       
  105.     /** 
  106.      * Function to set the specified Drawable as the tile for a particular 
  107.      * integer key. 
  108.      * 加载具体的砖块图片 到 砖块字典。 
  109.      * 即将对应的砖块的图片 对应的加载到 mTileArray数组中 
  110.      * @param key 
  111.      * @param tile 
  112.      */  
  113.     public void loadTile(int key, Drawable tile) {  
  114.         //这里做了一个 Drawable 到 bitmap 的转换。由于外部程序使用的时候是直接读取资源文件中的图片,   
  115.         //是drawable格式,而我们的数组是bitmap格式,方便最终的绘制。所以,需要进行一次到 bitmap的转换。   
  116.         Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);  
  117.         Canvas canvas = new Canvas(bitmap);  
  118.         tile.setBounds(00, mTileSize, mTileSize);  
  119.         tile.draw(canvas);  
  120.           
  121.         mTileArray[key] = bitmap;  
  122.     }  
  123.   
  124.     /** 
  125.      * Used to indicate that a particular tile (set with loadTile and referenced 
  126.      * by an integer) should be drawn at the given x/y coordinates during the 
  127.      * next invalidate/draw cycle. 
  128.      * 在相应的坐标位置绘制相应的砖块 
  129.      * 记得哦,mTileGrid其实就是我们直接操作的画布。 
  130.      * @param tileindex 
  131.      * @param x 
  132.      * @param y 
  133.      */  
  134.     public void setTile(int tileindex, int x, int y) {  
  135.         mTileGrid[x][y] = tileindex;  
  136.     }  
  137.   
  138.     /** 
  139.      * Resets all tiles to 0 (empty) 
  140.      * 清空图形显示。 
  141.      * 用以更新画面。 
  142.      * 调用了绘图的setTile()。 
  143.      */  
  144.     public void clearTiles() {  
  145.         for (int x = 0; x < mXTileCount; x++) {  
  146.             for (int y = 0; y < mYTileCount; y++) {  
  147.                 setTile(0, x, y);  
  148.             }  
  149.         }  
  150.     }  
  151.   
  152. /* 
  153.  * 将我们直接操作的画布绘制到手机界面上! 
  154.  * @see android.view.View#onDraw(android.graphics.Canvas) 
  155.  */  
  156.     @Override  
  157.     public void onDraw(Canvas canvas) {  
  158.         super.onDraw(canvas);  
  159.         for (int x = 0; x < mXTileCount; x += 1) {  
  160.             for (int y = 0; y < mYTileCount; y += 1) {  
  161.                 if (mTileGrid[x][y] > 0) {  
  162.                     canvas.drawBitmap(mTileArray[mTileGrid[x][y]],   
  163.                             mXOffset + x * mTileSize,  
  164.                             mYOffset + y * mTileSize,  
  165.                             mPaint);  
  166.                 }  
  167.             }  
  168.         }  
  169.     }  
  170.   
  171. }  

相关推荐