欢迎光临散文网 会员登陆 & 注册

植物大战僵尸一代毕业论文(5)

2019-08-26 09:45 作者:嘻哈宙帝  | 我要投稿

第5章 详细设计与实现

5.1 搭建游戏基本框架

5.1.1 WELCOME(欢迎界面)类

这是游戏的欢迎界面类,此类定义了开始游戏按钮的横坐标、纵坐标等,用draw()函数来绘制欢迎界面的一些图片按钮和主界面的背景。设计中还用到了onTouchEvent()函数来回应并控制玩家在图片按钮区域所触发的ACTION_DOWN事件,其目的就是用来控制和显示按钮所按下的图片。

在玩家触发完成ACTION_UP事件后,按钮图片将会被改变为未按下状态并会通过MainSurfaceView.gameState = MainSurfaceView.GAME_MENU代码将游戏转到主菜单界面。

5.1.2 MENU(菜单)类

游戏菜单,用boolean类型定义按钮是否按下状态,并初始化值全部为false。在主菜单界面设计中的布局绘制菜单选项涉及到的全部按钮。

用ACTION_DOWN或者ACTION_MOVE来检测每个按钮的状态,(是否被按下),如果是被按下的,则会在draw()函数中绘制按钮被按下状态时的相对应的图片。然后会在ACTION_UP事件中会把按钮的状态重新修正并且游戏界面会跳转到相应的游戏状态,就拿“游戏帮助”来说,点击“游戏帮助”后调用MainSurfaceView.gameState =

MainSurfaceView.GAME_HELP改变游戏状态。如果点击“退出”,则调用System.exit(0),系统退出游戏。

5.1.3 HELP(游戏帮助)类

Help类主要是给玩家提供相关帮助信息,把内容绘制在一张图片上,玩家需要帮助时可以打开此功能,该类通过把帮助图片显示在屏幕上,方便玩家查看。点击屏幕即可触发ACTION_UP事件,回到主菜单界面。

5.1.4 SELECT(游戏选项)类

为玩家提供游戏选项的一个类。玩家点击屏幕的不同游戏模式触发ACTION_UP事件,控制玩家进入不同的游戏。

接着在MainSurfaceView类中将游戏状态gameState初始化为GAME_WELCOME,定义并初始化SELECT类,在myDraw()状态下调用draw()函数,在onTouchEvent()状态调用onTouchEvent()函数。

5.2 游戏MODEL包

5.2.1 Plant接口

种植植物是按照坐标来种植的,五条线路来显示植物和僵尸的作战区,不能随便选取,每条路线都有九个格子的位置可以用来种植植物,玩家只能在这些规定的格子内种植植物,布局中,我们定义了54个这样的格子,并且规定每个格子能且只能栽种一种植物,不可以种植多种,就算是同一种植物也不可以在同一个格子里面种植。每个格子都有一个属于自己的编号,起作用是为了记录该区域是否已经种植了植物。该接口是用来实现getMapIndex()方法。

5.2.2 BaseMadol(基本)类

在游戏中,无论是植物单位,僵尸单位或者种子选择栏中的种子,他们都会有一些共同的方法或者属性,就如他们的坐标,即这些图片所在的位置。为了减少代码的编写量,也方便查看,在面向对象中我通常会将各个类的公共部分编写成一个类,方便其他类的调用。所以在程序中建立了这所有的公共父类BaseMadol。

5.2.3 Config(变量)类

Config类是用来全局变量的,这些都是游戏中所需要的变量。为什么要这么做,因为开发过程中测试是必须的,为了能够快速完成这个过程,要修改上述这些变量,当不是设置成全局变量将可能浪费大量时间做重复的修改操作

该类还定义了游戏中所有对象的图片素材。普通类不能从图片工厂中获取图片,普通类如果要使用图片都会从构造函数中传递进去,如果以此方法使用的多了,这将使程序显得混乱,不方便管理。

该类还定义了所有植物种植点。

5.3 游戏具体实现及相关的实体类

5.3.1 太阳花的种植及其产生阳光实现

太阳花卡片我们用SunSeed类定义,它就是继承了BaseMadol类,实现了TauchAble接口。除了定义其坐标、是否存在的成员变量外,还定义了一个触摸区域。它的成员变量及成员方法如图5.1。

图5.1 SeedFlower类成员变量及成员方法示意图

SeedFlower():SeedFlower类的构造函数,在这里的属性我们会将其初始化,我们isAlive默认为true。

drawSelf():绘画函数,主要功能是实现能在各个位置下显示种植的太阳花种子。具体实现方法如下。

