16.5 实现牌面分析

更新于 2026年10月10日 版权声明

第四篇 综合实战篇

第13章 体育竞技类游戏——疯狂足球

手机游戏开创了一种全新的娱乐方式和应用模式,并随着移动互联网的发展而快速崛起我们可以在大街上、公交车上、公园中随处可见玩手机游戏的人。所以开发一个Android手机游戏很有必要,在本章的内容中,将通过一个具体实例的实现过程,介绍开发一个Android游戏的基本流程。

13.1 蓬勃发展的手机游戏

手机游戏开创了一种全新的娱乐方式和应用模式,并随着移动互联网的发展而火热兴起数据分析机构Newzoo与TalkingData日前联合发布《2015中国移动游戏市场报告》,报告显示2015年市场总值达71亿美元的中国移动游戏在2016年将继续保持高速增长,报告显示2016年中国移动游戏市场将达到100亿美元的量级,这也将确保其稳固全球最大移动游戏市场的地位。

《2015中国移动游戏市场报告》指出尽管第四季度移动游戏设备数量增长率下滑至4.8%截至2015年第四季度,中国活跃设备数依旧突破10亿。2015年中国移动游戏市场收入达到71亿美元,超越美国和日本成为世界最大的移动游戏市场,较上年增长了57%。移动游戏市场占游戏产业比为33%,预计至2019年,中国移动游戏市场总值将达到139亿美元,市场占比将进一步提升至48%。2015年中国移动游戏达16500款,休闲和卡牌游戏占市场主题,不过报告却指出,中国的手机游戏类型有从“休闲游戏”向“硬核向”倾斜的趋势,大型游戏公司倾向于开发类MMORPG、ARPG、SLG类型的重度游戏,越来越多的玩家开始尝试倾向重度类型的移动游戏。

13.2 足球游戏介绍

足球游戏是指以足球作为游戏主题的游戏,目前在市场上主要分为足球类小游戏、足球类网页游戏、足球类电视游戏、足球类电脑游戏等几大类别。在足球游戏中,用户可以扮演不同的角色,扮演球员角色的通常以操作类的足球游戏为主,代表作品包括FIFA系列、实况足球系列。用户也可以扮演经理人角色,代表作品是足球经理人系列游戏。不同类型的足球游戏,可以让玩家得到不同的体验。足球游戏平台包括基于PSP、PS3、PS2、NDSL、PC、手机、XBOX360等。例如屏幕视图、道具视图、角色视图等。

13.2.1 手机足球游戏

绿茵场是充满激情的地方,足球是当今世界第一普及性运动,每四年一届的世界杯堪比奥运会。足球运动的盛行,也衍生了很多附属产业的兴起,例如手机游戏和电脑游戏。电脑足球游戏对于大家可能不会陌生,例如著名的EA FIFA和实况足球曾经令我们陶醉其中。现在随着智能手机的蓬勃发展,手机足球游戏也日益受到人们的青睐。

本项目将基于Android平台来开发一个基本的足球游戏。游戏操作方式比较简单,就像桌式足球一样用球杆来控制多个运动员。

13.2.2 策划游戏

本项目属于体育类游戏,下面开始策划整个项目的具体功能。

(1)情节

作为一个竞技足球项目,需要模拟现实世界的足球实况,所以游戏情节都是几乎一样的在此阶段的主要工作是规划游戏进程和不同的场景。

(2)目标用户

本项目的玩家主要是对足球有一定了解的用户,或者是对体育运动特别是足球感兴趣的人,并且以年轻人为主。

(3)运行平台

本项目的运行平台是Android 2.3及以上版本。

(4)显示技术

为了将绿荫场景生动地展示在用户面前,需要采用2D单屏模式以指定的视角展示游戏

(5)操控方式

将使用手机键来控制游戏。

13.2.3准备工作

在进行游戏开发之前,需要准备好游戏中用到的图片素材和配音文件。其中用到的图片素材文件保存在“res\drawable-mdpi”目录下,如图13-1所示。

图示

图13-1 图片素材

用到的配音文件保存在“res\raw”目录下,如图13-2所示

图示

图13-2 配音文件

13.3 项目架构

在本节内容中,将对整个项目进行总体架构分析,并对项目中的各个类及其结构进行介绍

13.3.1 总体架构

本项目的总体架构如图13-3所示

图示

图13-3 总体架构图

13.3.2 规划类

类是面向对象的核心,在本游戏项目中,为了实现各个具体的功能,需要编写各个类来实现具体的功能。下面将介绍各个类的具体功能。

1.界面显示类

项目中和界面显示有关的类如下。

(1)FootballActivity类:继承自Activity,扮演一个类似于控制器的角色,能够在不同的视图之间切屏以及处理键盘和触控笔的单击事件。

(2)视图类:包含了几个继承于SurfaceView的视图类,有WelcomeView、LoadingView和GameView,能够为玩家显示不同的视图效果。各类的具体功能如下。

■ WelcomeView:显示欢迎界面和系统菜单。

