热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Android编写2048小游戏

这篇文章主要为大家详细介绍了利用Android编写一个2048小游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

先来说说2048游戏规则:

开始时棋盘内随机出现两个数字,出现的数字仅可能为2或4

玩家可以选择上下左右四个方向,若棋盘内的数字出现位移或合并,视为有效移动

玩家选择的方向上若有相同的数字则合并,每次有效移动可以同时合并,但不可以连续合并

合并所得的所有新生成数字想加即为该步的有效得分

玩家选择的方向行或列前方有空格则出现位移

每有效移动一步,棋盘的空位(无数字处)随机出现一个数字(依然可能为2或4)

棋盘被数字填满,无法进行有效移动,判负,游戏结束

棋盘上出现2048,判胜,游戏结束

下面代码

MainActivity类

public class MainActivity extends AppCompatActivity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(new GameView(this));
 }
}

定义一个卡片类显示数据

/卡片类型
public class Card extends FrameLayout {

 //2
 TextView tv;

 private int number = 0;
 int width;

 public Card(Context context, int width) {
 super(context);
 this.width = width;
 init();
 }


 private void init() {
 tv = new TextView(getContext());
 setPadding(5, 5, 5, 5);
 FrameLayout.LayoutParams lp = new LayoutParams(width - 10, width - 10);
 tv.setLayoutParams(lp);
 tv.setGravity(Gravity.CENTER);
 tv.setTextColor(Color.WHITE);
 tv.setTextSize(48);
 this.addView(tv);
 setColor();
 }

 public void setNumber(int number) {
 this.number = number;
 if (number == 0)
  tv.setText("");
 else
  tv.setText(number + "");
 setColor();
 }

 @Override
 public String toString() {
 return "Card{" +
  "tv=" + tv +
  ", number=" + number +
  ", width=" + width +
  '}';
 }

 private void setColor() {
 switch (number) {
  case 0:
  tv.setBackgroundColor(getResources().getColor(R.color.c0));
  break;
  case 2:
  tv.setBackgroundColor(getResources().getColor(R.color.c2));
  break;
  case 4:
  tv.setBackgroundColor(getResources().getColor(R.color.c4));
  break;
  case 8:
  tv.setBackgroundColor(getResources().getColor(R.color.c8));
  break;
  case 16:
  tv.setBackgroundColor(getResources().getColor(R.color.c16));
  break;
  case 32:
  tv.setBackgroundColor(getResources().getColor(R.color.c32));
  break;
  case 64:
  tv.setBackgroundColor(getResources().getColor(R.color.c64));
  break;
  case 128:
  tv.setBackgroundColor(getResources().getColor(R.color.c128));
  break;
  case 256:
  tv.setBackgroundColor(getResources().getColor(R.color.c256));
  break;
  case 512:
  tv.setBackgroundColor(getResources().getColor(R.color.c512));
  break;
  case 1024:
  tv.setBackgroundColor(getResources().getColor(R.color.c1024));
  break;
  case 2048:
  tv.setBackgroundColor(getResources().getColor(R.color.c2048));
  break;
 }
 }

 public int getNumber() {
 return number;
 }

}

自己定义一下上面的几种颜色 在values下的colors中

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 #3F51B5
 #303F9F
 #FF4081

 #43382a
 #2a8618
 #3d6319
 #F2B179
 #F59563
 #F57C5F
 #5b69b7
 #b37d3e
 #3a9096
 #d7882c
 #5c1b78
 #640548



布局类 和里面的运算方法

public class GameView extends GridLayout {

 int[][] values = new int[4][4];


 Card[][] cards = new Card[4][4];


// Integer -128-127 == 大于这个数 两个对象


 public GameView(Context context) {
 super(context);
 init();
 }

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


