上个星期杭州这边突然刮起台风,无奈回不了公司上班,所以窝在宿舍无聊,想起之前看过一些2048的视频还有教程,手动写了一个2048的小游戏,在此分享下。先上图看看效果:

这个游戏其实比较简单,重点的部分主要有3个:UI界面实现、游戏逻辑控制还有数据存储。当然完成的游戏中还有包括语音播放等等,这里不做具体的说明。

UI界面设计与实现

由于个人比较喜欢简洁的风格,所以UI被我做成是浅淡色彩加扁平风格。其中包括两个分数(一个当前分数,一个历史分数)的显示,“New Game”按钮还有4x4的游戏主布局,当然为了更人性化一点还加了游戏声音。
思路:整个布局是一个LinearLayout(个人比较习惯,当然4.0以后谷歌推崇RelativeLayout),常规的TextView+Button,主要游戏布局采用的是GridLayout,典型的方阵布局。当然由于我们在这个布局上会进行手势的监听,所以原生的GridLayout并不能满足我们的需求,所以我们重写了一个GridLayout。整个布局代码如下:
<span style="font-family:SimHei;font-size:18px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:layout_margin="10dp"><LinearLayoutandroid:layout_marginTop="20dp"android:layout_width="fill_parent"android:layout_height="60dp"android:orientation="horizontal"><LinearLayoutandroid:layout_height="fill_parent"android:layout_width="0dp"android:layout_weight="1"android:orientation="vertical"android:background="@drawable/sorce_bg"><TextViewandroid:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"android:text="Sorce"android:gravity="center"android:textSize="20sp"android:textColor="#FFF8DC"/><TextViewandroid:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/id_sorce"android:gravity="center_horizontal"android:textSize="20sp"android:textColor="#ffffff"android:text="0" /></LinearLayout><LinearLayoutandroid:layout_height="fill_parent"android:layout_width="0dp"android:layout_weight="0.1"android:orientation="vertical"></LinearLayout><LinearLayoutandroid:layout_height="fill_parent"android:layout_width="0dp"android:layout_weight="1"android:orientation="vertical"android:background="@drawable/sorce_bg"><TextViewandroid:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"android:text="MaxSorce"android:gravity="center"android:textSize="20sp"android:textColor="#FFF8DC" /><TextViewandroid:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/id_maxsorce"android:gravity="center_horizontal"android:textSize="20sp"android:textColor="#ffffff"android:text="0" /></LinearLayout></LinearLayout><LinearLayoutandroid:layout_marginTop="10dp"android:layout_width="fill_parent"android:layout_height="40dp"android:orientation="horizontal"><Buttonandroid:layout_margin="5dp"android:background="@drawable/bt_sound"android:id="@+id/id_sound"android:layout_width="30dp"android:layout_height="30dp"/><Buttonandroid:background="@drawable/bt_start"android:layout_marginLeft="10dp"android:id="@+id/id_newStart"android:layout_width="0dp"android:layout_weight="1"android:layout_height="fill_parent"android:text="New   Game"android:textSize="15sp"android:textColor="#ffffff"/></LinearLayout><com.example.yummy.game2048.GameViewandroid:layout_marginTop="10dp"android:id="@+id/id_gameView"android:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"/></LinearLayout>
</span>
其中GameView采用height=“0dp”、weight=“1”及width=“fill_parent”是为了填充满剩余的区域,这是一个比较常用的布局分布技巧。TextView和Button都采用自定义样式,比如“New Game”按钮样式如下:(更多的代码可在博客最下方项目链接进行下载参考)
<span style="font-family:SimHei;font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle" ><gradientandroid:endColor="#bbada0"android:startColor="#bbada0" /><cornersandroid:bottomLeftRadius="8dp"android:bottomRightRadius="8dp"android:topLeftRadius="8dp"android:topRightRadius="8dp" /><strokeandroid:width="1dip"android:color="#bbada0" /></shape>
</span>

个人认为,学习Android开发selector和shape样式定义是必须学会的,这有利于我们开发各式各样的界面布局。

游戏逻辑控制