■ LoadingView:显示在不同界面之间进行切换时的进度条。

■ GameView:显示游戏画面。

(3)线程类:包含了几个继承于Thread的线程类,能够实现刷屏和修改后台数据库的功能。各类的具体功能如下。

■ WelcomeDrawThread、LoadingDrawThread和DrawThread:能够刷新视图类中的显示

内容。

■ WelcomeThread:能够修改WelcomeView中的数据。

(4)类CustomGallery:这是一个自定义控件,能够实现类似于Gallery的图片显示效果

2.运动控制类

项目中和运动控制有关的类如下。

(1)Ball类:根据足球的方向移动足球的位置,并检测是否与双方球员或奖励物品发生碰撞,如果碰撞则进行碰撞处理。

(2)AIThread类:使用算法设置手机控制球员的移动方向,项目中的球员只有左和右两个方向。

(3)PlayerMoveThread类:定时读取球员的移动方向,根据方向来移动球员。

(4)Play类:封装了球员信息以及对这些信息进行操作的成员方法。

3.奖品类

在奖品类中,有继承自Object类的Bonus类,此类是奖品类的父类。还有继承自Thread类的BonusManager类,此类能够添加一些新的Bonus对象到游戏中。

13.4 具体编码

经过前面的讲解,整个项目的前期工作结束。从本节的内容开始,将进入具体编码阶段希望读者仔细学习本节的内容。

13.4.1 Activity类开发

在Android中,Activity负责不同界面间的切换。在本项目中,Activity还能够实现按键单击和修改按键状态的功能。本足球游戏项目的Activity类是由文件FootballActivity.java实现的,下面开始介绍它的实现流程。

(1)作为一个控制器,首先要声明项目中需要的成员变量,在代码中对这些成员的具体含义进行了详细说明注释。具体代码如下。

图示

图示

(2)编写onCreate重写方法,这个方法在Activity创建时被首先调用,能够对各个变量进行初始化处理。具体代码如下。

图示

(3)定义方法initWelcomeSound(Context context)和initRects(),分别初始化欢迎界面的声音和初始化矩形框。具体代码如下。

图示

(4)定义方法onTouchEvent(MotionEvent event),能够处理用户所有的屏幕单击事件。具体代码如下。

图示

图示

图示

5)定义方法initSound(),用于加载游戏中用到的声音。具体代码如下

图示

6)定义方法updateProgressView(),用于更新进度条的进度。具体代码如下

图示

7)定义方法checkLayout(int[]layout),用于检查用户输入的layout是否合法。具体代码如下。

图示

图示

13.4.2 欢迎界面

在欢迎界面中,涉及的类有WelcomeView、WelcomeThread、WelcomeDrawThread和CustomGallery。在下面的内容中,将对实现上述类的文件进行一一讲解。

(1)文件CustomGallery.java

此文件仿照Gallery控件实现了图片的显示,在项目执行之后供用户选择自己的球队。其具体实现代码如下。

图示

图示

图示

在上述代码中,函数CustomGallery能够初始化屏幕上的坐标和所显示的图片大小。

(2)文件WelcomeView.java

类WelcomeView继承于SurfaceView类,并且实现了SurfaceHolder.Callback的接口。具体实现代码如下。

图示

图示

图示

图示

(3)文件WelcomeThread.java

类WelcomeThread继承于Thread类,能够对控制WelcomeView中的内容。具体实现代码如下。

图示

图示

(4)文件WelcomeDrawThread.java

类WelcomeDrawThread继承于Thread类,能够定时刷新WelcomeView。具体实现代码如下。

图示

图示

13.4.3 加载节目

加载界面在游戏开发项目中比较常见,是整个游戏表示层中比较简单的部分。主要涉及了类LoadingView,类LoadingView继承于SurfaceView类,并且实现了SurfaceHolder.Callback接口。具体实现代码如下。

图示

图示

图示

13.4.4 运动控制

运动控制模块用于控制足球和玩家运动模块的开发,主要涉及了类Ball、PlayerMoveThread、AIThread和Player。

(1)球员控制模块

球员控制功能是通过按键上的方向键实现的,这是在文件FootballActivity.java中定义的在里面定义了onKeyDown(int keyCode,KeyEvent event)和onKeyUp(int keyCode,KeyEvent event),分别处理键盘按下事件和键盘抬起事件。对应代码如下。

图示

(2)控制手机一方球员的运动

手机一方球员的运动控制是通过一个算法实现的,算法如下。

在每个固定时间读取足球的运动方向,如果足球偏向左,则将球员运动方向设置为向左如果足球偏向右,则将球员运动方向设置为向右。上述功能是通过AIThread类实现的,此类为AI(计算机人物角色)的后台线程,实现的功能是让AI足球运动员根据足球的运动的参数来确定自己的运动方向(向左还是右)。由于人工智能算法比较复杂,限于本书的篇幅,所以采用了一个比较简单的算法,即如果足球的方向偏左(即可以是左上、左下、正坐等),那么AI的运动方向就是向左,反之则向右。

