——/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