整个项目的逻辑包括很多:用户启动和退出项目逻辑,声音控制逻辑,分数存储逻辑,游戏过程手势判断与计分逻辑。其中我对于2048启动直接进入界面不需要任何动画与代码判断,退出的时候可重写 onKeyDown方法来实现监听返回键。而声音控制则判断用户点击声控按钮,在程序初始化的时候就产生MediaPlayer对象,并根据用户的手势结果来播放对应的音频文件;当用户点击静音的时候则使用AudioManager对象来实现静音。第三个分数的存储放到第三点来讲,每个应用都会涉及数据存储,我们都应该独立分开并进行模块的复用。而最后一个是我们要主讲的点,是这个游戏的难点。
上面我们说了,由于功能的需要我们需要重写GridLayout,我们继承它来实现我们自己的GameView。我们的主逻辑是:先初始化好GameView中4x4的布局,然后重写手势监听来根据用户手势进行布局的样式改变(比如说我滑动之后每一格上的样式应该怎么改变),最后再补全一些边缘的功能(比如说声控,样式的美化等等)。

布置4x4布局

GameView也是一个view,有addview的方法,所以我们应该往GameView中添加16个布局。而每一个布局也是一个view。这里最好是使用帧布局。比如说可以自定义一个Card类来实现,并且可以进行样式的绘制。代码如下:
<span style="font-family:SimHei;font-size:18px;">package com.example.yummy.game2048;import android.content.Context;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;/*** Created by yummy on 2015/7/11.*/
public class Card extends FrameLayout{private int number = 0;private TextView tv;public Card(Context context) {super(context);tv = new TextView(getContext());tv.setTextSize(32);tv.setGravity(Gravity.CENTER);tv.setTextColor(0xffffffff);tv.setBackgroundColor(0xffbbada0);LayoutParams layoutParams = new LayoutParams(-1,-1);layoutParams.setMargins(10,10,0,0);addView(tv,layoutParams);}public int getNumber() {return number;}public void setNumber(int number) {this.number = number;if(number == 0){tv.setText("");}else{tv.setText(number+"");}}@Overridepublic boolean equals(Object o) {return this.getNumber()==((Card)o).getNumber();}
}
</span>

其中重写equal方法主要是为后面合并两个相同的子布局做铺垫。然后在GameView初始化的时候进行16个子布局添加形成游戏布局。代码如下:

<span style="font-family:SimHei;font-size:18px;">        //初始化布局Card card;for( int y = 0; y < 4; y++){for(int x = 0; x < 4; x++){card = new Card(getContext());card.setNumber(0);addView(card,cardSideLenght,cardSideLenght);//添加在记录中cards[x][y] = card;}}</span>

别忘了要设置4列,不然就形成不了4x4方阵

<span style="font-family:SimHei;font-size:18px;">        //设置4列setColumnCount(4);</span>

重写手势监听

主要的逻辑是:根据用户的手指,当触碰到屏幕的时候记录下该点的坐标p1(x1,y1),本次活动离开屏幕的时候记录下手指坐标p2(x2,y2),根据这两个坐标进行相减就可以取绝对值并做比较来判断用户主要滑动的方向是x轴还是y轴,根据轴的差值的正负来判断滑动的方向。代码如下:
<span style="font-family:SimHei;font-size:18px;">//设置手势监听setOnTouchListener(new View.OnTouchListener() {private float startX ,startY,offsetX,offsetY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()){case MotionEvent.ACTION_DOWN:startX = event.getX();startY = event.getY();break;case MotionEvent.ACTION_UP:offsetX = event.getX() - startX;offsetY = event.getY() - startY;//如果x轴偏移比y轴偏移大,则认为x轴有滑动行为而y轴没有滑动行为if(Math.abs(offsetX) > Math.abs(offsetY)){if(offsetX < -5){toLeft();}else if(offsetX > 5){toRight();}else{//滑动距离太小}}else{if(offsetY < -5){toUp();}else if(offsetY > 5){toDowm();}else{//滑动距离太小}}break;}return true;}});</span>

    是不是感觉挺简单的呢?自己也可以做出来吧。只要往哪个方向滑动后,重点来了,就是滑动之后界面会产生什么变化?这里有四个方法toDowm、toUp、toLeft和toRight。