实现文件AIThread.java的对应代码如下。

图示

(3)PlayerMoveThread类

前面介绍了玩家和球员的移动,最终目的是实现双方球员位置变化的是PlayerMoveThread线程。此线程的实现文件是PlayerMoveThread.java,具体代码如下。

图示

图示

图示

(4)Player类

在本项目中,每个Player对象代表一个球员,在Player中除了成员变量之外,还有一个成员方法。并且还包括一个成员方法levelUp,负责玩家赢得一场比赛的胜利之后的升级操作Player来在文件Player.java中定义,具体代码如下。

图示

(5)Ball类

Ball类是一个继承于Thread类的线程类,是系统中比较重要的类,里面不仅封装了足球对象的必要信息,还提供了用于碰撞检测和处理的一系列相关方法,Ball类是整个项目后台运行的核心。在本项目中,设置了足球的移动方向为16个方向,夹角是22.5度。Ball类是在文件Ball.java中定义的,下面开始介绍其实现流程。

第一步:封装足球有关的信息,如坐标点、方向、移动速度等,定义成员变量,具体代码如下。

图示

图示

第二步:实现游戏碰撞检测处理。此功能主要是通过run方法来实现的,run方法中主要有两个方法move和checkCollision,前者负责根据足球的方向来的移动足球的位置。后者用于进行碰撞检测,查看是否足球碰到AI或玩家控制的运动员、是否遇到边界、是否遇到外部物体等。具体代码如下。

图示

图示

图示

图示

图示

图示

在上述代码中,方法checkForBorders()能够检测足球是否碰到了边界,如果碰到了上下左右中的某一边界,则处理方法为:一定几率沿正确的路线(类似反射定律)改变方向,一定概率随机变向,如以方向1碰到上边界,会以某个较大的概率将小球的方向改为7,而会有相对较小的概率将方向改为5、6、7三个方向中的某一个。

第三步:定义方法handleCollision(),此方法处理足球和运动员之间的碰撞,手机和玩家的处理方式是一样的,首先查看Player对象的movingDirection,再综合Player对象的attackDirection,确定方向范围,类似直角坐标系中的4个象限,然后在方向范围中随机产生一个,这样产生的方向有惯性在里面,这样看来会比较真实。需要注意的是如果足球和运动员碰撞时运动员静止不动,那么可选的方向就是1或15(进攻方向朝上)、7或9(进攻方行朝下)。具体代码如下。

图示

图示

第四步:定义方法checkIfScoreAGoal(),此方法用于检测是否进球,如果是,则相应球队得分加1,然后判断游戏是否结束(游戏规则是谁先进够8个谁就赢)。具体代码如下。

图示

13.4.5 奖品模块

本项目的奖品模块功能是通过类Bonus实现的,它是IceBonus和LargerGoalBonus的父类。主要提供一些公共的成员或方法。一个Bonus类主要包括自己的绘制部分、触发后的绘制、自己生命周期计时、触发后生命周期计时、触发后后台数据的修改、触发生命周期结束后后台数据的恢复。Bonus类是在文件Bonus.java中实现的,具体代码如下。

图示

图示

图示

BonusManager类继承于Thread,主要实现对Bonus对象的管理,通过定期检测屏幕上Bonus的个数,根据概率随机生成Bonus。实现文件BonusManager.java的实现代码如下。

图示

图示

至此,整个项目的主要模块功能介绍完毕,执行之后的初始界面如图13-4所示,菜单界面如图13-5所示,进度条界面如图13-6所示,游戏界面如图13-7所示。

图示

图13-4 初始界面

图示

图13-5 菜单界面

图示

图13-6 进度条界面

图示

图13-7 游戏界面

第14章 益智类游戏——魔塔游戏

益智游戏是指那些通过一定的逻辑或是数学、物理、化学,甚至是自己设定的原理来完成一定任务的小游戏。一般需要适当的思考,适合年轻人玩。益智游戏通常以游戏的形式锻炼了游戏者的脑、眼、手等,使人们身心健康,增强自身的逻辑分析能力和思维敏捷性。在本章的内容中,将详细讲解益智类游戏——魔塔游戏的具体实现过程。

14.1 魔塔简介

魔塔是一种具有固定数值RPG游戏,这个游戏需要多动脑筋,任何一个轻率的选择都可能导致游戏的失败,还可以锻炼游戏者的数学能力。在本节的内容中,将简要介绍此款游戏的基本知识。

14.1.1 游戏简介

经典魔塔有5种,分别是Tower of the Sorcerer、24层魔塔、新新魔塔、魔塔2006、魔塔2000。虽然魔塔的界面很像一般的地牢游戏,貌似随便的打打杀杀就可以过关,但事实上玩这个游戏需要动很多脑筋,任何一个轻率的选择都可能导致游戏的失败,该游戏有属性攻击防御、生命、金币、经验。对怪物的伤害次数计算公式是“敌人的生命/(自己的攻击−敌人的防御)”;而伤害的数目计算是“怪物伤害次数*(敌人的攻击−自己的防御)”。商店一般有三种21层魔塔里商店是固定的价格,50层魔塔里商店是价钱翻倍的,新新魔塔里商店有两个,一个初始20金币,买一次贵1金币;一个初始50金币,买一个贵2金币。魔塔游戏虽不大,但是制作精美,道具很多,而且难度适中。