 private void init() {
 setColumnCount(4);
 }


 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 super.onSizeChanged(w, h, oldw, oldh);
 newGame();
 }

 private void newGame() {
 //ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams((int) (getResources().getDisplayMetrics().widthPixels / 4), (int) (getResources().getDisplayMetrics().widthPixels / 4));
 GridLayout.LayoutParams params = new GridLayout.LayoutParams();
// params.width = getResources().getDisplayMetrics().widthPixels / 4;
// params.height = getResources().getDisplayMetrics().widthPixels / 4;
 //Log.e("TAG", params.width + " " + params.height);
 this.removeAllViews();
 // GridLayout.LayoutParams lpa = new GridLayout.LayoutParams(lp);
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  values[i][j] = 0;
  cards[i][j] = new Card(getContext(), getResources().getDisplayMetrics().widthPixels / 4);
  // cards[i][j].setLayoutParams(params);
  //cards[i][j].upLv();
  this.addView(cards[i][j]);
  }
 }
 //创建初始的两张卡
 int i = (int) (Math.random() * 16);
 int j = 0;
 do {
  j = (int) (Math.random() * 16);//0-15 15 3 3
 } while (j == i);
 Log.e("TAG", i + " " + j);
 values[i / 4][i % 4] = Math.random() * 20 <1 &#63; 4 : 2;
 values[j / 4][j % 4] = Math.random() * 20 <1 &#63; 4 : 2;
 setValues();
 }


 float oldx, oldy;
 int move = -1;


 @Override
 public boolean onTouchEvent(MotionEvent event) {
 float x = event.getX();
 float y = event.getY();
 switch (event.getAction()) {
  case MotionEvent.ACTION_DOWN:
  move = -1;
  oldx = x;
  oldy = y;
  break;
  case MotionEvent.ACTION_MOVE:
  if (Math.abs(oldx - x) > Math.abs(oldy - y)) {
   if (oldx - x > 15) { //左
   Log.e("TAG", "---------->>>");
   move = 1;
   } else if (oldx - x <-15) {//右
   Log.e("TAG", "---------->>>");
   move = 2;
   }
  } else {
   if (oldy - y > 15) {
   move = 3;
   } else if (oldy - y <-15) {
   move = 4;
   }
  }
  break;
  case MotionEvent.ACTION_UP:
  //记录之前的数组
  int[][] temp = new int[4][4];
  for (int i = 0; i <4; i++) {
   for (int j = 0; j <4; j++) {
   temp[i][j] = values[i][j];
   }
  }
  switch (move) {
   case 1:
   left();
   break;
   case 2:
   right();
   break;
   case 3:
   up();
   break;
   case 4:
   down();
   break;
  }
  setValues();
  if (move != -1) {
   //比对当前的数组
   for (int i = 0; i <4; i++) {
   for (int j = 0; j <4; j++) {
    if (values[i][j] != temp[i][j]) {
    addCard();
    return true;
    }
   }
   }
  }
  //判断游戏胜利还是结束4
  if (isWin()) {
   Toast.makeText(getContext(), "游戏胜利", Toast.LENGTH_SHORT).show();
  }
  if (isOver()) {
   this.removeAllViews();
   TextView tv = new TextView(getContext());
   tv.setText("游戏结束,点击从新开始");
   this.addView(tv);
   tv.setOnClickListener(new OnClickListener() {
   @Override
   public void onClick(View v) {
    newGame();
   }
   });
  }
  break;
 }
 return true;
 }

 private void addCard() {
 while (true) {
  int j = (int) (Math.random() * 16);
  if (values[j / 4][j % 4] == 0) {
  values[j / 4][j % 4] = 2;
  cards[j / 4][j % 4].setNumber(2);
  return;
  }
 }
 }

 public void left() {

 //取出 4个 集合
 for (int i = 0; i <4; i++) {
  List list = new ArrayList<>();
  for (int j = 0; j <4; j++) {
  int value = values[i][j];
  if (value != 0)
   list.add(value);
  }
  //比较
  Log.e("TAG", list.toString());
  if (list.size() == 0)
  continue;
  else if (list.size() == 1) {
  values[i][0] = list.get(0);
  for (int j = 0; j <3; j++) {
   values[i][j + 1] = 0;
  }
  } else if (list.size() == 2) {
  if (list.get(0).equals(list.get(1))) {
   values[i][0] = list.get(0) * 2;
   //三个值补0
   for (int j = 0; j <3; j++) {
   values[i][j + 1] = 0;
   }
  } else {
   values[i][0] = list.get(0);
   values[i][1] = list.get(1);
   values[i][2] = 0;
   values[i][3] = 0;
  }
  } else if (list.size() == 3) {
  if (list.get(0).equals(list.get(1))) {
   values[i][0] = list.get(0) * 2;
   values[i][1] = list.get(2);
   values[i][2] = 0;
   values[i][3] = 0;
  } else if (list.get(1).equals(list.get(2))) {
   values[i][0] = list.get(0);
   values[i][1] = list.get(2) * 2;
   values[i][2] = 0;
   values[i][3] = 0;
  } else {
   values[i][0] = list.get(0);
   values[i][1] = list.get(1);
   values[i][2] = list.get(2);
   values[i][3] = 0;
  }
  } else {
  if (list.get(0).equals(list.get(1))) {
   if (list.get(3).equals(list.get(2))) {
   values[i][0] = list.get(0) * 2;
   values[i][1] = list.get(2) * 2;
   values[i][2] = 0;
   values[i][3] = 0;
   } else {
   values[i][0] = list.get(0) * 2;
   values[i][1] = list.get(2);
   values[i][2] = list.get(3);
   values[i][3] = 0;
   }
  } else {
   //1和2不相等
   //先比对2 3 相等,不等
   if (list.get(1).equals(list.get(2))) {
   values[i][0] = list.get(0);
   values[i][1] = list.get(1) * 2;
   values[i][2] = list.get(3);
   values[i][3] = 0;
   } else {
   if (list.get(2).equals(list.get(3))) {
    values[i][0] = list.get(0);
    values[i][1] = list.get(1);
    values[i][2] = list.get(2) * 2;
    values[i][3] = 0;
   }
   }
  }
  }
 }

 }

 private void delete() {
 // Log.e("TAG", "--------------------执行");
// //遍历
// for (int i = 0; i <4; i++) {
//  for (int j = 0; j <3; j++) {
//  Card card = cards[i][j];
//  Log.e("TAG", "i:" + i + " j:" + j + " num:" + card.getNumber());
//  if (card.getNumber() == 0) {
//   boolean isSub = false;
//   for (int k = j; k <3; k++) {
//   cards[i][k].setNumber(cards[i][k + 1].getNumber());
//   if (cards[i][k + 1].getNumber() != 0) {
//    isSub = true;
//   }
//   }
//   if (isSub)
//   j--;
//   cards[i][3].setNumber(0);
//  } else if (card.getNumber() == cards[i][j + 1].getNumber()) {
//   card.upLv();
//   cards[i][j + 1].setNumber(0);
//   //后面的往前搬
//   for (int k = j + 1; k <3; k++) {
//   cards[i][k].setNumber(cards[i][k + 1].getNumber());
//   }
//   cards[i][3].setNumber(0);
//   j--;
//  }
//  }
// }


// for (int j = 0; j <4; j++) { //列
//  for (int i = 3; i >= 1; i--) {
//  Card card = cards[j][i];
//  if (card.getNumber() == 0) {
//   //全行左移
//   //要将
//   //如果是最后一个,不需要理会
//   continue;
//  } else {
//   //判断左边一个
//   if (cards[j][i - 1].getNumber() == 0) {
//   //从i --》i-1
//   for (int k = i - 1; k <3; k++) {
//    cards[j][k].setNumber(cards[j][k + 1].getNumber());
//   }
//   cards[j][3].setNumber(0);
//
//   } else if (cards[j][i - 1].getNumber() == card.getNumber()) {
//   cards[j][i - 1].upLv();
//   card.setNumber(0);
//   for (int k = i; k <3; k++) {
//    cards[j][k].setNumber(cards[j][k + 1].getNumber());
//   }
//   cards[j][3].setNumber(0);
//   }
//  }
//  }
// }
 }

 public void right() {
 mirrorH();
 left();
 mirrorH();
 }

 private void mirrorH() {
 for (int i = 0; i <4; i++) {
  int temp = values[i][0];
  values[i][0] = values[i][3];
  values[i][3] = temp;
  temp = values[i][1];
  values[i][1] = values[i][2];
  values[i][2] = temp;
 }
 }

 public void down() {
 //左旋
 int[][] temp = new int[4][4];
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  temp[i][j] = values[3 - j][i];
  }
 }
 values = temp;
 left();
 temp = new int[4][4];
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  temp[i][j] = values[j][3 - i];
  }
 }
 values = temp;
 }

 public void up() {
 mirrorV();
 down();
 mirrorV();
 }

 private void mirrorV() {
 for (int j = 0; j <4; j++) {
  int temp = values[0][j];
  values[0][j] = values[3][j];
  values[3][j] = temp;
  temp = values[1][j];
  values[1][j] = values[2][j];
  values[2][j] = temp;
 }
 }


 public void setValues() {
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  System.out.print(values[i][j] + " ");
  cards[i][j].setNumber(values[i][j]);
  }
  System.out.println();
 }

 }


 public boolean isWin() {
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  if (values[i][j] == 2048)
   return true;
  }
 }
 return false;
 }

 public boolean isOver() {
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  if (values[i][j] == 0)
   return false;
  }
 }
 //满了
 for (int i = 0; i <4; i++) {
  for (int j = 0; j <4; j++) {
  int value = values[i][j];
  if (i > 1 && value == values[i - 1][j])
   return false;
  else if (i <3 && value == values[i + 1][j])
   return false;
  else if (j > 1 && value == values[i][j - 1])
   return false;
  else if (j <3 && value == values[i][j + 1])
   return false;
  }
 }
 return true;
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • flowable工作流 流程变量_信也科技工作流平台的技术实践
    1背景随着公司业务发展及内部业务流程诉求的增长,目前信息化系统不能够很好满足期望,主要体现如下:目前OA流程引擎无法满足企业特定业务流程需求,且移动端体 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了在使用MSXML解析XML文件时出现DTD禁用问题的解决方案。通过代码示例和错误信息获取方法,解释了默认情况下DTD是禁用的,以及如何启用DTD的方法。此外,还提到了网上关于该问题的信息相对较少,因此本文提供了解决方案以供参考。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • MyBatis多表查询与动态SQL使用
    本文介绍了MyBatis多表查询与动态SQL的使用方法,包括一对一查询和一对多查询。同时还介绍了动态SQL的使用,包括if标签、trim标签、where标签、set标签和foreach标签的用法。文章还提供了相关的配置信息和示例代码。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文是关于自学Android的笔记,包括查看类的源码的方法,活动注册的必要性以及布局练习的重要性。通过学习本文,读者可以了解到在自学Android过程中的一些关键点和注意事项。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • 本文讨论了如何在codeigniter中识别来自angularjs的请求,并提供了两种方法的代码示例。作者尝试了$this->input->is_ajax_request()和自定义函数is_ajax(),但都没有成功。最后,作者展示了一个ajax请求的示例代码。 ... [详细]
  • 突破MIUI14限制,自定义胶囊图标、大图标样式,支持任意APP
    本文介绍了如何突破MIUI14的限制,实现自定义胶囊图标和大图标样式,并支持任意APP。需要一定的动手能力和主题设计师账号权限或者会主题pojie。详细步骤包括应用包名获取、素材制作和封包获取等。 ... [详细]
  • 网络请求模块选择——axios框架的基本使用和封装
    本文介绍了选择网络请求模块axios的原因,以及axios框架的基本使用和封装方法。包括发送并发请求的演示,全局配置的设置,创建axios实例的方法,拦截器的使用,以及如何封装和请求响应劫持等内容。 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
author-avatar
海纳百川2602902033
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有