zoukankan      html  css  js  c++  java
  • Android 带你玩转实现游戏2048 其实2048只是个普通的控件(转)

    1、概述

    博主本想踏入游戏开放行业,无奈水太深,不会游泳;于是乎,只能继续开发应用,但是原生Android也能开发游戏么,2048、像素鸟、别踩什么来着;今天给大家带来一篇2048的开发篇,别怕不分上下文,或者1、2、3、4,一篇包你能玩happy~虽然我从来没有玩到过2048!!!其实大家也可以当作自定义控件来看~~~

    特别说明一下,游戏2048里面的方块各种颜色来源于:http://download.csdn.net/detail/qq1121674367/7155467,这个2048的代码中,其他代码,太多,未参考;特此感谢分享;大家也可以下载下,对比学习下;

    接下来贴个我们项目的效果图:

    ok 看完效果图,我就准备带领大家征服这款游戏了~~~

    2、实现分析

    贴一张静态图,开始对我们游戏的设计:

    可以看到,游戏其实就是一个容器,里面很多个方块,触摸容器,里面的方块的形态会发生变化。那么:

    1、容器我们准备自定义ViewGroup ,叫做Game2048Layout ; 里面的块块自定义View ,叫做Game2048Item

    接下来从简单的开始:

    2、Game2048Item

    Game2048Item是个View,并且需要哪些属性呢?

    首先得有个number,显示数字嘛,然后绘制的时候根据number绘制背景色;还需要呢?嗯,需要正方形边长,再考虑下,这个边长应该Item自己控制么?显然不是的,Game2048Layout 是个n*n的面板,这个n是不确定的,所以Item的边长肯定是Game2048Layout 计算好传入的。这样必须的属性就这两个。

    3、Game2048Layout

     Game2048Layout是个容器,我们观察下,里面View是个 n*n的排列,我们准备让其继承RelativeLayout ; 这样可以通过设置Item的RIGHT_OF之类的属性进行定位;

    我们在onMeasure里面得到Layout的宽和高,然后根据n*n,生成一定数目的Item,为其设置宽和高,放置到Layout中,这样整个游戏的布局就做好了;绘制的细节上:Item间有横向与纵向的间距,所以需要设置这个值,叫做mMargin。然后Item的边长 =  ( Layout边长 - (n-1)*mMagin ) / n ; 

    剩下的就是onTouchEvent里面去判断用户手势了,然后就行各种逻辑操作了~

    3、代码之旅

    首先来看看我们的Game2048Item

    1、Game2048Item

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.zhy.game2048.view;  
    2.   
    3. import android.content.Context;  
    4. import android.graphics.Canvas;  
    5. import android.graphics.Color;  
    6. import android.graphics.Paint;  
    7. import android.graphics.Paint.Style;  
    8. import android.graphics.Rect;  
    9. import android.util.AttributeSet;  
    10. import android.util.Log;  
    11. import android.view.View;  
    12.   
    13. /** 
    14.  * 2048的每个Item 
    15.  *  
    16.  * @author zhy 
    17.  *  
    18.  */  
    19. public class Game2048Item extends View  
    20. {  
    21.     /** 
    22.      * 该View上的数字 
    23.      */  
    24.     private int mNumber;  
    25.     private String mNumberVal;  
    26.     private Paint mPaint;  
    27.     /** 
    28.      * 绘制文字的区域 
    29.      */  
    30.     private Rect mBound;  
    31.   
    32.     public Game2048Item(Context context, AttributeSet attrs, int defStyle)  
    33.     {  
    34.         super(context, attrs, defStyle);  
    35.         mPaint = new Paint();  
    36.   
    37.     }  
    38.   
    39.     public Game2048Item(Context context)  
    40.     {  
    41.         this(context, null);  
    42.     }  
    43.   
    44.     public Game2048Item(Context context, AttributeSet attrs)  
    45.     {  
    46.         this(context, attrs, 0);  
    47.     }  
    48.   
    49.     public void setNumber(int number)  
    50.     {  
    51.         mNumber = number;  
    52.         mNumberVal = mNumber + "";  
    53.         mPaint.setTextSize(30.0f);  
    54.         mBound = new Rect();  
    55.         mPaint.getTextBounds(mNumberVal, 0, mNumberVal.length(), mBound);  
    56.         invalidate();  
    57.     }  
    58.       
    59.       
    60.   
    61.     public int getNumber()  
    62.     {  
    63.         return mNumber;  
    64.     }  
    65.   
    66.     @Override  
    67.     protected void onDraw(Canvas canvas)  
    68.     {  
    69.           
    70.         super.onDraw(canvas);  
    71.         String mBgColor = "";  
    72.         switch (mNumber)  
    73.         {  
    74.         case 0:  
    75.             mBgColor = "#CCC0B3";  
    76.             break;  
    77.         case 2:  
    78.             mBgColor = "#EEE4DA";  
    79.             break;  
    80.         case 4:  
    81.             mBgColor = "#EDE0C8";  
    82.             break;  
    83.         case 8:  
    84.             mBgColor = "#F2B179";// #F2B179  
    85.             break;  
    86.         case 16:  
    87.             mBgColor = "#F49563";  
    88.             break;  
    89.         case 32:  
    90.             mBgColor = "#F5794D";  
    91.             break;  
    92.         case 64:  
    93.             mBgColor = "#F55D37";  
    94.             break;  
    95.         case 128:  
    96.             mBgColor = "#EEE863";  
    97.             break;  
    98.         case 256:  
    99.             mBgColor = "#EDB04D";  
    100.             break;  
    101.         case 512:  
    102.             mBgColor = "#ECB04D";  
    103.             break;  
    104.         case 1024:  
    105.             mBgColor = "#EB9437";  
    106.             break;  
    107.         case 2048:  
    108.             mBgColor = "#EA7821";  
    109.             break;  
    110.         default:  
    111.             mBgColor = "#EA7821";  
    112.             break;  
    113.         }  
    114.   
    115.         mPaint.setColor(Color.parseColor(mBgColor));  
    116.         mPaint.setStyle(Style.FILL);  
    117.         canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);  
    118.   
    119.         if (mNumber != 0)  
    120.             drawText(canvas);  
    121.   
    122.     }  
    123.   
    124.     /** 
    125.      * 绘制文字 
    126.      *  
    127.      * @param canvas 
    128.      */  
    129.     private void drawText(Canvas canvas)  
    130.     {  
    131.           
    132.         mPaint.setColor(Color.BLACK);  
    133.         float x = (getWidth() - mBound.width()) / 2;  
    134.         float y = getHeight() / 2 + mBound.height() / 2;  
    135.         canvas.drawText(mNumberVal, x, y, mPaint);  
    136.     }  
    137.   
    138. }  


    很简单,基本就一个onDraw通过number来绘制背景和数字;number通过调用setNumer进行设置;它的宽和高都是固定值,所以我们并不需要自己进行测量~~

    2、Game2048Layout

    1、成员变量

    这就是我们最主要的一个类了,首先我们看看这个类的成员变量,先看看各个成员变量的作用:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.      * 设置Item的数量n*n;默认为4 
    3.      */  
    4.     private int mColumn = 4;  
    5.     /** 
    6.      * 存放所有的Item 
    7.      */  
    8.     private Game2048Item[] mGame2048Items;  
    9.   
    10.     /** 
    11.      * Item横向与纵向的边距 
    12.      */  
    13.     private int mMargin = 10;  
    14.     /** 
    15.      * 面板的padding 
    16.      */  
    17.     private int mPadding;  
    18.     /** 
    19.      * 检测用户滑动的手势 
    20.      */  
    21.     private GestureDetector mGestureDetector;  
    22.   
    23.     // 用于确认是否需要生成一个新的值  
    24.     private boolean isMergeHappen = true;  
    25.     private boolean isMoveHappen = true;  
    26.   
    27.     /** 
    28.      * 记录分数 
    29.      */  
    30.     private int mScore;  


    主要的成员变量就这些,直接看注释也比较容易理解~~

    了解了成员变量,接下来我们需要在构造方法里面得到一些值和初始化一些变量

    2、构造方法

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. public Game2048Layout(Context context, AttributeSet attrs, int defStyle)  
    2.     {  
    3.         super(context, attrs, defStyle);  
    4.   
    5.         mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,  
    6.                 mMargin, getResources().getDisplayMetrics());  
    7.         // 设置Layout的内边距,四边一致,设置为四内边距中的最小值  
    8.         mPadding = min(getPaddingLeft(), getPaddingTop(), getPaddingRight(),  
    9.                 getPaddingBottom());  
    10.   
    11.         mGestureDetector = new GestureDetector(context , new MyGestureDetector());  
    12.   
    13.     }  


    我们在构造方法里面得到Item间的边距(margin)和我们容器的内边距(padding,),这个值应该四边一致,于是我们取四边的最小值;这两个属性可以抽取为自定义的属性;然后初始化了我们的mGestureDetector

    有了margin和padding,我们就可以计算我们item的边长了。这个计算过程肯定在onMeasure里面,因为我们需要在onMeasure获取容器的宽和高

    3、onMeasure

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. private boolean once;  
    2.   
    3.     /** 
    4.      * 测量Layout的宽和高,以及设置Item的宽和高,这里忽略wrap_content 以宽、高之中的最小值绘制正方形 
    5.      */  
    6.     @Override  
    7.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
    8.     {  
    9.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    10.         // 获得正方形的边长  
    11.         int length = Math.min(getMeasuredHeight(), getMeasuredWidth());  
    12.         // 获得Item的宽度  
    13.         int childWidth = (length - mPadding * 2 - mMargin * (mColumn - 1))  
    14.                 / mColumn;  
    15.   
    16.         if (!once)  
    17.         {  
    18.             if (mGame2048Items == null)  
    19.             {  
    20.                 mGame2048Items = new Game2048Item[mColumn * mColumn];  
    21.             }  
    22.             // 放置Item  
    23.             for (int i = 0; i < mGame2048Items.length; i++)  
    24.             {  
    25.   
    26.                 Game2048Item item = new Game2048Item(getContext());  
    27.   
    28.                 mGame2048Items[i] = item;  
    29.                 item.setId(i + 1);  
    30.                 RelativeLayout.LayoutParams lp = new LayoutParams(childWidth,  
    31.                         childWidth);  
    32.                 // 设置横向边距,不是最后一列  
    33.                 if ((i + 1) % mColumn != 0)  
    34.                 {  
    35.                     lp.rightMargin = mMargin;  
    36.                 }  
    37.                 // 如果不是第一列  
    38.                 if (i % mColumn != 0)  
    39.                 {  
    40.                     lp.addRule(RelativeLayout.RIGHT_OF,//  
    41.                             mGame2048Items[i - 1].getId());  
    42.                 }  
    43.                 // 如果不是第一行,//设置纵向边距,非最后一行  
    44.                 if ((i + 1) > mColumn)  
    45.                 {  
    46.                     lp.topMargin = mMargin;  
    47.                     lp.addRule(RelativeLayout.BELOW,//  
    48.                             mGame2048Items[i - mColumn].getId());  
    49.                 }  
    50.                 addView(item, lp);  
    51.             }  
    52.             generateNum();  
    53.         }  
    54.         once = true;  
    55.   
    56.         setMeasuredDimension(length, length);  
    57.     }  


    首先设置容器的边长为宽高中的最小值;然后(length - mPadding * 2 - mMargin * (mColumn - 1)) / mColumn ; 去计算Item的边长;

    拿到以后,根据我们的mColumn初始化我们的Item数组,然后遍历生成Item,设置Item的LayoutParams以及Rule(RIGHT_OF , BELOW),最后添加到我们的容器中;

    最后我们通过setMeasuredDimension(length, length);改变我们布局占据的空间;

    到此,我们整个面板绘制完成了;

    接下来,就是根据用户的手势,去进行游戏逻辑操作了,手势那么肯定是onTouchEvent了:

    4、onTouchEvent

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @Override  
    2.     public boolean onTouchEvent(MotionEvent event)  
    3.     {  
    4.         mGestureDetector.onTouchEvent(event);  
    5.         return true;  
    6.     }  


    我们把触摸事件交给了mGestureDetector,我们去看看我们的mGestureDetector,在构造方法中有这么一句:

    mGestureDetector = new GestureDetector(context , new MyGestureDetector());

    so,我们需要去看看MyGestureDetector:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. class MyGestureDetector extends GestureDetector.SimpleOnGestureListener  
    2.     {  
    3.   
    4.         final int FLING_MIN_DISTANCE = 50;  
    5.   
    6.         @Override  
    7.         public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
    8.                 float velocityY)  
    9.         {  
    10.             float x = e2.getX() - e1.getX();  
    11.             float y = e2.getY() - e1.getY();  
    12.   
    13.             if (x > FLING_MIN_DISTANCE  
    14.                     && Math.abs(velocityX) > Math.abs(velocityY))  
    15.             {  
    16.                 action(ACTION.RIGHT);  
    17.   
    18.             } else if (x < -FLING_MIN_DISTANCE  
    19.                     && Math.abs(velocityX) > Math.abs(velocityY))  
    20.             {  
    21.                 action(ACTION.LEFT);  
    22.   
    23.             } else if (y > FLING_MIN_DISTANCE  
    24.                     && Math.abs(velocityX) < Math.abs(velocityY))  
    25.             {  
    26.                 action(ACTION.DOWM);  
    27.   
    28.             } else if (y < -FLING_MIN_DISTANCE  
    29.                     && Math.abs(velocityX) < Math.abs(velocityY))  
    30.             {  
    31.                 action(ACTION.UP);  
    32.             }  
    33.             return true;  
    34.   
    35.         }  
    36.   
    37.     }  


    很简单,就是判读用户上、下、左、右滑动;然后去调用action(ACTION)方法;ACTION是个枚举:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.      * 运动方向的枚举 
    3.      *  
    4.      * @author zhy 
    5.      *  
    6.      */  
    7.     private enum ACTION  
    8.     {  
    9.         LEFT, RIGHT, UP, DOWM  
    10.     }  


    这么看,核心代码都在action方法里面了:

    5、根据用户手势重绘Item

    看代码前,先考虑下,用户从右向左滑动时,面板应该如何变化;取其中一行,可能性为:

    0 0 0 2 -> 2 0 0 0

    2 0 4 0 -> 2 4 0 0 

    2 2 4 0 -> 4 4 0 0 

    大概就这3中可能;

    我们算法是这么做的:

    拿2 2 4 0 来说:

    1、首先把每行有数字的取出来,临时存储下来,即[ 2, 2, 4 ];

    2、然后遍历合并第一个相遇的相同的,即[ 4, 4 ,0 ]

    3、然后直接放置到原行,不足补0,即[ 4, 4, 0 ,0 ]; 

    中间还有几个操作:

    1、生成一个新的数字,游戏在每次用户滑动时,可能会生成一个数字;我们的生成策略:如果发生移动或者合并,则生成一个数字;

    移动的判断,拿原数据,即【 2 ,2,4,0】和我们第一步临时存储的做比较,一一对比(遍历临时表),发现不同,则认为移动了;

    合并的判断,在合并的时候会设置合并的标志位为true;

    2、加分,如果发生合并,则加分,分值为合并得到的数字,比如 4,4 -> 8 ,即加8分 ; 也只需要在合并的时候进行相加就行了;

    介绍完了,来看我们的代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.  * 根据用户运动,整体进行移动合并值等 
    3.  */  
    4. private void action(ACTION action)  
    5. {  
    6.     // 行|列  
    7.     for (int i = 0; i < mColumn; i++)  
    8.     {  
    9.         List<Game2048Item> row = new ArrayList<Game2048Item>();  
    10.         // 行|列  
    11.         for (int j = 0; j < mColumn; j++)  
    12.         {  
    13.             // 得到下标  
    14.             int index = getIndexByAction(action, i, j);  
    15.   
    16.             Game2048Item item = mGame2048Items[index];  
    17.             // 记录不为0的数字  
    18.             if (item.getNumber() != 0)  
    19.             {  
    20.                 row.add(item);  
    21.             }  
    22.         }  
    23.           
    24.         for (int j = 0; j < mColumn && j < row.size(); j++)  
    25.         {  
    26.             int index = getIndexByAction(action, i, j);  
    27.             Game2048Item item = mGame2048Items[index];  
    28.   
    29.             if (item.getNumber() != row.get(j).getNumber())  
    30.             {  
    31.                 isMoveHappen = true;  
    32.             }  
    33.         }  
    34.           
    35.         // 合并相同的  
    36.         mergeItem(row);  
    37.           
    38.           
    39.         // 设置合并后的值  
    40.         for (int j = 0; j < mColumn; j++)  
    41.         {  
    42.             int index = getIndexByAction(action, i, j);  
    43.             if (row.size() > j)  
    44.             {  
    45.                 mGame2048Items[index].setNumber(row.get(j).getNumber());  
    46.             } else  
    47.             {  
    48.                 mGame2048Items[index].setNumber(0);  
    49.             }  
    50.         }  
    51.   
    52.     }  
    53.     generateNum();  
    54.   
    55. }  


    大体上是两层循环,外层循环代码循环次数,内层有3个for循环;

    第一个for循环,对应上述:首先把每行有数字的取出来,临时存储下来,即[ 2, 2, 4 ];

    第二个for循环,判断是否发生移动;

    // 合并相同的
    mergeItem(row); 是去进行合并操作,对应上述:然后遍历合并第一个相遇的相同的,即[ 4, 4 ,0 ];以及加分和设置合并标志位都在方法中;

    第三个for循环:设置合并后的值,对应上述:然后直接放置到原行,不足补0,即[ 4, 4, 0 ,0 ]; 

    最后生成数字,方法内部会进行判断游戏是否结束,是否需要生成数字;

    那么先看mergeItem的代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.      * 合并相同的Item 
    3.      *  
    4.      * @param row 
    5.      */  
    6.     private void mergeItem(List<Game2048Item> row)  
    7.     {  
    8.         if (row.size() < 2)  
    9.             return;  
    10.   
    11.         for (int j = 0; j < row.size() - 1; j++)  
    12.         {  
    13.             Game2048Item item1 = row.get(j);  
    14.             Game2048Item item2 = row.get(j + 1);  
    15.   
    16.             if (item1.getNumber() == item2.getNumber())  
    17.             {  
    18.                 isMergeHappen = true;  
    19.   
    20.                 int val = item1.getNumber() + item2.getNumber();  
    21.                 item1.setNumber(val);  
    22.   
    23.                 // 加分  
    24.                 mScore += val;  
    25.                 if (mGame2048Listener != null)  
    26.                 {  
    27.                     mGame2048Listener.onScoreChange(mScore);  
    28.                 }  
    29.   
    30.                 // 向前移动  
    31.                 for (int k = j + 1; k < row.size() - 1; k++)  
    32.                 {  
    33.                     row.get(k).setNumber(row.get(k + 1).getNumber());  
    34.                 }  
    35.                   
    36.                 row.get(row.size() - 1).setNumber(0);  
    37.                 return;  
    38.             }  
    39.   
    40.         }  
    41.   
    42.     }  


    也比较简单,循环查找相同的number,发现合并数字,加分;

    加分我们设置了一个回调,把分数回调出去:

    if (mGame2048Listener != null)
    {
    mGame2048Listener.onScoreChange(mScore);
    }

    最后看我们生成数字的代码:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.      * 产生一个数字 
    3.      */  
    4.     public void generateNum()  
    5.     {  
    6.   
    7.         if (checkOver())  
    8.         {  
    9.             Log.e("TAG", "GAME OVER");  
    10.             if (mGame2048Listener != null)  
    11.             {  
    12.                 mGame2048Listener.onGameOver();  
    13.             }  
    14.             return;  
    15.         }  
    16.   
    17.         if (!isFull())  
    18.         {  
    19.             if (isMoveHappen || isMergeHappen)  
    20.             {  
    21.                 Random random = new Random();  
    22.                 int next = random.nextInt(16);  
    23.                 Game2048Item item = mGame2048Items[next];  
    24.   
    25.                 while (item.getNumber() != 0)  
    26.                 {  
    27.                     next = random.nextInt(16);  
    28.                     item = mGame2048Items[next];  
    29.                 }  
    30.   
    31.                 item.setNumber(Math.random() > 0.75 ? 4 : 2);  
    32.   
    33.                 isMergeHappen = isMoveHappen = false;  
    34.             }  
    35.   
    36.         }  
    37.     }  


    首先判断是否结束,如果结束了,依然是回调出去,得让玩的人知道结束了;

    然后判断当然面板是有木有空的格子,如果没有,在判断需要生成新的数字么,需要则随机生成一个新的2或4;

    那么如何判断是否结束呢?

    首先肯定是没有空格了,然后四个方向上没有相同的数字就结束了:

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.      * 检测当前所有的位置都有数字,且相邻的没有相同的数字 
    3.      *  
    4.      * @return 
    5.      */  
    6.     private boolean checkOver()  
    7.     {  
    8.         // 检测是否所有位置都有数字  
    9.         if (!isFull())  
    10.         {  
    11.             return false;  
    12.         }  
    13.   
    14.         for (int i = 0; i < mColumn; i++)  
    15.         {  
    16.             for (int j = 0; j < mColumn; j++)  
    17.             {  
    18.   
    19.                 int index = i * mColumn + j;  
    20.   
    21.                 // 当前的Item  
    22.                 Game2048Item item = mGame2048Items[index];  
    23.                 // 右边  
    24.                 if ((index + 1) % mColumn != 0)  
    25.                 {  
    26.                     Log.e("TAG", "RIGHT");  
    27.                     // 右边的Item  
    28.                     Game2048Item itemRight = mGame2048Items[index + 1];  
    29.                     if (item.getNumber() == itemRight.getNumber())  
    30.                         return false;  
    31.                 }  
    32.                 // 下边  
    33.                 if ((index + mColumn) < mColumn * mColumn)  
    34.                 {  
    35.                     Log.e("TAG", "DOWN");  
    36.                     Game2048Item itemBottom = mGame2048Items[index + mColumn];  
    37.                     if (item.getNumber() == itemBottom.getNumber())  
    38.                         return false;  
    39.                 }  
    40.                 // 左边  
    41.                 if (index % mColumn != 0)  
    42.                 {  
    43.                     Log.e("TAG", "LEFT");  
    44.                     Game2048Item itemLeft = mGame2048Items[index - 1];  
    45.                     if (itemLeft.getNumber() == item.getNumber())  
    46.                         return false;  
    47.                 }  
    48.                 // 上边  
    49.                 if (index + 1 > mColumn)  
    50.                 {  
    51.                     Log.e("TAG", "UP");  
    52.                     Game2048Item itemTop = mGame2048Items[index - mColumn];  
    53.                     if (item.getNumber() == itemTop.getNumber())  
    54.                         return false;  
    55.                 }  
    56.   
    57.             }  
    58.   
    59.         }  
    60.   
    61.         return true;  
    62.   
    63.     }  
    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. /** 
    2.  * 是否填满数字 
    3.  *  
    4.  * @return 
    5.  */  
    6. private boolean isFull()  
    7. {  
    8.     // 检测是否所有位置都有数字  
    9.     for (int i = 0; i < mGame2048Items.length; i++)  
    10.     {  
    11.         if (mGame2048Items[i].getNumber() == 0)  
    12.         {  
    13.             return false;  
    14.         }  
    15.     }  
    16.     return true;  
    17. }  


    到此,我们的代码介绍完毕~~~完成了我们的Game2048Layout ; 接下来看如何使用呢?

    写游戏的过程很艰辛,但是用起来,看看什么叫so easy ; 当成普通的View即可:

    4、实践

    1、布局文件:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    2.     xmlns:tools="http://schemas.android.com/tools"  
    3.     android:layout_width="fill_parent"  
    4.     android:layout_height="fill_parent" >  
    5.   
    6.     <com.zhy.game2048.view.Game2048Layout  
    7.         android:id="@+id/id_game2048"  
    8.         android:layout_width="fill_parent"  
    9.         android:layout_height="fill_parent"  
    10.         android:layout_centerInParent="true"  
    11.         android:background="#ffffff"  
    12.         android:padding="10dp" >  
    13.     </com.zhy.game2048.view.Game2048Layout>  
    14.   
    15.     <LinearLayout  
    16.         android:layout_width="wrap_content"  
    17.         android:layout_height="wrap_content"  
    18.         android:layout_above="@id/id_game2048"  
    19.         android:layout_centerHorizontal="true"  
    20.         android:layout_marginBottom="20dp"  
    21.         android:background="#EEE4DA"  
    22.         android:orientation="horizontal" >  
    23.   
    24.         <TextView  
    25.             android:id="@+id/id_score"  
    26.             android:layout_width="wrap_content"  
    27.             android:layout_height="wrap_content"  
    28.             android:padding="4dp"  
    29.             android:text="Score: 0"  
    30.             android:textColor="#EA7821"  
    31.             android:textSize="30sp"  
    32.             android:textStyle="bold" />  
    33.     </LinearLayout>  
    34.   
    35. </RelativeLayout>  

    2、MainActivity

    [java] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. package com.zhy.game2048;  
    2.   
    3. import android.app.Activity;  
    4. import android.app.AlertDialog;  
    5. import android.content.DialogInterface;  
    6. import android.content.DialogInterface.OnClickListener;  
    7. import android.os.Bundle;  
    8. import android.widget.TextView;  
    9.   
    10. import com.zhy.game2048.view.Game2048Layout;  
    11. import com.zhy.game2048.view.Game2048Layout.OnGame2048Listener;  
    12.   
    13. public class MainActivity extends Activity implements OnGame2048Listener  
    14. {  
    15.     private Game2048Layout mGame2048Layout;  
    16.   
    17.     private TextView mScore;  
    18.   
    19.     @Override  
    20.     protected void onCreate(Bundle savedInstanceState)  
    21.     {  
    22.         super.onCreate(savedInstanceState);  
    23.         setContentView(R.layout.activity_main);  
    24.   
    25.         mScore = (TextView) findViewById(R.id.id_score);  
    26.         mGame2048Layout = (Game2048Layout) findViewById(R.id.id_game2048);  
    27.         mGame2048Layout.setOnGame2048Listener(this);  
    28.     }  
    29.   
    30.     @Override  
    31.     public void onScoreChange(int score)  
    32.     {  
    33.         mScore.setText("SCORE: " + score);  
    34.     }  
    35.   
    36.     @Override  
    37.     public void onGameOver()  
    38.     {  
    39.         new AlertDialog.Builder(this).setTitle("GAME OVER")  
    40.                 .setMessage("YOU HAVE GOT " + mScore.getText())  
    41.                 .setPositiveButton("RESTART", new OnClickListener()  
    42.                 {  
    43.                     @Override  
    44.                     public void onClick(DialogInterface dialog, int which)  
    45.                     {  
    46.                         mGame2048Layout.restart();  
    47.                     }  
    48.                 }).setNegativeButton("EXIT", new OnClickListener()  
    49.                 {  
    50.   
    51.                     @Override  
    52.                     public void onClick(DialogInterface dialog, int which)  
    53.                     {  
    54.                         finish();  
    55.                     }  
    56.                 }).show();  
    57.     }  
    58.   
    59. }  


    很简单,代码主要就是设置个接口,当发生加分已经游戏结束时会交给Activity去处理~~~如果喜欢,你可以在一个界面放4个游戏~~~

    当然了游戏Item的个数也可以动态设置~~~最后贴一个5*5游戏的截图~~

    好了,2048到此结束,拿只笔开始设计,然后根据自定义View的经验去写,相信你可以学会不少东西~~~

    并且我们的View是抽取出来的,其实换成图片也很简单~~

    今天又看了war3十大经典战役,献上war3版,代码就不贴了,改动也就几行代码,贴个截图,纪念我们曾经的war3~~~:

    额,咋都弄成5*5了~大家可以把mColumn改为4~~~

    2048源码点击下载

    war3版2048点击下载

  • 相关阅读:
    计算机图形学学习方法和相关书籍,做游戏,GIS,虚拟现实,三维引擎的都能够看看.
    HDU 1248 寒冰王座(全然背包:入门题)
    android widget 开发实例 : 桌面便签程序的实现具体解释和源代码 (上)
    Oracle varchar 字段排序问题
    Response.AddHeader使用实例
    Unity 3D 文件导入出错
    Sencha app build 出现 missing name after . operator 问题
    TFS(Team Foundation Server)介绍和入门
    较具体的介绍JNI
    Struts2学习笔记1
  • 原文地址:https://www.cnblogs.com/dongweiq/p/4806574.html
Copyright © 2011-2022 走看看