14.1.2 发展版本

魔塔最早是两位日本设计师制做的,引进中国后“胖老鼠”又制作了21层魔塔,然后就是新型作品新新魔塔,魔塔2000,后来“0ksh”制作了魔塔样板,参与制作魔塔的人也就越来越多了,但制作水平不一。

(1)21层魔塔和24层魔塔

这两款魔塔都是由胖老鼠制作的,其区别从名字中就可以看出来:层数不一样。但是如果不在25分钟之内打到16层并获得灵杖,或在获得灵杖之前已经拿到十字架,就不能出现隐藏楼层。其他的区别并没有多少。在24层魔塔中,圣光盾的价格被降低为500金币,不同于21层魔塔的800金币,从此打法就发生了变化(多费的金可以省下来)。21层冥灵魔王的能力被改为2550/2250。另外还有一个不太容易被看出来的区别:多了一种宝物,目前不知道叫什么,用<C>键可以使用,可以破坏整个楼层的墙,现在还没有人发现获得此宝物的方法除此之外,还可以在游戏中存档,打错一步可以重来。

(2)21层魔塔和扑克魔塔

这两款魔塔基本上是一样的,地图几乎完全相同,但是刘景雄在制作魔塔一的时候做了如下修改。

■ 4层的两个骷髅人下面各多了一个红血瓶。

■ 11层守着黄金盾的卫兵改成了4个中级卫兵。

■ 困难模式下,21层的两个栅栏门被开成了两个绿花门,在心形的两边也多出了两个

NPC。

14.2 设计游戏框架

从本节内容开始,将详细讲解在Android平台上开发一个魔塔游戏的具体流程。因为所有游戏是基于框架的,所以设计一个合适的框架尤为重要。为了正确设计框架,先看魔塔游戏的界面,如图14-1所示。

图示

图14-1 游戏界面

由游戏界面可知,游戏中包含了地图、角色、屏幕界面、道具等元素,上述元素构成了一个视图,例如屏幕视图、道具视图、角色视图等。

14.2.1 设计界面视图

在Android中,视图是通过继承View类实现的,在View类中包含了各种绘制图形的方法和事件处理,这样构建一个游戏界面类将变得轻而易举。界面类ViewCH类的具体代码如下。

图示

14.2.2 屏幕处理

在玩游戏的过程中,屏幕会伴随玩家的操作而变化。在设计好整个游戏的屏幕框架后,还需要设计屏幕的控制类。通过这些类,可以根据不同的游戏状态来控制屏幕的具体显示内容。在此编写MainCH类,实现文件是MainCH.java,具体代码如下。

图示

图示

图示

14.2.3 更新线程

到此为止,整个游戏界面的设计告一段落。但是还有一个十分关键的问题,屏幕更新功能需要借助线程来实现,因为只有这样才能在本质上实现实时更新。在本游戏项目中开启了一个主线程,并通过方法getMainView()来获取并显示当前界面,而且可以根据不同的界面来进行界面更新。线程更新功能在文件CanvasCH.java中实现的,具体代码如下。

图示

图示

图示

14.2.4 游戏界面显示

经过前面的界面类设计工作后,要想完美地实现游戏界面,还需要做最后一步的工作。接下来我们需要用一个Activity来显示具体的界面。因为是在CanvasCH中控制界面,所以只需使用方法setContentView()显示一个CanvasCH对象即可。游戏界面显示功能是通过文件MagicCH.java实现,具体代码如下。

图示

图示

通过上述处理,一个基本的游戏框架宣告建设完毕。在后续的开发中,只需直接继承上面的类界面即可。即继承GameView,然后在MainView中更改游戏状态即可。

14.3 绘制处理

设计好游戏框架之后,我们需要绘制游戏中的角色和场景。在本节的内容中,将简要介绍魔塔游戏中绘制处理的实现过程。

14.3.1 绘制地图

绘制地图功能是通过文件TiledCH.java实现的,在里面定义了方法paint()来绘制地图,并将绘制的图形显示在屏幕上。文件TiledCH.java的具体实现流程如下所示。

(1)定义方法TiledCH(),其中参数columns和rows分别表示地图的列数和行数,即构建的地图数组的行数和列数;参数image表示地图所有图块的一张图片,即编辑地图时所使用的图片;参数tileWidth和tileHeight分别表示每个图片的宽度和高度。对应代码如下。

图示

图示

2)定义方法setCell()来设置该地图使用的地图数据,通过一个循环设置了所有要显示的行和列的图块索引值。参数col和row分别表示在屏幕上要显示的列数和行数;参数tileIndex则表示在地图上显示图块的值。对应代码如下。

图示

3)定义方法fillCells()在图层中指定单元格区域,对应代码如下

