上个周末,3个小时总体上读完了《Android群英传》,本周主要在研究代码层次的设计和实现。
  编译安装在手机上,玩了几把,结合代码,一周时间才掌握了整体的思路。
  大部分时间,其实花在了“重构”上。
  重构的过程,就是学习和思考的过程。
  
  本文,算是一篇学习总结,总体介绍下这款小游戏的实现思路。
  后面抽空,再改造下这个游戏不合理的设计方式,即格子是N*N+1,而不是N*N个。
  
  写到快吐了:在写过的几百篇文章里,其中有很多案例了,写得次数越多,越发现很多流程和思路是一致的。
  因此,很有必要把一些通用的知识总结下。写清楚了,再介绍就清楚多了。
  文章的名字初步定为“可视化界面GUI应用开发总结:Android、iOS、Web、Swing、Windows开发等”,预计2015年12月7日之前发表。
  
  代码讲解
  
  1.包结构

    cn.fansunion.puzzle
  --activity
    GlobalConst.java 几个全局常量
MainActivity.java 游戏的入口Activity
PuzzleActivity.java 拼图游戏过程的Activity
  --adapter
    MainGridViewAdapter.java 游戏入口界面的Gridview的适配器,可以理解成GridView的数据提供者
PuzzleGridViewAdapter.java拼图界面的GridView的适配器
  --bean
    GridItem.java 表格中的1个元素
  --util
     GameUtil.java 封装了游戏规则
 ImageUtil.java 图片处理工具
 ScreenUtil.java 屏幕工具
 
  2.基础类讲解
    GameUtil.java

isMoveable:判断图片是否可以移动,或者称为“能否和空格进行交换”,根据GridView中的position,判断是否和空格是“相邻”的就可以了。
swapItems:交换2个GridItem的位置,在判断可以移动之后
isSuccess:判断当前拼图是否完成
getPuzzleGenerator:生成随机的Item,就是把N*N个数字的位置,打乱
canSolve:判断随机生成的Item是否有解,即能否通过移动交换图片,还原“原图”。
(这个地方的设计,也比较坑。我目前认为,可以换种方式生成初始拼图,即随机交换空格和周边的图片N次。因为“交换是可逆的”,所以总是有解)

ImageUtil.java:把1个图片,切成N*N个;放大图片。
ScreenUtil.java:获得屏幕的大小、密度。

GridItem.java:游戏拼图的核心Model,表格中的1项,id、图片资源id、图片资源,方便绘图和游戏规则实现。
MainGridViewAdapter.java和PuzzleGridViewAdapter.java:继承android.widget.BaseAdapter,重载若干方法。

GlobalConst.java:一些常量,太简单了吧。

3.游戏的流程
    游戏入口MainActivity.java

核心流程:
 a.设置主体界面
   setContentView(R.layout.xpuzzle_main);
 b.初始化其它界面,按钮等
        initViews();
 c.数据适配器
        gridView.setAdapter(new MainGridViewAdapter(
                MainActivity.this, bitmapList));
 d.按钮、界面等绑定事件
   gridView.setOnItemClickListener
      e.事件响应
 
    重要事件
    a.选择游戏难度,保存到Type字段中。给用户一个“弹出对话框”选择。
       

 selectedTypeTextView.setOnClickListener(
new OnClickListener() { @Override
public void onClick(View v) {
// 弹出popup window
popupShow(v);
}
});
}

b.游戏自带若干图片和使用系统图片。
 用表格展示的,Item点击监听,最后1个图片,表示选择“本地图库或者相机拍摄”,其它图片就直接选择了。
       

 gridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long arg3) {
if (position == photoResourceIdArray.length - 1) {
// 选择本地图库 相机
showDialogCustom();
} else {
// 选择默认图片
Intent intent = new Intent(
MainActivity.this,
PuzzleMain.class);
intent.putExtra(GlobalConst.SELECT_PHOTO_ID, photoResourceIdArray[position]);
intent.putExtra(GlobalConst.TYPE, type);
startActivity(intent);
}
}
});

