星空网 > 软件开发 > 操作系统

Android 之 2048 的游戏逻辑分析

 

继续学习了极客学院的实战路径课程,讲到了2048游戏的编写过程,我在这里作个总结分享给大家(结果会附源代码和我改写后的代码):

这里主要包括两个方面:1.2048界面的绘制   2.2048算法逻辑的实现   3.添加随机数  4.判断游戏结束

先看效果图(真机上模拟图):

 Android 之 2048 的游戏逻辑分析images/loading.gif' data-original="http://images2015.cnblogs.com/blog/671549/201510/671549-20151013090719710-2020473484.png" />

1.界面的绘制

界面的绘制相对还是比较简单的。先新建一个card卡片类,这个类主要是描述在效果图中那16个小方块

/* * 这个类主要用来初始化2048游戏中的方块 */public class Card extends FrameLayout{  private TextView lable;  public Card(Context context) {    super(context);    lable = new TextView(getContext());    lable.setTextSize(32);    lable.setGravity(Gravity.CENTER);    lable.setBackgroundColor(0X30FFFFFF);  //30表示透明度,透明度范围是00-ff,后六位是颜色值        //下面设置了Layout_wight和Layout_height分别为match_parent(-1代表match_parent,-2代表wrap_content)    LayoutParams lp = new LayoutParams(-1,-1);    lp.setMargins(10, 10, 10, 10);   //设置card的间距    addView(lable,lp);    setNum(0);  }  int num = 0;  public int getNum(){    return num;  }  public void setNum(int num) {    this.num = num;    //当cardMap[][]<=0时,设为""    if (num<=0) {      lable.setText("");    }else {      lable.setText(num+"");    }  }  public boolean equals(Card o) {    return getNum()==o.getNum();  }}

 

然后新建一个GameView的主类,使它继承GirdLayout,复写其中的方法。再在此之前需要更改一下main_activity布局文件,包括计分的一个textView,和在外面实现的布局。

<LinearLayout   ="http://schemas.android.com/tools"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical"  tools:context="com.example.game1024.MainActivity" >  <LinearLayout     android:layout_width="match_parent"    android:layout_height="wrap_content"    android:orientation="vertical">        <TextView       android:layout_width="wrap_content"      android:layout_height="match_parent"      android:layout_gravity="center_vertical"      android:textSize="20sp"      android:text="score:"/>    <TextView       android:id="@+id/cvScore"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:textSize="20sp"       />  </LinearLayout>    <com.example.game1024.GameView    android:background="#00ff00"    android:layout_width="match_parent"    android:layout_height="0dp"    android:layout_weight="1">    </com.example.game1024.GameView></LinearLayout>

 

public class GameView extends GridLayout{  public GameView(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    initGame();  }  public GameView(Context context, AttributeSet attrs) {    super(context, attrs);    initGame();  }  public GameView(Context context) {    super(context);    initGame();  }    public void initGame(){    setColumnCount(4); //设定规定行数为四行    setBackgroundColor(0XffF4A460);        setOnTouchListener(new View.OnTouchListener() {            private float startX,startY,offsetX,offsetY;      @Override      public boolean onTouch(View v, MotionEvent event) {        switch (event.getAction()) {        case MotionEvent.ACTION_DOWN:          //取得点击时的初始坐标          System.out.println("00000");          startX = event.getX();          startY = event.getY();          break;        case MotionEvent.ACTION_UP:          //求得各方向的偏移量          System.out.println("0--0");          offsetX = event.getX() - startX;          offsetY = event.getY() - startY;          /*           * 比较在x轴和y轴的偏移量,可以判断为上下滑动,还是左右滑动           * 接着判断偏移量的正负,来判断是具体向哪个方向的滑动           * 下面我写移动的顺序为:向左,右,上,下           */          if (Math.abs(offsetX)>Math.abs(offsetY)) {            //当移动的距离大于5dp时才看作移动            if (offsetX<-5) {              swipeLeft();            }else if (offsetX>5) {              swipeRight();            }          }else if (Math.abs(offsetX)<Math.abs(offsetY)) {            if (offsetY<-5) {              swipeUp();            }else if (offsetY>5) {              swipeDown();            }          }          break;        default:          break;        }        return true;      }    });  }  /*   * (non-Javadoc)   * @see android.view.View#onSizeChanged(int, int, int, int)   * 当屏幕的宽高改变时,卡片所占的宽高会随之改变   */  @Override  protected void onSizeChanged(int w, int h, int oldw, int oldh) {    super.onSizeChanged(w, h, oldw, oldh);        int cardWidth =(Math.min(w, h)-10)/4;    addCard(cardWidth, cardWidth);        startGame();  }  //建立一个数组用于存储各个卡片的num  private Card cardMap[][] = new Card[4][4];  /*   * 添加card卡片的方法   */  private void addCard(int cardwidth, int cardheight){    Card c;    for (int y = 0; y < 4; y++) {      for (int x = 0; x < 4; x++) {        c = new Card(getContext());        c.setNum(0);        addView(c,cardwidth,cardheight);        cardMap[x][y]=c;      }    }  }

2.游戏逻辑的算法

这个注释比较清楚,大家看注释吧 ,if(judge)是后面要判断游戏结束时用的

/*   * 移动方面的算法   */  private void swipeLeft(){    boolean judge = false;    for (int y = 0; y < 4; y++) {      for (int x = 0; x < 4; x++) {                for (int x1 = x+1; x1 < 4; x1++) {             //先判断在当前点的右边是否存在num大于零的点,如果是,进行下一步,否的话继续循环
              //判断当前点是否为空(小于等于零相当于空,在card类中已经设置为了不显示),为空:将右面的点赋予当前点,同时自身置零。不为空的话判断当前点是否和               
              //右面的点相等,相等将当前点的num乘2,并将右面的点置零
  if (cardMap[x1][y].getNum()>0) { if (cardMap[x][y].getNum()<=0) { cardMap[x][y].setNum(cardMap[x1][y].getNum()); cardMap[x1][y].setNum(0); /* * 假如在第1个位置有一个数,它将移动到第0个位置,此时继续循环,如果第2个位置也有数, * 此时因为第0个位置已经存在了数值,所以第2个位置的数不会移动到第一个空白位置,而是保持不变 * 因此需要将x减1,在比较一遍 */ x--; judge = true; }else if (cardMap[x][y].getNum()==cardMap[x1][y].getNum()) { cardMap[x][y].setNum(cardMap[x][y].getNum()*2); cardMap[x1][y].setNum(0); MainActivity.getMainActivity().addScore(cardMap[x][y].getNum()); judge = true; } break; } } } } if (judge) { checkGame(); addRandom(); } } private void swipeRight(){ boolean judge = false; for (int y = 0; y < 4; y++) { for (int x = 3; x >= 0; x--) { for (int x1 = x-1; x1 >=0; x1--) { if (cardMap[x1][y].getNum()>0) { if (cardMap[x][y].getNum()<=0) { cardMap[x][y].setNum(cardMap[x1][y].getNum()); cardMap[x1][y].setNum(0); x++; judge = true; }else if (cardMap[x][y].getNum()==cardMap[x1][y].getNum()) { cardMap[x][y].setNum(cardMap[x][y].getNum()*2); cardMap[x1][y].setNum(0); MainActivity.getMainActivity().addScore(cardMap[x][y].getNum()); judge = true; } break; } } } } if (judge) { checkGame(); addRandom(); } } private void swipeUp(){ boolean judge = false; for (int x = 0; x < 4; x++) { for (int y = 0; y <4; y++) { for (int y1 = y+1 ; y1 <4 ; y1++) { if (cardMap[x][y1].getNum()>0) { if (cardMap[x][y].getNum()<=0) { cardMap[x][y].setNum(cardMap[x][y1].getNum()); cardMap[x][y1].setNum(0); y--; judge = true; }else if (cardMap[x][y].getNum()==cardMap[x][y1].getNum()) { cardMap[x][y].setNum(cardMap[x][y].getNum()*2); cardMap[x][y1].setNum(0); MainActivity.getMainActivity().addScore(cardMap[x][y].getNum()); judge = true; } break; } } } } if (judge) { checkGame(); addRandom(); } } private void swipeDown(){ boolean judge = false; for (int x = 0; x < 4; x++) { for (int y = 3; y >=0; y--) { for (int y1 = y-1 ; y1 >=0; y1--) { if (cardMap[x][y1].getNum()>0) { if (cardMap[x][y].getNum()<=0) { cardMap[x][y].setNum(cardMap[x][y1].getNum()); cardMap[x][y1].setNum(0); y++; judge = true; }else if (cardMap[x][y].getNum()==cardMap[x][y1].getNum()) { cardMap[x][y].setNum(cardMap[x][y].getNum()*2); cardMap[x][y1].setNum(0); MainActivity.getMainActivity().addScore(cardMap[x][y].getNum()); judge = true; } break; } } } } if (judge) { checkGame(); addRandom(); } }

3.添加随机出现的点:

同样在GameView中添加方法,startGame()在onSizeChanged()方法中调用

/*   * 游戏开始的初始化方法   */  private void startGame(){    MainActivity.getMainActivity().clearScore();    for (int y = 0; y < 4; y++) {      for (int x = 0; x < 4; x++) {        cardMap[x][y].setNum(0);      }    }      addRandom();    addRandom();  }    private List<Point> emptyPoint =new ArrayList<Point>();  //添加随机数的方法  private void addRandom(){    emptyPoint.clear();    for (int y = 0; y < 4; y++) {      for (int x = 0; x < 4; x++) {        //将cardMap中小于0的点放在emptyPoint中        if (cardMap[x][y].getNum()<=0) {          emptyPoint.add(new Point(x, y));        }      }    }    //随机移除emptyPoint中的一个单元    Point p = emptyPoint.remove((int)(Math.random()*emptyPoint.size()));    cardMap[p.x][p.y].setNum(Math.random()>0.1?2:4);  }

4.判断游戏结束

/*   * 结束游戏方法   * 当存在点和旁边的数相等时,游戏就不会提示已经结束   */    private void checkGame(){      boolean check = true;      ALL:      for (int y = 0; y < 4; y++) {        for (int x = 0; x < 4; x++) {          if (cardMap[x][y].getNum()==0||              x>0&&cardMap[x][y].equals(cardMap[x-1][y])||              x<3&&cardMap[x][y].equals(cardMap[x+1][y])||              y>0&&cardMap[x][y].equals(cardMap[x][y-1])||              y<3&&cardMap[x][y].equals(cardMap[x][y+1])) {            check = false;            break ALL;          }        }      }             // 提示游戏失败      if (check) {        new AlertDialog.Builder(getContext()).setTitle("提示").setMessage("游戏失败").setPositiveButton("再来一次", new DialogInterface.OnClickListener() {                    @Override          public void onClick(DialogInterface dialog, int which) {            startGame();          }        }).show();      }    }

 

我改进的2048:

1.增加了最高分显示

2.增加了重新开始游戏按钮

3.增加了颜色变化

Game1024原版:http://pan.baidu.com/s/1sjpCdIl

Game2048改进版地址:http://pan.baidu.com/s/1o6qyfJc

 




原标题:Android 之 2048 的游戏逻辑分析

关键词:Android

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

外媒:亚马逊将通过电商平台11街切入韩国市场:https://www.kjdsnews.com/a/556706.html
2021美国返校季销售趋势报告:https://www.kjdsnews.com/a/556707.html
eBay与泰案联达成战略合作,升级中国汽配出海之路:https://www.kjdsnews.com/a/556708.html
亚马逊将在德国市场加码!新建8个仓库,招聘3000名员工!:https://www.kjdsnews.com/a/556709.html
亚马逊自配送订单"预付费退货标签计划"解读:https://www.kjdsnews.com/a/556710.html
亚马逊照明品类月销售超100万美元是如何做到的?:https://www.kjdsnews.com/a/556711.html
美众议院对TikTok“动手”,下一步该怎么在TikTok上营销?:https://www.kjdsnews.com/a/1836587.html
速卖通在韩国争议不断,投诉量激增两倍:https://www.kjdsnews.com/a/1836588.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流