图示

4)定义方法paint()和drawImage()将地图绘制到屏幕上。此功能通过一个循环将设置的

地图数组和图片进行对应,并绘制到对应的屏幕上。对应代码如下

图示

14.3.2 绘制游戏主角

魔塔游戏中的主角被称为“精灵”,这个主角可以做很多动作,比如,可以向4个方向移动,并且分别对应4个不同的动画。动画本身就是将图片一帧一帧地连接起来,然后循环地播放每一帧形成的。在本实例中,是通过SpriteCH类实现主角功能的。类SpriteCH是一个显示图像类,该类和TiledCH的区别是:SpriteCH是由一个可以有好几帧的图组成的,所以SpriteCH通常被定义为一些小的、有动作的游戏对象,而TiledCH通常被用来构造生动的背景。类SpriteCH是在文件SpriteCH.java中实现的,此文件的具体实现流程如下。(https://www.daowen.com)

1)定义系统所需要的初始常量和标量,具体代码如下。

图示

2)在SpriteCH类中构造如下3个构造方法,具体代码如下

图示

图示

在上述三个构造方法中,参数image表示主角的图片,参数frameWidth和frameHeight分别表示主角图片的每一帧的宽度和高度,参数s表示通过一个主角来创建另一个主角。在构造SpriteCH类时,需要指定主角的高度和宽度,单位是像素值。图像的高度和宽度必须分别是主角的高度和宽度的整数倍。也就是说,需要正好让计算机把图像按照主角的大小划分成几个类。在本游戏中的这些帧,无论是横排、竖排、横竖排、方阵排都无所谓。接下来就可以指定帧数了,左上方是编号0,然后从左到右、从上到下依次排列。在项目中使用方法setFrame(int sequenceIndex)来设置哪一帧被显示,此功能是通过将编号作为参数传递来实现的。

(3)因为使用类TiledCH的好处是,自动根据主角的位置来判断地图绘制的位置。所以可以使用下面的方法setRefPixelPosition()来设置主角的位置。其中参数x和y是主角的位置。

图示

4)定义如下三个碰撞检测函数,分别表示主角和TiledCH的碰撞、主角和主角的碰撞主角和图片的碰撞。参数pixelLevel表示使用像素检测还是矩形检测。矩形检测只需要将主角对应成相应的矩形范围来进行检查,这种检测速度很快,但不是很准确,对于碰撞要求不高的游戏可以使用它。同时还可以将一个SpriteCH分解成很多矩形来使用矩形检测以提高准确性。而像素检测则比较准确,但是速度必然会减慢。具体实现代码如下。

图示

图示

图示

图示

图示

图示

14.3.3 绘制对话界面

魔塔中的主角可以和NPC进行对话,通过对话可以获得对游戏有帮助的信息。对话界面如图14-2所示。

图示

图14-2 对话界面

图14-2所示的界面通过一个浮动的对话框来显示对话内容,这个对话框只是一个矩形框,然后在右边绘制出对应的NPC的头像即可。这里的对话内容可以通过前面介绍的TextCH类来实现自动换行。对应代码如下。

图示

14.3.4 战斗界面

当主角和怪物发生碰撞时就会发生战斗,在项目中需要专门设计一个界面来实现战斗效果。本项目的战斗界面功能是通过文件FightScreen.java实现的,通过此文件可以分别显示玩家和怪物的头像以及属性,包括生命、攻击、防御。主要代码如下。

图示

图示

图示

14.3.5 图层管理器

编写文件LayerCH.java,定义图层管理器类Layer,我们前面使用的类TiledCH和SpriteCH都继承自一个抽象类Layer(图层)。也就是说,不管是地图还是主角,都包含在图层这个类中,所以为了方便管理和维护这些图层,我们构建一个专门用来管理图层的图层管理器ManagerCH。抽象类LayerCH的实现很简单,只是包括了图层的位置(x,y)、图层的宽度和高度(width,height)以及一个控制是否显示图层的布尔变量visible。

文件LayerCH.java的具体实现流程如下。

(1)设置并获得图层的一些属性,对应代码如下。

图示

图示

(2)接下来创建一个图层管理器ManagerCH。在具体实现时,需要先确定图层管理器需要的成员变量,用视窗的x和y用来表示宽度和高度,用一个Layer的数组用来保存所有的图层,用一个变量来保存实际图层的数量。在此只需要将所有图层一起添加到图层管理器中然后设置视图查看时的位置及大小,调用图层管理器的paint()方法绘制图层。绘制的顺序是按添加的反顺序,即先添加的后绘制,大家一定要注意这一点,以免图层被覆盖之后显示不出来。上述功能的对应代码如下。

图示

图示

图示

14.4 实现游戏音效

音效在游戏开发中占据重要地位,在开发游戏时人们经常忽视游戏的音效。开发者往往把主要精力花费在游戏的图像和动画等方面,而忽视了背景音乐和声音效果。这种做法是不正确的,因为好的游戏音效和音乐可以使玩家融入游戏世界,产生共鸣。我们为本游戏项目加入了两个背景音乐,一个是菜单背景音乐,一个是游戏中的背景音乐。