onTouch():对触屏事件处理,在该函数中它会首先记录玩家点击的触摸点坐标,检测touchArea.contains(pointX,pointY) && Config.sunshineValue>=Config.flowerCost,如果成立,就会此坐标显示一个玩家所要种植的植物,这个功能用定义在Game类里的apply4EmplacePlant(int locationX,int locationY)函数来实现。该函数会检测所要种植的植物并创建一个要被种植的植物对象。

EmplaceFlower类是玩家所选择的并且将要被种植的太阳花类,也是继承自BaseMadol,实现了TauchAble接口。

touchArea:手指触屏跟随区域,根据构造函数所接收到的参数,为即将种植太阳花大小的区域进行初始化。

Flower类是玩家可以看到的显示屏上已经种植的太阳花,也是继承自BaseMadol,实现了Plant接口。不仅有从父类继承来变量,它还有属于自己新增成员变量:frameIndex和长整型变量lastShineTime,他们用来表示太阳花位图数组下标,所在格子编号。如图5.2。

图5.2 Flower类成员变量及成员方法示意图

drawSelf():绘图函数,绘制当前帧的图片。

Sunshine类,太阳花所生产出来的阳光值,每10s都会产生一个。此类只存在5s,在这段时间内,如果玩家点击了阳光,那么对应的阳光值就会得到增长,每个增加50,要是在这5s内没有点击到,那么阳光机会自动消失。从上述设计可以知道阳光有两种状态,一种是显示状态,另一种是待拾取状态。

drawSelf():在阳光存活状态下,若它此时是SHOW状态,判断阳光存在时间是否已经有5s,如果存在时间已经过了5s,那么isAlive值就将被赋值为false,如果没有的话,就不会进行任何操作。在MOVE状态下,此时,阳光的横纵坐标就会以xSpeed,ySpeed的速度递减,当到达上边边界时,即当纵坐标小于屏幕的边界时,此时显示栏的阳光值就会显示增加50,并且isAlive就会被赋值为false。

当玩家点击到阳光时,此时它的状态就会被设置为MOVE,并且记录运动起点到终点的横纵距离,分别用xDistance,yDistance表示,然后将xSpeed,ySpeed分别设置为xDistance/5f,yDistance/5f。

状态图如图5.3所示。

图5.3 阳光的状态图

5.3.2 豌豆射手种植及射击实现

根太阳花一样,我们也定义SeedPea、EmplacePea、Pea、Bullet,其中SeedPea、EmplacePea、Pea前三个类与太阳花相似。

Bullet:炮弹类,也是继承自BaseMadol。游戏中我们用xSpeed来表示炮弹在水平方向的移动速度,其初始值为5。在它的drawSelf()函数中,炮弹被先画出来,接着给它的横坐标加上xSpeed,这样,在我们看来,炮弹就是在直线匀速运动的,当炮弹越过右边边界时,那么isAlive就会自动设置为false。若炮弹与僵尸碰撞,我们用getModelWidth()方法来处理此事件。

5.3.3 生成僵尸的实现

Zombie类(僵尸类)继承BaseMadol。构造方法参数也会用到僵尸刚生成使得坐标,用raceWay来传递一个整型变量来表示跑道,简单的来说,就是僵尸进攻的线路,在做碰撞检测的时候,系统会检测跑道上的炮弹和所种植的植物。由于僵尸是横向向着屏幕的左边移动,所以在drawSelf()函数中要在绘制每一帧之后再把动画帧下标加一,然后它的横坐标还要减去僵尸前进的速度xSpeed。

为了方便管理僵尸的生成,我们定义了一个ZombieManager类,此类会控制僵尸在15s随机生成一类的僵尸。我们用以下方法来实现僵尸的生成:

public boolean isExistPlant(int key,int raceWayIndex) {

switch (raceWayIndex) {

case 0:

for (BaseModel model : gameLayout4plant0) {

if (model instanceof Plant) {

if (key == ((Plant) model).getMapIndex())

return false;

}

}

break;

„„

}

return true;

}

5.3.4 游戏管家

此游戏是通过不断绘制图片来,因此必须非常清楚的划分回吐的顺序,不然会产生非正常的覆盖将大大影响游戏的视觉效果。最后画的元素覆盖在屏幕最上层,并且将其规定为第一层,依次类推。

