——/android-sdk-windows/samples/android-7/Snake
首届 Google 暑期大学生博客分享大赛——2010 Andriod 篇
Snake源码由三部分组成:Snake.java,SnakeView.java,TileView.java。
1. Snake.java
Snake.java是整个整个贪吃蛇游戏的主框架;主要负责程序界面的初始化,游戏的初始化及负责游戏暂停或载入游戏的状态。
a.界面初始化
setContentView(R.layout.snake_layout);
mSnakeView = (SnakeView) findViewById(R.id.snake);
mSnakeView.setTextView((TextView) findViewById(R.id.text));
/** R.layout.snake_layout 指向的snake_layout.xml是游戏的UI设定,在FrameLayout中包含了两个元素:com.example.android.snake.SnakeView(这是个画布);TextView(用来显示文字)。*/
b.游戏初始化及载入游戏状态
if(savedInstanceState == null) {
mSnakeView.setMode(SnakeView.READY); // 设置新游戏
} else {
//读取状态
Bundle map = savedInstanceState.getBundle(ICICLE_KEY);
if (map != null) {
mSnakeView.restoreState(map); //载入状态
} else {
mSnakeView.setMode(SnakeView.PAUSE); //暂停
}
}
}
2. TiltView.java
TiltView的基类是View,包含了贪吃蛇游戏画面的各个设定参数,主要负责绘制游戏画面。
protected static int mTileSize;//方格的边长
protected static int mXTileCount;//X轴上方格的个数
protected static int mYTileCount;//Y轴上方格的个数
private static int mXOffset;//绘图时X轴上的起始座标
private static int mYOffset;//绘图时Y轴上的起始座标
private Bitmap[] mTileArray;//位图数组
private int[][] mTileGrid;//映射整个游戏画面的数组
private final Paint mPaint = new Paint();//画笔
mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);//设置方格的相对大小
public void resetTiles(int tilecount)//重置位图数组的长度
protected void onSizeChanged(int w, int h, int oldw, int oldh)//适应各种分辨率的屏幕
public void loadTile(int key, Drawable tile)//导入位图
public void clearTiles()//擦除游戏画面
public void setTile(int tileindex, int x, int y)//设置游戏画面:tileindex取值为0,1,2,3;0:空白;1:redstar.png;2:yellowstar.png;3:greenstar.png.
public void onDraw(Canvas canvas)//根据mTileGrid数组绘制游戏画面
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);
/**自己改的代码,将不同的位图替换为相应颜色的圆形*/
switch(mTileGrid[x][y]){
case 1:mPaint.setColor(Color.RED);break;
case 2:mPaint.setColor(Color.YELLOW);break;
case 3:mPaint.setColor(Color.GREEN);
}
canvas.drawCircle(mXOffset + x * mTileSize + mTileSize/2, mYOffset + y * mTileSize + mTileSize/2,
mTileSize/2, mPaint);
}
}
}
}
图1 不同的界面
3. SnakeView.java
SnakeView的基类是TileView,是整个贪吃蛇游戏的核心,包含了游戏的算法及相应的数据。
贪吃蛇移动的算法很简单,使用一个队列保存贪吃蛇身体的每一个节点的座标,移动时只需要根据移动的方向在队列的头部加入一个新的节点,同时删除尾部的节点。
private void updateSnake() {
boolean growSnake = false;
Coordinate head = mSnakeTrail.get(0);
Coordinate newHead = new Coordinate(1, 1);
mDirection = mNextDirection;
switch (mDirection) {
case EAST: {
newHead = new Coordinate(head.x + 1, head.y);
break;
}
case WEST: {
newHead = new Coordinate(head.x - 1, head.y);
break;
}
case NORTH: {
newHead = new Coordinate(head.x, head.y - 1);
break;
}
case SOUTH: {
newHead = new Coordinate(head.x, head.y + 1);
break;
}
}//构造新头
if ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2) || (newHead.y > mYTileCount - 2)) {
setMode(LOSE);
return;
}//撞墙了
int snakelength = mSnakeTrail.size();
for (int snakeindex = 0; snakeindex < snakelength; snakeindex++) {
Coordinate c = mSnakeTrail.get(snakeindex);
if (c.equals(newHead)) {
setMode(LOSE);
return;
}
}//撞到自己了
int applecount = mAppleList.size();
for (int appleindex = 0; appleindex < applecount; appleindex++) {
Coordinate c = mAppleList.get(appleindex);
if (c.equals(newHead)) {//撞苹果了
mAppleList.remove(c);
addRandomApple();
mScore++;
mMoveDelay *= 0.9;
growSnake = true;
}
}
mSnakeTrail.add(0, newHead);//加头
if (!growSnake) {
mSnakeTrail.remove(mSnakeTrail.size() - 1);//去尾
}
int index = 0;
for (Coordinate c : mSnakeTrail) {
if (index == 0) {
setTile(YELLOW_STAR, c.x, c.y);
} else {
setTile(RED_STAR, c.x, c.y);
}
index++;
}//标记头部
}
随机生成苹果的算法:随机生成苹果依赖随机函数Random();算法流程是先随机生成一个在(1,1)~(mXtileCount,mYtileCount)范围之内的座标,然后读取保存有贪吃蛇身体节点座标的队列,以保证生成的座标不在蛇的身体上。
private void addRandomApple() {
Coordinate newCoord = null;
boolean found = false;
while (!found) {
int newX = 1 + RNG.nextInt(mXTileCount - 2);
int newY = 1 + RNG.nextInt(mYTileCount - 2);
newCoord = new Coordinate(newX, newY);//随机生成的座标
boolean collision = false;
int snakelength = mSnakeTrail.size();
for (int index = 0; index < snakelength; index++) {
if (mSnakeTrail.get(index).equals(newCoord)) {
collision = true;//座标在蛇的身上,!found为真,重新生成座标
}
}
found = !collision;
}
if (newCoord == null) {
Log.e(TAG, "Somehow ended up with a null newCoord!");
}
mAppleList.add(newCoord);
}
处理按键事件:这一部分主要分为两个小部分;第一部分是处理游戏的开始及重新开始的按键事件;第二部分是处理在游戏过程中的按键事件。第二部分主要是通过前一移动方向(mDirection)和按键方向(KeyEvent),推出下一个移动方向(mNextDirection),主要是过滤掉和mDirection相反的方向。
定时刷新游戏画面:定时刷新游戏画面通过android.os.handler类实现;
class RefreshHandler extends Handler {
@Override
/**收到消息就执行的动作*/
public void handleMessage(Message msg) {
SnakeView.this.update();//计算一帧画面
SnakeView.this.invalidate();//更新画面;调用Draw()
}
/**定时发消息*/
public void sleep(long delayMillis) {
this.removeMessages(0);
sendMessageDelayed(obtainMessage(0), delayMillis);
}
};
4. View Hiersrchy