(1)首先准备两个符合游戏剧情的背景音乐放到“res\raw”目录下。

(2)在文件PlayerCH.java中创建了一个PlayerCH类来控制音乐播放,在里面构建了一个MediaPlayer对象,通过方法create()来装准备好的载音乐素材文件。对应代码如下。

图示

图示

到此为止,整个实例的主要模块代码介绍完毕。为节省本书篇幅,其他部分的代码不再详细讲解。本魔塔游戏执行后的界面效果如图14-3所示。

图示

图14-3 执行效果

第15章 桌面类小游戏——五子棋和扫雷

在Windows系统中,自带了很多可玩性很高的桌面小游戏,例如扫雷、五子棋和纸牌等其实在Android手机中,也可以开发出类似的小型游戏。在本章的内容中,将通过两个具体实例的实现过程,介绍在Android系统中开发五子棋游戏和扫雷游戏的基本流程。

15.1 开发一个五子棋游戏

图示

15.1.1 实例说明

五子棋是一种两人对弈的纯策略型棋类游戏,是起源于中国古代的传统黑白棋种之一。发展于日本,流行于欧美。容易上手,老少皆宜;不仅能增强思维能力,提高智力,还有助于修身养性。

许多国家的人对五子棋都有不同的爱称,例如,韩国人把五子棋称为“情侣棋”,暗示情人之间下五子棋有利于增加情感的交流;欧洲人称其为“绅士棋”,代表下五子棋的君子风度胜似绅士;日本人则称其为“中老年棋”,说明五子棋适合中老年人的生理特点和思维方式;美国人喜欢将五子棋称为“商业棋”,也就是说,商人谈生意时可边下棋边谈生意,棋下完了生意也谈成了。

15.1.2 具体实现

本项目实例实现了一个简单的五子棋功能,主界面有三个按钮,分别是“重玩”、“选项”和“退出”。界面大部分都是方格棋盘,在上面可以摆放五子棋的黑棋子和白棋子。棋格实例比较简单,具体实现流程如下。

(1)编写布局文件main.xml,具体代码如下。

图示

图示

(2)编写文件Const.java,这是一个常量文件,将系统中需要的量在此文件中统一定义,这样做的好处是方便对系统的维护和理解。主要代码如下。

图示

(3)编写文件mainA.java,此文件实现游戏主界面,能够实现标题栏隐藏功能和全屏显示功能。主要代码如下。

图示

图示

(4)编写文件GameV.java,此文件是这个五子棋游戏的核心,在里面定义了继承于SurfaceView类的子类GameV,在里面实现了整个游戏框架功能。文件GameV.java的具体实现流程如下。

■ 定义了继承于SurfaceView类的子类GameV,定义了游戏框架界面中元素的初始值,

具体代码如下。

图示

图示

■ 定义方法onTouchEvent(),功能是根据用户触摸屏幕实现走棋响应。具体代码如下

图示

图示

图示

■ 定义方法UpdateTouchEvent(),功能是当触摸屏幕棋盘时实现屏幕内容的更新,从而

实现下棋功能。具体代码如下

图示

图示

■ 定义方法CreatMatrixBitmap(),功能是创建一个缩小或放大的新图片。具体代码如下

图示

■ 定义方法DrawString(),功能是在屏幕中绘制一个字符串。具体代码如下

图示

图示

■ 定义方法DrawImage(),功能是绘制一张图片可以选择图片的锚点位置。在此有三个

锚点位置,分别是“重玩”、“选项”和“退出”。具体代码如下。

图示

到此为止,本五子棋游戏项目介绍完毕,执行后的效果如图15-1所示。分别单击“重玩”、“选项”和“退出”可以实现对应的操作。

图示

图15-1 执行效果

15.2 开发一个扫雷游戏

图示

15.2.1 实例说明

扫雷游戏是微软于1992年附带在其操作系统中的小游戏,它通过单击格子并以出现的数字来判断附近地雷的数量,将全部地雷做上标记即可胜利。扫雷游戏的目标是尽快找到雷区中所有不是地雷的方块,而不踩到地雷。点开的数字是几,则说明该数字旁边的8个位置中有几个雷,如果挖开的是地雷,则会输掉游戏。在本实例中,编写了一个能够在Android系统上运行的扫雷游戏。

15.2.2 具体实现

(1)编写布局文件test.xml,里面使用TableLayout布局控件设置了3行内容。文件main.xml的主要代码如下。

图示

图示

(2)编写文件Bl.java,在里面定义了继承于Button的类Bl,功能是实现了一个个地雷快的显示功能。文件Bl.java的具体实现代码如下。

图示

图示

图示

图示

3)编写文件leiGame.java,此文件实现了本扫雷游戏的主界面,具体实现流程如下

■使用TableLayout动态添加行,主要代码如下。

图示

图示

■ 实现定时器Handler功能,用于统计扫雷完成的时间。具体代码如下

