转载请写明出处:http://blog.csdn.net/big_heart_c

下面所解析的源码是来自极客学院“Android 2048 ”中的源码,读者可以从 https://github.com/plter/Android2048GameLesson 中下载,作者是 ime 。

源码主要由3个 java 方法组成:MainActivity、Card、GameView。MainActivity就不用说了,Card方法是实现每一个小方格的形状、颜色等等,GameView方法主要是处理用户滑动时间、控制游戏界面等等。其实都挺简单的,关键是要耐心的去读,每次读源码,看别人活用书本上的东西,都感觉 unbelievable !自己自然能从中学习不少,这更是书本上学不来的。

首先解析 "Card.java" 文件:

package com.jikexueyuan.game2048;import android.content.Context;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.TextView;public class Card extends FrameLayout {private TextView label;public Card(Context context) {super(context);label = new TextView(getContext());label.setTextSize(32);label.setBackgroundColor(0x33ffffff);   //设置方格背景label.setGravity(Gravity.CENTER);   //使数字居于方格正中LayoutParams lp = new LayoutParams(-1, -1); //使方格自适应屏幕lp.setMargins(10, 10, 0, 0);      //使方格左,上的间距均为10像素addView(label, lp);setNum(0);}private int num = 0;public int getNum() {return num;}public void setNum(int num) {   //定义一个在方格中显示数字的方法供 “GameView.java” 调用this.num = num;if (num<=0) {label.setText("");}else{label.setText(num+"");}}public boolean equals(Card o) {      //定义一个比较方格的数字是否相同的方法供 “GameView.java” 调用return getNum()==o.getNum();}
}

接下来是"GameView.java"文件:

package com.jikexueyuan.game2048;import java.util.ArrayList;
import java.util.List;import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Point;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.GridLayout;public class GameView extends GridLayout {private Card[][] cardsMap    = new Card[4][4];      //用来存储没有数字显示的方格,当其没有数字时,使其值为 0private List<Point>   emptyPoints = new ArrayList<Point>();    // 使用emptyPoints数组来存储没有数字的方格public GameView(Context context, AttributeSet attrs,int defStyle) {super(context, attrs, defStyle);initGameView();}public GameView(Context context) {super(context);initGameView();}public GameView(Context context, AttributeSet attrs) {super(context, attrs);initGameView();}private void initGameView() {setColumnCount(4); // 定义列数,即 4*4 的格子setBackgroundColor(0xffbbada0);setOnTouchListener(new View.OnTouchListener() {private float startX,startY,offsetX,offsetY;  // 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;if (Math.abs(offsetX) > Math // 说明用户是水平方向滑动的.abs(offsetY)) {if (offsetX < -5) { // 设置为“-5”是为了容错,因为数据存储精度原因swipeLeft();}else if (offsetX > 5) {swipeRight();}}else { // 说明用户是竖直方向滑动的if (offsetY < -5) {swipeUp();}else if (offsetY > 5) {swipeDown();}}break;}return true; // 原先是return false,在这里得改成 return true,原因请参照本人转载的一篇博文  http://blog.csdn.net/big_heart_c/article/details/39678439}});}@ Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { // 跟随不同手机的屏幕大小,设置相应每个方格的大小super.onSizeChanged(w, h, oldw, oldh);int cardWidth = (Math.min(w, h) - 10) / 4;addCards(cardWidth, cardWidth);        //向  GameView 界面添加方格startGame();}private void addCards(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);  // 先设置每个格子都是没有数字,即值均为 0addView(c, cardWidth, cardHeight);cardsMap[x][y] = c;}}}private void startGame() {MainActivity.getMainActivity().clearScore();for (int y = 0; y < 4; y++) {for (int x = 0; x < 4; x++) {cardsMap[x][y].setNum(0);}}addRandomNum(); // 开始时先有两个方格有数字addRandomNum();}private void addRandomNum() { // 随机生成下一个数字出现的位置emptyPoints.clear(); // 先清空游戏界面for (int y = 0; y < 4; y++) {for (int x = 0; x < 4; x++) {if (cardsMap[x][y].getNum() <= 0) { // 遍历cardsMap中所有元素,如果其值为// 0,即不需要显示数字的话,则加入emptyPoints中emptyPoints.add(new Point(x, y));}}}Point p = emptyPoints // 随机生成下一个格子的位置,即只需要从emptyPoints中随机挑一个就OK了.remove((int) (Math.random() * emptyPoints.size()));// 使下一个格子出现 4 和2的概率比为 1 9(实际游戏中出现4的概率比较小,这里我们假设它为0.1)cardsMap[p.x][p.y].setNum(Math.random() > 0.1 ? 2 : 4);}private void swipeLeft() { // 处理用户向左滑动的事件boolean merge = false;for (int y = 0; y < 4; y++) {for (int x = 0; x < 4; x++) {for (int x1 = x + 1; x1 < 4; x1++) {   // 每一个方格都比较一下自己右边的数,看能否结合if (cardsMap[x1][y].getNum() > 0) {if (cardsMap[x][y].getNum() <= 0) {cardsMap[x][y].setNum(cardsMap[x1][y].getNum());cardsMap[x1][y].setNum(0);x--;merge = true;}else if (cardsMap[x][y].equals(cardsMap[x1][y])) {cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);cardsMap[x1][y].setNum(0);MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());merge = true;}break;}}}}if (merge) {addRandomNum();checkComplete();  //每次移动都判断游戏是否结束}}private void swipeRight() { // 处理用户向右滑动的事件boolean merge = false;  //判断此次操作是否有合并for (int y = 0; y < 4; y++) {for (int x = 3; x >= 0; x--) {for (int x1 = x - 1; x1 >= 0; x1--) {if (cardsMap[x1][y].getNum() > 0) {if (cardsMap[x][y].getNum() <= 0) {cardsMap[x][y].setNum(cardsMap[x1][y].getNum());cardsMap[x1][y].setNum(0);x++;merge = true;}else if (cardsMap[x][y].equals(cardsMap[x1][y])) {cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);cardsMap[x1][y].setNum(0);MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());merge = true;}break;}}}}if (merge) {       //如果有合并,则再随机添加一个有数字的格子,并检查游戏是否结束addRandomNum();checkComplete();}}private void swipeUp() { // 处理用户向上滑动的事件boolean merge = false;for (int x = 0; x < 4; x++) {for (int y = 0; y < 4; y++) {for (int y1 = y + 1; y1 < 4; y1++) {if (cardsMap[x][y1].getNum() > 0) {if (cardsMap[x][y].getNum() <= 0) {cardsMap[x][y].setNum(cardsMap[x][y1].getNum());cardsMap[x][y1].setNum(0);y--;merge = true;}else if (cardsMap[x][y].equals(cardsMap[x][y1])) {cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);cardsMap[x][y1].setNum(0);MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());merge = true;}break;}}}}if (merge) {addRandomNum();checkComplete();}}private void swipeDown() { // 处理用户向下滑动的事件boolean merge = false;for (int x = 0; x < 4; x++) {for (int y = 3; y >= 0; y--) {for (int y1 = y - 1; y1 >= 0; y1--) {if (cardsMap[x][y1].getNum() > 0) {if (cardsMap[x][y].getNum() <= 0) {cardsMap[x][y].setNum(cardsMap[x][y1].getNum());cardsMap[x][y1].setNum(0);y++;merge = true;}else if (cardsMap[x][y].equals(cardsMap[x][y1])) {cardsMap[x][y].setNum(cardsMap[x][y].getNum() * 2);cardsMap[x][y1].setNum(0);MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());merge = true;}break;}}}}if (merge) {addRandomNum();checkComplete();}}private void checkComplete() { // 判断游戏是否结束boolean complete = true;ALL:// 定义一个ALL标签,是下面双重循环中的break能跳出该双重循环for (int y = 0; y < 4; y++) {for (int x = 0; x < 4; x++) {if (cardsMap[x][y].getNum() == 0 // 如果还有空格子 或// 任意一个格子的上下左右可以合并,即存在相同的数的时候,则游戏继续|| (x > 0 && cardsMap[x][y].equals(cardsMap[x - 1][y]))|| (x < 3 && cardsMap[x][y].equals(cardsMap[x + 1][y]))|| (y > 0 && cardsMap[x][y].equals(cardsMap[x][y - 1]))|| (y < 3 && cardsMap[x][y].equals(cardsMap[x][y + 1]))) {complete = false;break ALL; // 跳出该双重循环}}}if (complete) {      //游戏结束的时候跳出一个dialognew AlertDialog.Builder(getContext()).setTitle("你好").setMessage("游戏结束").setPositiveButton("重来",new DialogInterface.OnClickListener() {@ Overridepublic void onClick(DialogInterface dialog,int which) {startGame();}}).show();}}
}

然后是"MainActivity.java":

package com.jikexueyuan.game2048;import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.widget.TextView;public class MainActivity extends Activity {private int score = 0;private TextView tvScore; //用于显示分数private static MainActivity mainActivity = null;public MainActivity() {mainActivity = this;}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tvScore = (TextView) findViewById(R.id.tvScore);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}public void clearScore(){    //分数清零,用于游戏开始或重新开始时score = 0;showScore();}public void showScore(){tvScore.setText(score+"");}public void addScore(int s){score+=s;showScore();}/*使其他方法能调用 MainActivity中的方法,如  GameView 方法中* MainActivity.getMainActivity().addScore(cardsMap[x][y].getNum());*/public static MainActivity getMainActivity() {return mainActivity;}}

最后是"activity_mian.xml",这个布局比较简单,没什么好说的,仅贴出来供不想下载源码的读者查看:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context="com.jikexueyuan.game2048.MainActivity"tools:ignore="MergeRootFrame" ><LinearLayoutandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:orientation="horizontal" ><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/score" /><TextViewandroid:id="@+id/tvScore"android:layout_width="wrap_content"android:layout_height="wrap_content" /></LinearLayout><com.jikexueyuan.game2048.GameViewandroid:layout_width="fill_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/gameView" ></com.jikexueyuan.game2048.GameView></LinearLayout>

以上便是本人对该源码的浅见了,由于学习Android不是很长时间,可能会有些许错误的地方,还望大家指出!如果大家有不明白的也可提问,本人一定解答。另外,若还是看不明白,可参看另一位博主关于改源码的解析http://www.cnblogs.com/ilfmonday/p/2048android.html,或去下载极客学院视频观看。

Android手游 “2048” 源码解析相关推荐

  1. 烈焰遮天 cocos 手游mmo 源码 解析

    引擎: cocos2.x 代码: c++ 混合 lua 游戏类型: mmo 工程结构: game : 游戏启动地方 gamelogic:接sdk相关,登陆支付统计等 libFramework:主要本游 ...

  2. android handler2--消息队列源码解析

    android handler2–消息队列源码解析 1.Looper 对于Looper主要是prepare()和loop()两个方法. 首先看prepare()方法 public static fin ...

  3. Android Hawk数据库的源码解析,Github开源项目,基于SharedPreferences的的存储框架

    今天看了朋友一个项目用到了Hawk,然后写了这边文章 一.了解一下概念 Android Hawk数据库github开源项目 Hawk是一个非常便捷的数据库.操作数据库只需一行代码,能存任何数据类型. ...

  4. android网络框架retrofit源码解析二

    注:源码解析文章参考了该博客:http://www.2cto.com/kf/201405/305248.html 前一篇文章讲解了retrofit的annotation,既然定义了,那么就应该有解析的 ...

  5. Android之EventBus框架源码解析下(源码解析)

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! 前言 EventBus是典型的发布订阅模式,多个订阅者可以订阅某个事件,发布者通过 ...

  6. Android 常用开源框架源码解析 系列 (四)Glide

    一.定义  Glide 一个被google所推荐的图片加载库,作者是bumptech.对Android SDk 最低要求是 API 10  与之功能类似的是Square公司的picasso  二.基本 ...

  7. 手游平台源码有什么用处?

    在开发手游平台的基础上,必须要弄清楚手游平台的源码是什么,而源码就是最基础的程序.这是一门编程语言.如果你不认识,就打开你的浏览器,点击F12.你能看见这个页面的源码.源码必须在特定的软件进行编译之后 ...

  8. Android 常用开源框架源码解析 系列 (九)dagger2 呆哥兔 依赖注入库

    一.前言 依赖注入定义 目标类中所依赖的其他的类的初始化过程,不是通过手动编码的方式创建的. 是将其他的类已经初始化好的实例自动注入的目标类中. "依赖注入"也是面向对象编程的 设 ...

  9. Android存储之SharedPreferences源码解析

    个人博客:haichenyi.com.感谢关注 1. 目录 1–目录 2–简介 3–getSharedPreferences会不会阻塞线程,为什么? 4–get操作,为什么有时候会卡顿? 5–comm ...

最新文章

  1. 同步、异步 与 串行、并行的区别
  2. 参加Google™ Code Jam - 中国编程挑战赛(2)
  3. java编程里的values怎么使用,详解Java编程中super关键字的用法
  4. 图解 Numpy,原来数据操作这么简单!
  5. 一只紧握笔的手:地震中的感人图片之二
  6. MySQL笔记——DQL查询数据
  7. 补肾分男女,养肾如养命
  8. 两位动态数码管电子秒表c语言,清翔电子51单片机6课动态显示数码管作业秒表...
  9. 添加库文件_S7200的库文件导至200SMART正确操作
  10. ESP32-SPI接口bl0942驱动
  11. Arcgis地籍图河流注记字体批量修改
  12. 小米Android 4.3.1刷机包,终于来了:小米4 Win10刷机包下载!附刷机教程
  13. itools苹果录屏大师_iTools Pro 1.8.0.4 简单易用的苹果设备 iPhone/iPad 管理工具
  14. 美洽在线客服系统使用指南
  15. 解决Rufus不会自动下载ldlinux.sys和ldlinux.bss文件问题
  16. 如何判断Activity是否在前台显示
  17. 根号3表白html,根号三的那句情话
  18. hexo博客yilia主题作者名字的更改
  19. Linux下安装Atom编辑器
  20. 利用Axure做原型设计

热门文章

  1. 图像处理与计算机视觉的经典书籍
  2. U8与MES对接,字段对接案例分享
  3. 高新计算机考试题库安装,计算机信息高新技术考试模块题库教材配套一览表.doc...
  4. 固态硬盘简称是不是ssd_为什么懂电脑的人都说SSD不要分区?原来真相是这样!...
  5. 2.0手动挡马自达3红色车漆嫩
  6. 阿里虚拟主机屡有非法访问攻击
  7. 【06】【模板方法模式】
  8. DIjskstra曰
  9. MVVM与DataBinding简单使用
  10. VLSI数字信号处理系统——第二章迭代边界