作为一个刚入门或者还没入门的新手,着实花了我一些力气来理解这段代码。
对于各种不懂的地方,慢慢查询资料,对于新的方法,通过修改代码尝试效果。到现在终于能算个一知半解。
在代码中,对于自己有所收获的地方,我都做了相应的注释。
回过头来,觉得从这段代码中,能学到不少东西~~
包括Android应用的基本架构,他的面向对象的思想,以及代码的简洁明了。
于是,我想到,何不将这些东西分享出来,如果碰巧对感兴趣的朋友们有搜帮助,那就更好了~
好了,闲话不说~代码和注释如下(处于对源码的敬意,原本的英文注释部分都没有删去~大家可以配合理解):
PS:最近我正在写自己的“贪吃蛇”,说事贪吃蛇,其实完全颠覆了这个经典版本的设计理念和操作方式。具体细节先卖一个关子,作品准备参加这次第二届大学生Android应用开发大赛。
Snake工程中,总共有三个文件: *TileView是基于Android的View类实现的方块图类,用来支撑上层类的调用,绘制方块图的显示界面。通过这些代码,能打之了解如何 扩展View,实现特色的界面效果。 *SnakeView调用了TileView,实现了游戏逻辑 和 具体的显示。 *Snake为主Activity类。
建议大家按照上面的顺序看三个文件,可能逻辑上更舒服一点~~
下面贴上代码和注释。
PS: 调试版本为Android2.2。 其他版本应该也没问题吧,不过得用虚拟机。因为它是上下左右按键操作,现在大多数android机是没有方向键的吧。
1: package com.example.Android.snake;
2: import Android.content.Context;
3: import Android.content.res.TypedArray;
4: import Android.graphics.Bitmap;
5: import Android.graphics.Canvas;
6: import Android.graphics.Paint;
7: import Android.graphics.drawable.Drawable;
8: import Android.util.AttributeSet;
9: import Android.view.View;
10: /**
11: * TileView: a View-variant designed for handling arrays of "icons" or other
12: * drawables.
13: *
14: */
15: public class TileView extends View {
16: /**
17: * Parameters controlling the size of the tiles and their range within view.
18: * Width/Height are in pixels, and Drawables will be scaled to fit to these
19: * dimensions. X/Y Tile Counts are the number of tiles that will be drawn.
20: */
21: protected static int mTileSize; //每个tile的边长的像素数量
22: protected static int mXTileCount; //屏幕内能容纳的 X方向上方块的总数量
23: protected static int mYTileCount;//屏幕内能容纳的 Y方向上方块的总数量
24: private static int mXOffset; //原点坐标,按pixel计。
25: private static int mYOffset;
26: /**
27: * A hash that maps integer handles specified by the subclasser to the
28: * drawable that will be used for that reference
29: * 存储着不同种类的bitmap图。通过resetTiles,loadTile,将游戏中的方块加载到这个数组。
30: * 可以理解为 砖块字典
31: */
32: private Bitmap[] mTileArray;
33: /**
34: * A two-dimensional array of integers in which the number represents the
35: * index of the tile that should be drawn at that locations
36: * 存储整个界面内每个tile位置应该绘制的tile。
37: * 可看作是我们直接操作的画布。
38: * 通过setTile、clearTile 进行图形显示的修改操作。
39: *
40: */
41: private int[][] mTileGrid;
42: //画笔,canvas的图形绘制,需要画笔Paint实现。
43: private final Paint mPaint = new Paint();
44: public TileView(Context context, AttributeSet attrs, int defStyle) {
45: super(context, attrs, defStyle);
46: //使用TypedArray,获取在attrs.xml中为TileView定义的新属性tileSize 。参考: http://weizhulin.blog.51cto.com/1556324/311453
47: TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
48: mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
49: a.recycle();
50: }
51: public TileView(Context context, AttributeSet attrs) {
52: super(context, attrs);
53: TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
54: mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
55: a.recycle();
56: }
57: /**
58: * Rests the internal array of Bitmaps used for drawing tiles, and
59: * sets the maximum index of tiles to be inserted
60: * 重置清零mTileArray,在游戏初始的时候使用。
61: * 即清空砖块字典
62: * @param tilecount
63: */
64: public void resetTiles(int tilecount) {
65: mTileArray = new Bitmap[tilecount];
66: }
67: /*
68: * 当改变屏幕大小尺寸时,同时修改tile的相关计数指标。
69: */
70: @Override
71: protected void onSizeChanged(int w, int h, int oldw, int oldh) {
72: mXTileCount = (int) Math.floor(w / mTileSize);
73: mYTileCount = (int) Math.floor(h / mTileSize);
74: //mXOffset mYOffset是绘图的起点坐标。
75: mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
76: mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
77: mTileGrid = new int[mXTileCount][mYTileCount];
78: clearTiles();
79: }
80: /**
81: * Function to set the specified Drawable as the tile for a particular
82: * integer key.
83: * 加载具体的砖块图片 到 砖块字典。
84: * 即将对应的砖块的图片 对应的加载到 mTileArray数组中
85: * @param key
86: * @param tile
87: */
88: public void loadTile(int key, Drawable tile) {
89: //这里做了一个 Drawable 到 bitmap 的转换。由于外部程序使用的时候是直接读取资源文件中的图片,
90: //是drawable格式,而我们的数组是bitmap格式,方便最终的绘制。所以,需要进行一次到 bitmap的转换。
91: Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
92: Canvas canvas = new Canvas(bitmap);
93: tile.setBounds(0, 0, mTileSize, mTileSize);
94: tile.draw(canvas);
95: mTileArray[key] = bitmap;
96: }
97: /**
98: * Used to indicate that a particular tile (set with loadTile and referenced
99: * by an integer) should be drawn at the given x/y coordinates during the
100: * next invalidate/draw cycle.
101: * 在相应的坐标位置绘制相应的砖块
102: * 记得哦,mTileGrid其实就是我们直接操作的画布。
103: * @param tileindex
104: * @param x
105: * @param y
106: */
107: public void setTile(int tileindex, int x, int y) {
108: mTileGrid[x][y] = tileindex;
109: }
110: /**
111: * Resets all tiles to 0 (empty)
112: * 清空图形显示。
113: * 用以更新画面。
114: * 调用了绘图的setTile()。
115: */
116: public void clearTiles() {
117: for (int x = 0; x < mXTileCount; x++) {
118: for (int y = 0; y < mYTileCount; y++) {
119: setTile(0, x, y);
120: }
121: }
122: }
123: /*
124: * 将我们直接操作的画布绘制到手机界面上!
125: * @see Android.view.View#onDraw(android.graphics.Canvas)
126: */
127: @Override
128: public void onDraw(Canvas canvas) {
129: super.onDraw(canvas);
130: for (int x = 0; x < mXTileCount; x += 1) {
131: for (int y = 0; y < mYTileCount; y += 1) {
132: if (mTileGrid[x][y] > 0) {
133: canvas.drawBitmap(mTileArray[mTileGrid[x][y]],
134: mXOffset + x * mTileSize,
135: mYOffset + y * mTileSize,
136: mPaint);
137: }
138: }
139: }
140: }
141: }
142:
SnakeView.java
: package com.example.Android.snake;
2: import Android.app.Activity;
3: import Android.os.Bundle;
4: import Android.view.Window;
5: import Android.widget.TextView;
6: /**
7: * Snake: a simple game that everyone can enjoy.
8: * This is an implementation of the classic Game "Snake", in which you control a
9: * serpent roaming around the garden looking for apples. Be careful, though,
10: * because when you catch one, not only will you become longer, but you'll move
11: * faster. Running into yourself or the walls will end the game.
12: */
13: public class Snake extends Activity {
14: private SnakeView mSnakeView;
15: private static String ICICLE_KEY = "snake-view";
16: /**
17: * Called when Activity is first created. Turns off the title bar, sets up
18: * the content views, and fires up the SnakeView.
19: *
20: */
21: @Override
22: public void onCreate(Bundle savedInstanceState) {
23: super.onCreate(savedInstanceState);
24: setContentView(R.layout.snake_layout);
25: mSnakeView = (SnakeView) findViewById(R.id.snake);
26: mSnakeView.setTextView((TextView) findViewById(R.id.text));
27: if (savedInstanceState == null) {
28: // We were just launched -- set up a new game
29: mSnakeView.setMode(SnakeView.READY);
30: } else {
31: // We are being restored
32: Bundle map = savedInstanceState.getBundle(ICICLE_KEY);
33: if (map != null) {
34: mSnakeView.restoreState(map);
35: } else {
36: mSnakeView.setMode(SnakeView.PAUSE);
37: }
38: }
39: }
40: @Override
41: protected void onPause() {
42: super.onPause();
43: // Pause the game along with the activity
44: mSnakeView.setMode(SnakeView.PAUSE);
45: }
46: @Override
47: public void onSaveInstanceState(Bundle outState) {
48: //Store the game state
49: outState.putBundle(ICICLE_KEY, mSnakeView.saveState());
50: }
51: }