Android实例剖析笔记(五)

      这个系列的前四篇文章介绍了Android sdk中自带的NotePad程序,算是开了个头,这篇开始介绍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 ;
    }

修改后运行截图如下:



Android实例剖析笔记(五)_第1张图片

当然,这段代码还是有问题的,游戏刚开始时,必须先点击菜单确认,再按上方向键才能开始。(以后再来修改。。。)

穿墙贪食蛇

      第二个修改是把这个普通的贪食蛇改成可以穿墙(呵呵,这样就可以不死了。。。)。想必要修改的就是撞墙检测那段代码?没错,就是下面这段!

//  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 ;
}

原来的版本是发现撞墙时就直接判定为失败,我这里做个小小的修改,让它可以穿墙而去:

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
++ ;
        }
}

    其实修改后的代码非常简单,就是把新节点的值做些处理,让它移动到对应的行/列的头部或尾部即可。

下面就是修改后的穿墙贪食蛇的运行截图:

Android实例剖析笔记(五)_第2张图片

全屏机制

      游戏一般都是全屏的,原始代码也考虑到标题栏太过难看了,于是使用下面这句代码就去掉了标题栏:

requestWindowFeature(Window.FEATURE_NO_TITLE);

可还是没有达到全屏的效果,在Android1.5中实现全屏效果非常简单,只需要一句代码即可实现:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

运行效果如下图所示:

Android实例剖析笔记(五)_第3张图片
    接下来的修改目标是加入得分排行榜机制,再加入一个启动画面和选择菜单。当然,这一篇文章水了点,仅仅记录了自己做的一些小实验,并没有涉及到Snake的代码分析,不过请继续期待下一篇文章。。。


作者:
phinecos(洞庭散人)
出处:http://phinecos.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但请保留此段声明,并在文章页面明显位置给出原文连接

你可能感兴趣的:(Android实例剖析笔记(五))