图示

■ 第一次单击的处理事件代码如下

图示

■ 第一次点击无雷时的处理事件代码如下

图示

图示

■ 单击雷块后会实现一个特殊的效果,此效果的实现代码如下

图示

■ 通过如下代码记录当前玩家的胜负

图示

图示

因为本书篇幅的限制,本实例就讲解到此为止。执行后的游戏界面效果如图15-2所示

图示

图15-2 执行效果

第16章 棋牌类游戏——斗地主

斗地主是一款深受欢迎在中国的游戏。在互联网快速发展的今天,斗地主游戏也逐渐走进网络游戏的领域。在本章的内容中,将详细讲解斗地主游戏的构建过程,旨在让读者牢固掌握Android游戏项目的建立、维护以及前台应用程序的开发知识。

16.1 斗地主简介

斗地主是一种扑克游戏。游戏最少需要3个玩家,使用一副(54张)牌(带王牌),其中一方为地主,其余两家为另一方,双方对战,先出完牌的一方获胜。该扑克游戏最初流行于中国湖北武汉市汉阳区,现已逐渐在各地流行。

在网络和现实游戏应用中,斗地主游戏的玩法规则如下。

(1)发牌和叫牌:一副扑克54张,先为每个人发17张,剩下的3张作为底牌,玩家视自己手中的牌来确定自己是否叫牌。按顺序叫牌,谁出的分多谁就是地主,一般分数有1分2分、3分,其他出分低的玩家为农民。地主的底牌需要给其他玩家看过后才能拿到手中,最后地主有20张牌,农民分别有17张牌。

(2)出牌:地主先出牌,按照逆时针顺序依次进行,农民利用手中的牌有组织地出牌,并和同伴配合(这种配合的默契程度,之后会在算法中体现),尽快出完手中的牌。一手牌在另外两家打不过的情况下,出牌的玩家继续出牌。

(3)牌型以及大小:单牌大小顺序为大王,小王,2,A,K,Q,J,10,9,8,7,6,5 4,3。组合牌大小顺序为火箭最大,炸弹其次。如果是同种牌型,则比较其主牌作为单牌时的顺序。下面是各种牌型的使用说明。

■ 单牌:任何一张牌都是单牌,大小为大王、小王、2、A、K、Q、J等。

■ 对牌:2张数值相同,花色不同的牌。

■ 三张:3张数值相同,花色不同的牌。

■ 单顺:5张或5张以上,数值连续的牌,2和双王不能列入其中。

■ 双顺:3个或者3个以上数值连续的对牌。

■ 三顺:2个或2个以上数值连续的三张牌。

■ 飞机:三顺加数量相同的单牌或者对牌。

■ 炸弹:4张数值相同的牌。

■ 火箭:两个王。

16.2 准备素材文件

作为一款纸牌类游戏项目,素材图片资源是必不可少的。本项目中用到的素材图片如

图16-1 所示

图示

图16-1 素材图片

16.3 实现游戏框架

本节将详细讲解在Android平台上开发一个斗地主游戏的具体流程。因为所有游戏是基于框架的,所以设计一个合适的框架尤为重要。为了正确设计框架,先看市面中斗地主游戏的界面,如图16-2所示。

图示

图16-2 游戏界面

由游戏界面可知,游戏中包含了纸牌、玩家角色、桌子界面、积分等元素,上述元素构成了一个视图,例如屏幕视图、纸牌视图、角色视图和桌子视图等。

16.3.1 系统主界面视图

首先打开文件AndroidManifest.xml查看系统文件的运行顺序,由此可知系统运行后将首先执行类DDZ。文件AndroidManifest.xml的具体实现代码如下。

图示

图示

文件DDZ.java构建了系统运行后的第一个视图,通过函数handleMessage中的case语句判断来到了哪一个视图界面。其中mv表示菜单视图界面,gv表示游戏视图界面。文件DDZ.java的具体实现代码如下。

图示

图示

16.3.2 设计菜单视图界面

在Android系统中,视图是通过继承View类实现的,在View类中包含了各种绘制图形的方法和事件处理,这样构建一个游戏界面类将变得轻而易举。本项目的菜单视图界面类的实现文件是MenuView.java,具体实现代码如下。

图示

图示

图示

图示

16.3.3 游戏视图界面

本项目的游戏视图界面类是GameView,功能是通过Canvas构建二维打牌视图。文件GameView.java的具体实现代码如下。

图示

图示

图示

16.4 实现游戏角色

在本项目中,游戏角色有扑克、玩家、记分牌、桌子等。在本节的内容中,将详细讲解实现上述游戏角色的具体过程。

16.4.1 实现扑克角色

文件PokeType.java的功能是定义了斗地主游戏中的牌面类型,例如单牌、对牌、炸弹等,具体实现代码如下。

图示

文件Poke.java的功能是定义了斗地主游戏中的所有54张牌的面值,并按照指定的排列顺序显示在每一个玩家面前。类Poke定义了一些关于扑克牌的核心操作,例如洗牌、获取牌型和出牌等操作。作为一个关于扑克操作的工具栏,Poke中的所有方法全部是静态方法,可以直接通过类名调用,不实例化Poke类。

