Android實例剖析筆記(五)
摘要:介紹Android sdk中自帶的第二個示例程序—Snake(貪食蛇)
游戲暫停/繼續機制
由于原來的代碼中在游戲運行時沒有提供控制選項(比如暫停/繼續),因此除非你死了,否則只能玩到底。我這里對代碼進行一些修改,加入一個Option Menu來提供暫停/繼續機制。
首先加入一個變量記錄游戲當前狀態
private int mState = SnakeView.READY;
然后重載onCreateOptionsMenu函數,創建一個控制菜單項,并對其進行處理,提供暫停/繼續機制。
/*
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @Author:phinecos
* @Date:2009-08-28
*/
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case MENU_CONTROL:
{
if (mState == SnakeView.PAUSE)
{//此前狀態是"停止",則轉為"運行"
mState = SnakeView.RUNNING;
mSnakeView.setMode(SnakeView.RUNNING);
item.setIcon(android.R.drawable.ic_media_pause).setTitle(R.string.cmd_pause);
}
else if(mState == SnakeView.RUNNING)
{//此前狀態是"運行",則轉為“暫停"
mState = SnakeView.PAUSE;
mSnakeView.setMode(SnakeView.PAUSE);
item.setIcon(android.R.drawable.ic_media_play).setTitle(R.string.cmd_run);
}
else if(mState == SnakeView.READY)
{//此前是"初始狀態",則轉為"運行"
mState = SnakeView.RUNNING;
}
return true;
}
}
return super.onOptionsItemSelected(item);
}
/*
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @Author:phinecos
* @Date:2009-08-28
*/
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_CONTROL, 0, R.string.cmd_pause).setIcon(android.R.drawable.ic_media_pause);
return true;
}
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @Author:phinecos
* @Date:2009-08-28
*/
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case MENU_CONTROL:
{
if (mState == SnakeView.PAUSE)
{//此前狀態是"停止",則轉為"運行"
mState = SnakeView.RUNNING;
mSnakeView.setMode(SnakeView.RUNNING);
item.setIcon(android.R.drawable.ic_media_pause).setTitle(R.string.cmd_pause);
}
else if(mState == SnakeView.RUNNING)
{//此前狀態是"運行",則轉為“暫停"
mState = SnakeView.PAUSE;
mSnakeView.setMode(SnakeView.PAUSE);
item.setIcon(android.R.drawable.ic_media_play).setTitle(R.string.cmd_run);
}
else if(mState == SnakeView.READY)
{//此前是"初始狀態",則轉為"運行"
mState = SnakeView.RUNNING;
}
return true;
}
}
return super.onOptionsItemSelected(item);
}
/*
* @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
* @Author:phinecos
* @Date:2009-08-28
*/
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
super.onCreateOptionsMenu(menu);
menu.add(0, MENU_CONTROL, 0, R.string.cmd_pause).setIcon(android.R.drawable.ic_media_pause);
return true;
}
修改后運行截圖如下:
當然,這段代碼還是有問題的,游戲剛開始時,必須先點擊菜單確認,再按上方向鍵才能開始。(以后再來修改。。。)
穿墻貪食蛇
第二個修改是把這個普通的貪食蛇改成可以穿墻(呵呵,這樣就可以不死了。。。)。想必要修改的就是撞墻檢測那段代碼?沒錯,就是下面這段!
// Collision detection
// For now we have a 1-square wall around the entire arena
if ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2)|| (newHead.y > mYTileCount - 2))
{//撞墻
setMode(LOSE);
return;
}
// For now we have a 1-square wall around the entire arena
if ((newHead.x < 1) || (newHead.y < 1) || (newHead.x > mXTileCount - 2)|| (newHead.y > mYTileCount - 2))
{//撞墻
setMode(LOSE);
return;
}
原來的版本是發現撞墻時就直接判定為失敗,我這里做個小小的修改,讓它可以穿墻而去:
private void updateSnake()
{
boolean growSnake = false;
// grab the snake by the head
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 == 0)
{//穿左邊的墻
newHead.x = mXTileCount - 2;
}
else if (newHead.y == 0)
{//穿上面的墻
newHead.y = mYTileCount - 2;
}
else if (newHead.x == mXTileCount - 1)
{//穿右邊的墻
newHead.x = 1;
}
else if (newHead.y == mYTileCount - 1)
{//穿下面的墻
newHead.y = 1;
}
// 判斷是否撞到自己
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;
}
}
// push a new head onto the ArrayList and pull off the tail
mSnakeTrail.add(0, newHead);
// except if we want the snake to grow
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++;
}
}
{
boolean growSnake = false;
// grab the snake by the head
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 == 0)
{//穿左邊的墻
newHead.x = mXTileCount - 2;
}
else if (newHead.y == 0)
{//穿上面的墻
newHead.y = mYTileCount - 2;
}
else if (newHead.x == mXTileCount - 1)
{//穿右邊的墻
newHead.x = 1;
}
else if (newHead.y == mYTileCount - 1)
{//穿下面的墻
newHead.y = 1;
}
// 判斷是否撞到自己
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;
}
}
// push a new head onto the ArrayList and pull off the tail
mSnakeTrail.add(0, newHead);
// except if we want the snake to grow
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++;
}
}
其實修改后的代碼非常簡單,就是把新節點的值做些處理,讓它移動到對應的行/列的頭部或尾部即可。下面就是修改后的“穿墻”貪食蛇的運行截圖:
全屏機制
游戲一般都是全屏的,原始代碼也考慮到標題欄太過難看了,于是使用下面這句代碼就去掉了標題欄:
requestWindowFeature(Window.FEATURE_NO_TITLE);
可還是沒有達到全屏的效果,在Android1.5中實現全屏效果非常簡單,只需要一句代碼即可實現:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
運行效果如下圖所示:
全站熱搜