我们以toLeft方法为例来讲解下逻辑。玩过2048的朋友大概很清楚,要么子View会被合并数值变为当前的2倍,那么就被推倒滑动方向的一边。而无论哪一种情况,界面都会产生一个新的数字,要么是2,要么是4。
首先我们需要遍历下这16个格子,当我们的手向左滑的时候(p2←p1),相当于我们把左右带有数值的格子往左边推,我们定义一个格子,该格子就是当前遍历点的相邻右边的格子。那么如果右边的格子为0,那么它和左边的格子合并后还是一样;如果右边的格子不为0呢?第一种情况是数字和遍历点上一样,那么就把遍历点数值x2,清空右边格子数值;第二种情况是遍历点的值为0,那么应该把右边格子的值赋给它并自己清0;第三种就是遍历点也不为0且和右边的不相等,那么不需要任何操作了。先看下代码:
<span style="font-family:SimHei;font-size:18px;"><span style="color:#5a5a5a;">  for(int y = 0; y < 4; y++){for(int x = 0; x < 4; x++){for(int x1 = x+1; x1 < 4; x1++){if(cards[x1][y].getNumber() > 0){//当前位置的值为0,则应该把后面的值放到当前位置上去if(cards[x][y].getNumber() ==0){cards[x][y].setNumber(cards[x1][y].getNumber());cards[x1][y].setNumber(0);</span><span style="color:#ff0000;">  x--;</span><span style="color:#5a5a5a;">flag  =true;mediaPlayer2.start();}else if(cards[x][y].equals(cards[x1][y])){cards[x][y].setNumber(cards[x1][y].getNumber()*2);cards[x1][y].setNumber(0);//计分MainActivity.getMainActivity().addSorce(cards[x][y].getNumber());flag  =true;mediaPlayer1.start();}break;}}}}</span></span>

值得注意的是:当遍历点为0且右边格子不为0,此时合并之后需要再此进行重新遍历,为什么呢?举个例子,当有一行的格子数值为

0202
当x=0的时候 如果按照上述逻辑,变化如下
2002
2020
2200
发现最后是合并不了?原因就是当发现右边不为0合并过来的时候(比如看第二组数据2020),最后一个2从右边合并过来的时候此时x=2,那么就应该让x=1有机会重新计算是否右边能满足合并条件,毕竟x=2的数值已经发生了变化。此时应该执行x--;然后发现第三组(2200)此时x=1发生了合并,那么x--后x为0进行合并后才是正确的结果。
4000(正确结果)
其他方向的逻辑都是一样。更多代码请参考源码

数据存储

数据存储几乎是每个APP都必备的一个模块,2048的数据很少,只需要才每次安装的时候生成一个data文件来记录最高分即可。那么SharedPreferences就是首选。

申明SharedPreferences对象和SharedPreferences.Editor对象并进行get和put的操作就可以了,别忘记Editor的数据操作需要commit来完成哦。代码部分比较简单就不过多叙述。

2048游戏源码下载

github下载链接

CSDN下载链接

周末闲来——2048游戏开发相关推荐

  1. Cocos2d-x 3.x版2048游戏开发

    Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍如何快速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程,从本篇博客你将可以学习到以下内容: 这里注明一下,本教程来自极客学 ...

  2. python实现2048游戏开发笔记

    一.游戏描述 这里省略了(估计来看的人都玩过2048游戏) 二.游戏设计 首先将游戏分解成若干个局部一一实现 (1)输入规则:asdw分别代表左下由上,r为reset,q为退出,其他不执行. (2)输 ...

  3. android2048项目报告,Android项目开发实战-2048游戏

    <2048>是一款比较流行的数字游戏,最早于2014年3月20日发行.原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台.这款游戏是基于&l ...

  4. 微信公众平台开发(100) 2048游戏

    微信开发第100篇了,算上微信支付和微信小店,其实已经超过了,这次完整讲一下2048游戏吧. 一.2048游戏 <2048>是比较流行的一款数字游戏.原版2048首先在github上发布, ...

  5. Excel_VBA开发2048游戏教程——Einsphoton

    VBA对游戏开发的流程帮助甚微,甚至影响游戏开发效率,本应用实例仅为消遣,切勿过分关注! 前言 抱歉,这可能是我最后的几篇文章之一了. 由于最近工作中遇到很多问题,作者现在处于自我检讨中,恐怕以后将要 ...

  6. 华为鸿蒙2048小游戏,《从零开发鸿蒙小游戏App》直播答疑(包含新版2048游戏代码)...

    请到附件中下载新版2048游戏代码.最好能对该代码再做一些优化(见下述问题8),欢迎感兴趣的朋友随时跟我探讨,^_^ 问题1:如何将开发的Lite Wearable项目部署在鸿蒙手表Watch GT2 ...

  7. 基于android的2048游戏设计,基于Android平台的2048游戏设计与开发.docx

    基于Android平台的2048游戏设计与开发 高级操作系统论文(设计) 题 目 基于Android个人2048 小游戏的设计与开发姓 名 学 号 院. 系 信息学院 专 业 指导教师 职称(学历)目 ...

  8. 基于粤嵌gec6818开发板嵌入式开发电子相册,音乐播放,视频播放,2048游戏

    一.功能与要求 实现功能:本系统需要使用粤嵌的GEC-6818开发板设计一款娱乐影音系统,其中包括图片显示(相册).音乐播放.视频播放,游戏四个部分,在每个部分内部,具有操控各个部分的功能触摸按键.本 ...

  9. 使用python开发网页游戏_不敢想!不敢想!我用Python自动玩转2048游戏

    近来在折腾selenium自动化, 感觉配合爬虫很有意思, 大多数以前难以模拟登录的网站都可以爬了,折腾了这么久,于是想自动玩个2048游戏!嘿嘿, 我是一个不擅长玩游戏的人, 以前玩2048就经常得 ...

  10. LibGDX_8.1: LibGDX 项目实战: 开发跨平台 2048 游戏

    本文链接: http://blog.csdn.net/xietansheng/article/details/50188259 LibGDX 基础教程(总目录) 声明: 游戏中使用到的部分图片和音频资 ...

最新文章

  1. div文字自动扩充_文字资料扩充
  2. php服务划分,云计算提供的服务分为哪三个层次
  3. mysql主从配置错误_mysql主从配置失败,主从通讯失败
  4. LeetCode 402. 移掉K位数字(贪心,单调栈)
  5. redhat linux yum仓库,关于RHEL6发行版yum仓库的配置
  6. 从 VC7 的 CHtmlView 不能正常退出谈 CComPtr 使用中的一个误区
  7. Web前端笔记-画布拖动及放缩(two.js)
  8. risc 服务器 操作系统,数据中心系统用RISC还是CISC?
  9. JAVA输入输出IO流→File、RandomAccessFilse、字节流InputSream与OutputStream、字符流Reader与Writer、对象序列化Serializable
  10. BlackBerry 9520上结合139邮箱实现Gmail邮件的短信通知
  11. 【三维路径规划】基于matlab RRT算法无人机三维路径规划【含Matlab源码 155期】
  12. 将element-china-area-data获取的地区编码转为文字存储
  13. 【历史上的今天】1 月 23 日:现代集成电路雏形;JDK 1.0 发布;数学大师诞生
  14. 第十届蓝桥杯大赛个人赛省赛(软件类本科B组)做题笔记Partial
  15. AS3多线程快速入门(三):NAPE物理引擎+Starling[译]
  16. angr入门之CLE
  17. 110种有趣的游戏和应用
  18. java学习笔记—java的学习路线
  19. 空前绝后!PostgresConf.CNPGConf.Asia 2020大会闭幕
  20. UCOSII MailBox

热门文章

  1. 知弥深度清理大师隐私政策
  2. Basler相机参数设置
  3. 深入分析 Spring 基于注解的 AOP 实现原理
  4. 【LuoguP4770】[NOI2018] 你的名字
  5. donet core 应用 部署到CentOS
  6. java生成树型思维导图,Android树形控件绘制方法
  7. 谷歌网页存储为pdf或图片
  8. MATLAB图像处理(一)——计算机图形学之图像形状识别
  9. 机器学习中的核函数与核方法(是什么?为什么?怎么做?)
  10. latex下载安装记录