本地图库和相机拍照,是2套类似的逻辑。用户选择之后,调用图库相机回调方法,保存用户选择的图片。
       然后就进入到“拼图游戏主界面”了。
  
拼图游戏主界面PuzzleActivity.java
核心流程:
a.设置主体布局
  setContentView(R.layout.xpuzzle_puzzle_detail_main);
b.获得用户选择的图片,并切图
  getIntent().getExtras().getInt(GlobalConst.SELECT_PHOTO_ID);
c. 初始化其它Views
        initViews();
d. 调用GameUtil生成游戏初始数据,并启动定时器。(写到这里突然发现,又不合理了,定时器,应该在程序全部初始化完成之后,再开启。)
  generateGame();
e.事件绑定。
   // 返回按钮点击事件
        backButton.setOnClickListener(this);
        // 显示原图按钮点击事件
        imageButton.setOnClickListener(this);
        // 重置按钮点击事件
        restartButton.setOnClickListener(this);

// GridView点击事件(最重要的其实是这个),图片可否移动,在能够移动的情况下,需要“交换图片、”“更新绘图”、“更新步数”。
  //在成功的情况下,后续处理(停止计时等)
     

  gridView.setOnItemClickListener(new OnItemClickListener() {

            @Override
public void onItemClick(AdapterView<?> arg0, View view,
int position, long arg3) {
// 判断是否可移动
if (GameUtil.isMoveable(position)) {
// 交换点击Item与空格的位置
GameUtil.swapItems(
GameUtil.gridItemList.get(position),
GameUtil.blankGridItem);
// 重新获取图片
recreateData();
// 通知GridView更改UI
puzzleGridViewAdapter.notifyDataSetChanged();
// 更新步数
stepCount++;
stepCountTextView.setText("" + stepCount);
// 判断是否成功
if (GameUtil.isSuccess()) {
// 将最后一张图显示完整
recreateData();
bitmapItemList.remove(TYPE * TYPE - 1);
bitmapItemList.add(lastBitmap);
// 通知GridView更改UI
puzzleGridViewAdapter.notifyDataSetChanged();
Toast.makeText(PuzzleMain.this, "拼图成功!",
Toast.LENGTH_LONG).show();
gridView.setEnabled(false);
timer.cancel();
timerTask.cancel();
}
}
}
});

4.资源
    布局、菜单、字符串,结合Java代码,很容易读懂。

代码地址:
https://git.oschina.net/fansunion/puzzle
  
  个人看法
  目前的技术,入门,达到中级水平,能够干活和赚钱,还是比较容易的。
  达到一定水平之后,想要继续高深,就要看个人对技术的理解了。
  至于重构、代码规范、游戏设计,每个人都有自己的理解。
  结合实际情况,再做具体考量。

Android群英传-拼图游戏puzzle-代码设计和实现的更多相关文章

  1. Android群英传-拼图游戏puzzle-6点吐槽

    一.缘由  经常写文章,混了一些C币.最近在深入学习Android应用开发,就从商城里买了一本<Android群英传>.这本书的内容,不是纯粹的入门那种,分几个章节,重点讲解Activit ...

  2. Android群英传帝落篇——程序人生,路漫漫其修远兮,吾将上下而求索!

    Android群英传帝落篇--程序人生,路漫漫其修远兮,吾将上下而求索! 当写这篇博客的时候,自2016-02-22到现在5.2号,一晃眼,也㓟两个多月就过去了,我才将这本书看完,虽然写笔记花了很大的 ...

  3. Android群英传笔记——第十二章:Android5.X 新特性详解,Material Design UI的新体验

    Android群英传笔记--第十二章:Android5.X 新特性详解,Material Design UI的新体验 第十一章为什么不写,因为我很早之前就已经写过了,有需要的可以去看 Android高 ...

  4. Android群英传笔记——摘要,概述,新的出发点,温故而知新,可以为师矣!

    Android群英传笔记--摘要,概述,新的出发点,温故而知新,可以为师矣! 当工作的越久,就越感到力不从心了,基础和理解才是最重要的,所以买了两本书,医生的<Android群英传>和主席 ...

  5. Android群英传笔记——第十章:Android性能优化

    Android群英传笔记--第十章:Android性能优化 随着Android应用增多,功能越来越复杂,布局也越来越丰富了,而这些也成为了阻碍一个应用流畅运行,因此,对复杂的功能进行性能优化是创造高质 ...

  6. Android群英传笔记——第六章:Android绘图机制与处理技巧

    Android群英传笔记--第六章:Android绘图机制与处理技巧 一直在情调,时间都是可以自己调节的,不然世界上哪有这么多牛X的人 今天就开始读第六章了,算日子也刚好一个月了,一个月就读一半,这效 ...

  7. Android群英传笔记——第四章:ListView使用技巧

    Android群英传笔记--第四章:ListView使用技巧 最近也是比较迷茫,但是有一点点还是要坚持的,就是学习了,最近离职了,今天也是继续温习第四章ListView,也拖了其实也挺久的了,list ...

  8. Android群英传笔记——第三章:Android控件架构与自定义控件讲解

    Android群英传笔记--第三章:Android控件架构与自定义控件讲解 真的很久没有更新博客了,三四天了吧,搬家干嘛的,心累,事件又很紧,抽时间把第三章大致的看完了,当然,我还是有一点View的基 ...

  9. 【Android群英传】学习笔记(一)

    本系列博客为笔者在学习<Android群英传>的学习总结 Android相关工具镜像连接:http://www.androiddevtools.cn/ Dalvik与ART Dalvik包 ...