种植植物时,我们设定种子图片是随着玩家的手指移动而移动的,这个时候种子图片显示在所有屏幕对象的最上边,为第一层,最后画这一层。植物的种子设定为第2层,阳光则规定为第3层,然后将植物、僵尸、炮弹统一设定为第4层。定义容器gamesLayout1,gamesLayout2,gamesLayout3分别用来表示第1、2、3层容纳的单位。用gamesLayout4plant0,gamesLayout4zombie0表示第4层第一条跑道植物和僵尸单位。剩下的跑到依次类推。定义createElement()为阳光值Config.sunshineValue赋初值为100,初始化各种容器,并且新建会SeedFlower、SeedPea类对象seedFlower、seedPea,将他们初始化到种子栏中相应位置,用gamesLayout2.add()添加到第二层。用如下代码来设计植物与僵尸的跑道:

(以下代码就不用突出功能强调)

private void createElement() {

„„

for (int i = 0; i < 5; i++) {

for (int j = 0; j < 9; j++) {

Config.plantPoints.put(i * 10 + j, new Point((j + 2)* Config.screenW / 11

- Config.screenW / 11 / 2,(i + 1) * Config.screenH / 6 - 10));

if (j == 0) {

Config.raceWayYpoints[i] = (i + 1) * Config.screenH / 6- 10;

}

}

}

}

以下代码是用来记录植物并添加植物到相应的跑道的植物容器里面:

public void apply4Plant(int locationX, int locationY, BaseModel baseModel) {

„„

for (Integer key : Config.plantPoints.keySet()) {

point = Config.plantPoints.get(key);

if ((Math.abs(locationX - point.x) < Config.screenW / 11 / 2)

&& (Math.abs(locationY - point.y) < Config.screenH / 6 / 2)) {

int raceWayIndex = 6;

for (int i = 0; i < Config.raceWayYpoints.length; i++) {

if (point.y == Config.raceWayYpoints[i]) {

raceWayIndex = i;

}

}

„„

}

}

}

游戏的初始化:

/**

* 初始化游戏基本参数

* @param plantTypes

*/

public void initGameParas (ViewGroup root,int type, int[] plantTypes) {

// 获取屏幕宽高

ScreenWidth = ((Activity) getContext()).getWindow().getWindowManager()

.getDefaultDisplay().getWeight();

ScreenHeight = ((Activity) getContext()).getWindow().getWindowManager()

.getDefaultDisplay().getHeight();

// 初始化植物、僵尸、子弹、卡片管理者

plantMgr = new PlantManager(getResources());

zoManager = new ZoobieManager(getResources());

bulletManager = new BulletManager(getResources());

CardManager(getContext(), root,plantTypes); cardManager = new

sunManager = new SunManager(getResources());

// 初始化游戏线程

gameDrawThread = new GameDrawThread(surfaceHolder, plantMgr, zoManager,

bulletManager, sunManager, choooseDayOrNight(type));

}

5.3.5 根据有无僵尸判断是否射击

根据需求,只有当跑道有僵尸时豌豆射手才需要发射炮弹,当该跑道还没有生成或所有僵尸时豌豆射手将不会射击,即不发射炮弹。在Pea类中,isShoot用来表示定义的一个布尔变量,其初始值设为false,定义其get、set方法,检测isShoot值是否为true,true时调用shootBullet()函数。在Game类apply4AddZombie()中当产生僵尸的时候,检测该产生僵尸的跑道是否有豌豆射手存在,如果有,那么isShoot就被设置为true,如果没有,那么依然为false。然而若是在产生僵尸时判断是否有豌豆射手,每次都要对isShoot判断。所以应当在豌豆射手发射炮弹时检测是否有僵尸在跑道上,如果有僵尸则发射导弹,否则不发射。

5.3.6 僵尸碰到植物停止当吃掉植物后继续前进

当僵尸和植物相遇后就会停止前进,此时,僵尸开始进食植物,在此过程中,植物会抵抗3s,接着,僵尸还会继续前进。在Zombie类中用布尔变量isMove来定义僵尸的活动状态,并初始化为true、僵尸碰撞植物后用变量eatTime(长整型)记录此时系统时间,并设置变量get(),set()属性。在僵尸横向移动代码上添加条件语句:只有isMove为true时僵尸才从右向左移动。在Game类中当碰撞函数检测到僵尸与植物碰撞时,若僵尸还处于移动状态,则使其停止前进,将这刻系统时间用zombie.setEatTime(System.currentTimeMillis())记录。当僵尸与植物的接触超过3s时,系统将植物isAlive赋值为false,此时植物即被吃掉消失,然后僵尸会继续进攻,向左屏幕前进。


植物大战僵尸一代毕业论文(5)的评论 (共 条)

分享到微博请遵守国家法律