zoukankan      html  css  js  c++  java
  • android_snakez

    新文章移至 
    http://cffile.sinaapp.com/?p=50
     

    /**

     * Snake: a simple game that everyone can enjoy.

     *

     * This is an implementation of the classic Game "Snake", in which you control a

     * serpent roaming around the garden looking for apples. Be careful, though,

     * because when you catch one, not only will you become longer, but you'll move

     * faster. Running into yourself or the walls will end the game.

     *

     */

    翻译:

    这个一个每个人都喜欢的简单的小游戏

    Snake是游戏的实现类,通过控制小蛇在花园中游走寻找苹果,注意,每吃掉一个苹果,小蛇身体不但会变的更长,还会移动的更敏捷,一旦撞上四周的墙或是碰到自己就会结束这次游戏。

     

    代码结构分析:

    Snake            主游戏窗口

    SnakeView      游戏视图类,是实现游戏的主体类

    TileView        一个处理图片或其它

    Coordinate   :这是一个包括两个参数,用于记录X轴和Y轴简单类,其中包括一个比较函数.

    RefshHandler :用于更新视图

    Snake

           这个类是游戏的主游戏窗口,是框架容器,

    1.         游戏的开始:oncreate此外的亮点是:setContentView(R.layout.snake_layout);设置窗口的布局文件,这里Android123给大家说明的是,这里 snake_layout使用了自定义资源标签的方式,大家注意学习:这里我们可以看到来自SnakeView这个派生类的名称,由于Android 部的R.资源不包含SnakeView类,所以我们必须写清楚Package,比如 com.exmple.android.snake.SnakeView 然后和其他控件使用一样,都是一个id然后宽度、高度、以及自定义的标签tileSize(尾巴长度),如下:

     <com.example.android.snake.SnakeView

         android:id="@+id/snake"

           android:layout_width="fill_parent"

                    android:layout_height="fill_parent"

                    tileSize="12"

                    />

    2.         onPause:关于这点,大家可以参考下在我blog中关于active生命周期http://xusaomaiss.javaeye.com/admin/blogs/379826

    在玩游戏过程中,如果有来电或是其它事件中断,这时应该把当前状态保存。以便返回时,还可以继续玩游戏。这就使用onSaveInstanceState实现保存当前状态。

     

    TileView

    注:此部分解析来自: Android示例程序Snake贪食代码分析()

    TileView,从名称上不难看出这是一个方砖类,就是生成一个方块。 TileView使用了Android平台的显示基类ViewView类是直接从java.lang.Object派生出来的,是各种控件比如 TextViewEditView的基类,当然包括我们的窗口Activity类,这些在SDK文档中都说的比较清楚。

      
    这里定义了 5int型全局的变量,分别是方砖的数量mTileSize;方砖水平x防线的数量mXTileCount;以及竖直y方向上的方砖数量 mYTileCount,下面是一个相对偏移位置mXOffsetmYOffset;这里android123主让要大家了解如何自定义View Android开发中,在一个View类中主要是重写onSizeChanged方法来控制改变部分,以及onDraw实现画布的修改,实现的简写如下:

    @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {}
    @Override
        public void onDraw(Canvas canvas) { super.onDraw(canvas);}
      
    我们自定义的TileView类需要自己添加一个构造方法,根据需要,我们还重载了一种包含样式的方法,这里大家可以多看下Gallery控件的实现,就好理解了,下面是基本框架。
    public TileView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}
    public TileView(Context context, AttributeSet attrs) { super(context, attrs);}
      
    在贪食蛇游戏中我们知道Snake是移动的,所以加入了一个清除显示的clearTiles方法,通过一个二维数组保存一个gird网格型的运动轨迹,下一次我们将会讲解android贪食蛇的游戏逻辑和完整的关联拼接实现。

     

    SnakeView

    在这个类中实现的游戏的实体,从游戏需求的角色,这个游戏包括了如下方面:

    1. 随机产生小苹果,apples这里是复数,当然是是大于1个苹果,所以代码中产生了两个苹果。

    2. 游戏状态管理

    3. 画蛇,view的更新

    4. 吃掉苹果后小蛇状态的变化

    5. 画围墙

     

    如果实现吃掉苹果小蛇速度变快?

     

    关键是:mMoveDelay这个变量,以下是涉及到这个变量的函数,

    每次吃掉苹果后,就会updateSnake一下,里面就把时间处理了:mMoveDelay *= 0.9;

     

    小蛇其实就是一个数组,google的代码就是好注释写的清楚:

    /**

         * mSnakeTrail: a list of Coordinates that make up the snake's body

        * mAppleList: the secret location of the juicy apples the snake craves.

         */

    private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();

    private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>();

    mSnakeTrail:一个由Coordinates列表组织的蛇身.

    mAppleList:存放鲜美多汁的苹果列表

    通过这个数组画出小蛇不难,问题是如何判断游戏是否结束?

    问题是如何判断游戏的状态

    所有以下的代码来自updateSnake

    1. 吃了苹果

    // Look for apples

            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;

                }

            }

    2. 碰到了自己

    // Look for collisions with itself

            int snakelength = mSnakeTrail.size();

            for (int snakeindex = 0; snakeindex < snakelength; snakeindex++) {

                Coordinate c = mSnakeTrail.get(snakeindex);

                if (c.equals(newHead)) {

                    setMode(LOSE);

                    return;

                }

            }

    3.碰到墙了

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

     

            }

     

    源代码分析

    Snake状态分析:

    snakeView中定义了snake游戏的几种状态:

        private int mMode = READY;     

        public static final int PAUSE = 0; //暂定

        public static final int READY = 1; //准备好了

        public static final int RUNNING = 2;//正在运行

    public static final int LOSE = 3; //结束,输了游戏

     

    各种游戏状态

     rady running

    pausedlose

    以上状态是通过:void setMode(int newMode)函数实现。

    如何实现画出小方块:

    参看:http://yuefeng.javaeye.com/blog/206706

     

    public class DrawView extends View {

       

        private final int mTileSize = 12;

       

        private final String TAG="DEMO";

       

        private Paint pa = new Paint();

     

        private Bitmap mTileArray;

     

        void loadImage(){

           Resources r = this.getContext().getResources();

          

           Drawable tile = r.getDrawable(R.drawable.redstar);

          

           Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize,

                  Bitmap.Config.ARGB_8888);

           Canvas canvas = new Canvas(bitmap);

           tile.setBounds(0, 0, mTileSize, mTileSize);

           tile.draw(canvas);

     

           mTileArray = bitmap;

          

          

        }

    public DrawView(Context context, AttributeSet attrs, int defStyle) {

           super(context, attrs, defStyle);

           // TODO Auto-generated constructor stub

           loadImage();

           x = 10;

           y = 10;

           Log.i(TAG, "DrawView 2");

        }

       

    //如果没有这段代码,大家可以试一下,改用上面的代码,程序能否通过。

        public DrawView(Context context, AttributeSet attrs) {

           super(context, attrs);

           // TODO Auto-generated constructor stub

           loadImage();

           Log.i(TAG, "DrawView 3");

       

        }

        @Override

        protected void onDraw(Canvas canvas) {

           super.onDraw(canvas);

           Log.i(TAG, "onDraw 1");

           canvas.drawBitmap(mTileArray, x, y, pa);

        }

    }

    通过上面的文章可以画出小方块,但注意到SnakeView一共有两构造函数,那个函数才真正起作用呢?

    l         public SnakeView(Context context, AttributeSet attrs)

    l         public SnakeView(Context context, AttributeSet attrs, int defStyle)

    通过加log的方式,判断是第一个构造函数起作用。

    在第一个构造函数上方有一段注释:通过XML文件构造出SnakeView

         * Constructs a SnakeView based on inflation from XML

    如果不使用这个构造函数,将会造成错误,可以试一下,看一下结果是怎样!本人得到如下的错误提示:

     

    05-21 14:13:26.079: ERROR/AndroidRuntime(711): Caused by: java.lang.NoSuchMethodException: DrawView

    按键处理:

    public boolean onKeyDown(int keyCode, KeyEvent event) {

           // TODO Auto-generated method stub

            if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {

                Log.i(TAG, "KEYCODE_DPAD_UP");       

            } 

           return super.onKeyDown(keyCode, event);      

        }

    如何让我们的小方块动起来?

    实现小方块动起来的秘密在于viewpublic void invalidate ()

    大家可以参看SDK文档中关于ViewDrawing中的一小段话

    To force a view to draw, call invalidate().//为了让view重画,可以调用invalidate函数

    方法:

    1.      DrawView类中添加两个成员:

        private int x,y;

    同时实现get,set方法,

    2.         在构造函数中添加他们的初始值,

    3.         修改onDraw

    @Override

        protected void onDraw(Canvas canvas) {

           super.onDraw(canvas);

           Log.i(TAG, "onDraw 1");

           canvas.drawBitmap(mTileArray, x, y, pa);

        }

    4.修改onKeyDown函数

    @Override

        public boolean onKeyDown(int keyCode, KeyEvent event) {

           // TODO Auto-generated method stub

            if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {

                Log.i(TAG, "KEYCODE_DPAD_UP");

                dv.setX(dv.getX()+10);

                dv.invalidate();

            } 

           return super.onKeyDown(keyCode, event);      

        }

    最后运行结果如下图:

    附:网络上关于snake分析的三篇文章

    上一次我们大概讲解了下Android SDK中的演示程序Snake游戏的主框架,今天我看来看下实现的基础类TileView,从名称上不难看出这是一个方砖类,就是生成一个方块。 TileView使用了Android平台的显示基类ViewView类是直接从java.lang.Object派生出来的,是各种控件比如 TextViewEditView的基类,当然包括我们的窗口Activity类,这些在SDK文档中都说的比较清楚。

      
    这里定义了 5int型全局的变量,分别是方砖的数量mTileSize;方砖水平x防线的数量mXTileCount;以及竖直y方向上的方砖数量 mYTileCount,下面是一个相对偏移位置mXOffsetmYOffset;这里android123主让要大家了解如何自定义View Android开发中,在一个View类中主要是重写onSizeChanged方法来控制改变部分,以及onDraw实现画布的修改,实现的简写如下:

    @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {}


    @Override
        public void onDraw(Canvas canvas) { super.onDraw(canvas);}

      
    我们自定义的TileView类需要自己添加一个构造方法,根据需要,我们还重载了一种包含样式的方法,这里大家可以多看下Gallery控件的实现,就好理解了,下面是基本框架。
    public TileView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}

    public TileView(Context context, AttributeSet attrs) { super(context, attrs);}

      
    在贪食蛇游戏中我们知道Snake是移动的,所以加入了一个清除显示的clearTiles方法,通过一个二维数组保存一个gird网格型的运动轨迹,下一次我们将会讲解android贪食蛇的游戏逻辑和完整的关联拼接实现。

    今天我们分析下最复杂的SnakeView的设计,它是派生于TileView方砖类,TileView构建是基于Android直接的显示类View,如果不明白的可以查看Android示例程序Snake贪食蛇代码分析(二)一文有关TileView类的实现, 首先我们看到整个游戏分 READY、PAUSE 、RUNNING 、LOSE四种mMode状态模式,分别对应准备、暂停、运行中、结束(死亡),毕竟贪食蛇没有胜利这个结果。

     整个Snake的运行分4个方向,NORTH、SOUTH 、EAST、WEST分别对应了北、南、东、西四个方向,其中变量mDirection对应当 前的方向,而mNextDirection对应下个运行时的位置。这里星星分3种,使用的是一个Drawable图片,分RED_STAR、 YELLOW_STAR和GREEN_STAR三种颜色,游戏的星星出现位置由Random随机数生成器来决定,这里Random一般和Timer系统时 钟来随机生成更真实一些,通过一个Handler对象来控制画面的更新,使用了this.update();和this.invalidate();这两 个本地方法,Update和invaildate均为android.view.View类的本地方法。这里资源的使用通过Resources r = this.getContext().getResources();获取了r对象的实例,通过 r.getDrawable(R.drawable.redstar)获取资源名为redstar的资源,返回的是一个Drawable对象。

     对于按键信息,直接重写View类的onKeyDown方法,这里KeyEvent传递的是按键的映射,比如KEYCODE_DPAD_UP向上,KeyEvent.KEYCODE_DPAD_DOWN向下等等,详细的查看SDK中的onKeyDown

      @Override
        public boolean onKeyDown(int keyCode, KeyEvent msg) {

            if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {}

      }

     整个游戏的控制流程就是上面这些,对于游戏的逻辑而言比较简单,这个贪食蛇并没有包含3D设计和类似Nokia的能量走廊、6边形轨迹,有空了我们一起来完善一个3D的贪食蛇游戏

  • 相关阅读:
    Maven中的依赖相关总结
    Redis(序)应用场景
    Java并发专栏(一)—— Process vs Thread
    Java中转换为二进制的几种实现
    Java中转换为十六进制的几种实现
    oracle日期格式和java日期格式区别 HH24:mm:ss和HH24:mi:ss的区别
    远程教学的一些准备
    将latex的beamer做的幻灯片转换为ppt格式后的一些问题
    最近看过的雨课堂和智慧树的笔记
    关于在线授课的探索
  • 原文地址:https://www.cnblogs.com/chenzhihong/p/2232228.html
Copyright © 2011-2022 走看看