随机推荐

  1. [CTSC1999][网络流24题]补丁VS错误

    题目:洛谷P2761.vijos P1019.codevs1239.codevs2218. 题目大意:有n个错误,m个不同的补丁. 对于一个补丁,有两个不同的字符串描述.具体如下: 如果当前错误包含第 ...

  2. 【HNOI】合唱队

    [HNOI]合唱队 题意 对于一个初始序列,保证两两不同,通过一些变换得到目标序列: 第一个值直接插入空的当前队列 对于从第二个值开始的每个值 如果原序列中 $ a[i] $,若 $ a[i]> ...

  3. BZOJ 2402 陶陶的难题II (01分数规划+树剖+线段树+凸包+二分)

    题目大意:略 一定范围内求最大值,考虑二分答案 设现在选择的答案是$mid$,$max \left \{ \frac{yi+qj}{xi+pj} \right \} \geq mid $ 展开可得,$ ...

  4. HDU 5421 Victor and String (回文自动机)

    题目大意:让你维护一个字符串,支持在开头结尾插入字符,以及查询本质不同的回文串数量以及回文串总数量 开头结尾都维护一个$last$指针,如果插入新字符后,整个串是一个回文串,就把另一个$last$赋值 ...

  5. Vue -- 只弹一次的弹框

    核心代码是 getCookie()部分,控制弹框的显示隐藏则在 created()中. <template> <div v-if="isShow"> < ...

  6. S3C6410 LCD Overlay Test Program

    测试了一下S3C6410 LCD控制器提供的Overlay功能,写了一个简单的test,主要用于实现FB0和FB1之间的Overlay操作.内核选项的Windows至少要为2. 具体支持如下操作:1 ...

  7. 解决utf8' codec can't decode byte 0xe5 in position 0: unexpected end of data

    使用unicode对象的话,除了这样使用u标记,还可以使用unicode类以及字符串的encode和decode方法. unicode类的构造函数接受一个字符串参数和一个编码参数,将字符串封装为一个u ...

  8. django-3-模板变量,过滤器,静态文件的引用

    <<<模板变量>>> (1)定义视图函数 通过context传递参数来渲染模板,context要是个字典 当模板变量为可调用对象的时候,函数不传递参数 (2)配置模 ...

  9. 06001_NoSQL概述

    1.什么是NoSQL? NoSQL(NoSQL=Not Only SQL),意即“不仅仅是SQL”,是一项全新的数据库理念,泛指非关系型的数据库. 2.关于关系型数据库和nosql数据库 (1)关系型 ...

  10. ACdream 1157 Segments

    Segments Time Limit: 2000ms Memory Limit: 10000KB This problem will be judged on ACdream. Original I ...