根据经验可知,洗牌六次可以达到最大的混乱度。但是,此处采用了一个随机算法,也就是让54张牌分别和随机生成的牌发生交换,这种方法没有常规洗牌那么的“随机性”,不过,作为置乱,也已经足够了。

在类Poke中给出了这样一个方法,可以直接从牌中选中能够打过card值的牌,如果没有则返回false。利用must值来判断紧迫性,如果neesZd为true,则需要“炸弹”的配合,也就是到了一些关键关时刻。另外,在选择拆牌的时候,考虑到“火箭”和“4个2”的牌是拥有绝对实力的,这样的牌都不能拆开。在检查炸弹的时候,也可根据紧迫性几率出牌,如果下家是和自己一伙的,则顺延给下家。文件Poke.java具体实现流程如下。

(1)定义类Poke,并通过函数show显示每一张扑克,具体实现代码如下。

图示

(2)定义函数shuffle,使用0~53表示54张牌,使用for语句对54张牌中的任何一张都与随机找到的一张和它互换,将牌顺序打乱。具体实现代码如下。

图示

(3)定义函数sort,实现冒泡排序,具体实现代码如下

图示

图示

(4)定义函数getPokeValue,实现大王和小王的判断处理,具体实现代码如下

图示

(5)定义函数isCard,判断当前是不是一个有效的牌型,具体实现代码如下

图示

(6)定义函数getPokeType,获取当前牌的类型,具体实现代码如下

图示

图示

图示

图示

(7)定义函数shunzi,判断是不是顺子,具体实现代码如下

图示

图示

(8)定义函数getPokeCount,判断牌中同值牌出现的次数,即判断是对牌、三顺、三带一、炸弹和四代二等的个数。具体实现代码如下。

图示

(9)定义函数getPokeTypeValue,来判断牌的类型,具体实现代码如下

图示

图示

(10)定义函数compare来判断同一种类型牌的大小,即判断谁的牌值大。具体实现代码如下。

图示

图示

(11)定义函数outCardByItsself来随意出牌,通过case语句根据不同的牌类型获取值的大小。具体实现代码如下。

图示

图示

图示

(12)定义函数findTheRightCard,实现智能出牌功能,具体实现代码如下

图示

图示

(13)定义函数findBigThanCardSimple2,从pokes数组中找到比card大的一手牌,具体实现代码如下。

图示

图示

图示

图示

图示

图示

图示

图示

16.4.2 实现计分角色

计分角色实现文件是Card.java,通过函数paint实现绘制功能,具体实现代码如下

图示

图示

16.4.3 实现玩家角色

本项目的玩家角色实现文件是Person.java,游戏中的玩家有三个,其中两家是NPC。本文件的核心是判断出牌算法函数chupaiAI,实现下家出牌是否合理的判断。文件Person.java的具体实现代码如下。

图示

图示

图示

图示

图示

图示

16.4.4 实现游戏桌位角色

在本斗地主游戏项目中,桌位角色的实现文件是Desk.java。在一个游戏桌位中不但存储了三个玩家的共有信息,而且还存储了当前游戏的进度控制。因为本游戏是一个单机游戏,所以桌子(Desk)只有一个,桌子上有3个玩家(Person),其中两个是NPC玩家,一个是用户玩家,每一个玩家都有一把牌,17张或者20张,每一把牌都可以分成很多手牌(Card)。Desk是桌子类,它持有3个玩家的实例对象,负责为3个玩家分牌,控制出牌的顺序流程和当前分数的倍数等全局性信息。

文件Desk.java的具体实现代码如下。

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

16.5 实现牌面分析

在本项目中,实现牌面分析功能的实现文件是AnalyzePoke.java。此文件能够分析手中的所有牌,将各种牌型进行划分。牌面分析和牌类型的分析不同,牌面分析是对一副牌的分析上面是对一手牌的分析。对于开发者来说,类AnalyzePoke本来应该也放置在Poke类中,但是为了减少Poke类中的代码量,于是就将牌型的分析这个模块分离出来。在类AnalyzePoke中,最主要的方法就是分析方法,它将一副牌中所有的牌型全部分析出来(按照牌的威力大小依次下降而逐层分析),放置到各自的Vector容器中,这样就可以在需要的时候从各自的牌型中取得,或者进行组合得到。

文件AnalyzePoke.java的具体实现代码如下。

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

图示

除了前面介绍的类之外,还定义了一个存储不同数值的辅助工具类UniqInt,具体实现代码如下。

图示

图示

到此为止,整个斗地主项目全部介绍完毕。执行后将首先显示菜单视图界面,如图16-3所示。

单击“开始游戏”按钮后将来到游戏视图界面,如图16-4所示。

图示

图16-3 执行效果

图示

图16-4 游戏视图界面

↑上一章
关注公众号获取验证码
复制内容需要验证码(7.99元/天)