基于Java实现的植物大战僵尸游戏
资源下载地址:https://download.csdn.net/download/sheziqiong/86812910
资源下载地址:https://download.csdn.net/download/sheziqiong/86812910
基于Java设计的植物大战僵尸游戏
一、植物大战僵尸游戏规则
游戏简介
玩家通过种植太阳花收取阳光来购买植物;通过种植不同的植物来抵御僵尸的攻击。当一个关卡里的僵尸全部被消灭时,玩家胜;当僵尸越过地图的右边界时,僵尸胜利。
植物简介
购买植物需要花费一定数量的阳光,每购买一次过后需要冷却一段时间才能再次购买。每个关卡允许使用的植物各有不同,不同植物的特性也不同
植物主要分为:攻击类,防御类和生产类。也可以分为夜间植物和白天植物(夜间植物只能在夜间出现)
攻击类
- 发射类
- 防御类
- 攻击增强类
发射类
当僵尸进入射手的射程内时,射手会发射豌豆攻击。
豌豆射手
- 单发射手
- 攻击:20
- 耐久:300
- 射程:正前方一整行
- 双发射手
- 发射速度是单发射手的两倍,其余同单发射手。
- 三线射手
- 该植物可同时向3排(植物所处排和左右排)同时发射出3颗豌豆 ,其余同单发射手。
- 寒冰射手
- 寒冰射手每次攻击发射一颗冰豌豆,命中目标后对僵尸造成伤害。其余同单发射手。
- 机枪射手
- 连续射出四发豌豆子弹
- 四倍的快乐
- 小喷菇(夜间植物)
- 小喷菇免费
- 射程短
- 胆小菇(夜间植物)
- 它是一种远程射手,敌人接近后会躲起来,不会攻击。
- 攻击:20
- 耐久:300
- 射程:正前方一整行
- 单发射手
爆炸类
- 樱桃炸弹
- 种下0.6秒后爆炸,能炸死3*3范围内的僵尸
- 火爆辣椒
- 种下0.75秒后爆炸,能炸死同排的僵尸
- 土豆雷
- 种下后2s后长大,在此期间可以被僵尸吃掉。
- 长大后进入等待状态,当同排僵尸距离土豆雷半格时,土豆雷爆炸,僵尸被炸死。
- 耐久: 300
吞食类
- 食人花
- 能够一口吞掉僵尸,然后要咀嚼消化一段时间,此时容易受到攻击。
- 耐久:300
攻击增强类
- 火炬树桩
- 用来增强豌豆植物发射的豌豆的火力,当豌豆划过树桩后,会变成火球,豌豆的威力变成2倍
- 但是如果穿过的是寒冰豌豆就会变成普通的豌豆了
防御类
- 坚果墙
- 攻击性:0(无攻击力)
- 防御力:3000(较高)
- 用于阻碍僵尸前进的步伐
- 高坚果
- 巨大的坚果,可以更好的阻挡僵尸前行
- 攻击性:0(无攻击力)
- 防御力:8000
生产类
生产阳光,供拾取购买植物
- 向日葵
- 可生产阳光
- 耐久:300
- 阳光菇(夜间植物)
- 白天睡觉,可在夜间生产阳光
- 耐久:250
- 双子向日葵
- 双份的阳光,双份的喜悦
- 耐久:300
僵尸简介
在游戏中,不同种类的僵尸会一波波的攻击。不同僵尸的攻击值,耐久,特性有所不同。
僵尸分为:
- 普通僵尸
- 游戏中最普通的花园僵尸
- 血量:270(普通)
- 攻击:啃食攻击,100/秒
- 速度:约4.7秒/格(普通)
- 旗帜僵尸
- 该僵尸是领头者,速度比普通僵尸快
- 血量:270
- 路障僵尸
- 防御能力是普通僵尸的两倍
- 血量:640
- 铁桶僵尸
- 防御能力比路障僵尸更强
- 血量:1100
- 橄榄球僵尸
- 速度很快,防御强于铁桶僵尸
- 血量:1160
- 读报僵尸
- 报纸可做防御,拿着报纸时速度很慢
- 多次受到攻击后失去报纸,防御变低,速度变快
- 血量:420
附加道具简介
- 小推车
- 位于最后防线的前方,当僵尸濒临最后防线时,小推车出动,将同排僵尸碾压致死。
- 阳光
- 可以靠天吃饭获得
- 可以生产类植物处获得
- 拾取后,可用来购买植物
关卡简介
逐个关卡击破,取得最终胜利。
关卡很有趣,请各位自行体验,这里不再赘述。
二、文档
1. 类图
整体:
核心部分:
大图见docs文件夹
2. 用例图
3. 时序图
I. 更新植物
II. 开始新游戏
III. 向僵尸总HP最少的行添加一个指定的僵尸
IV. 阳光下落
V. 向音频池添加游戏音效
三、项目完成情况
这是一份项目开始时准备的的TODO-List
游戏核心- [x] 单次派发系统- [x] 基于FSM的状态机制- [x] 基于多线程的音频池(使用.wav)- [x] 附带(类似)回调函数的杂项GIF播放系统- [x] 交互界面- [x] 开始界面- [x] 游戏界面- [x] 后院- [x] 卡牌槽- [x] 阳光槽- [x] 卡牌槽- [x] 卡牌- [x] 关卡进度- [x] 界面交互- [x] 放置植物- [x] 收集阳光- [x] 暂停界面- [x] 通关/失败提示- [x] 关卡设计- 考虑一关总僵尸量一定- 每间隔一段时间放置- 原则:- 在僵尸总HP最少的行上放置
植物- [x] 普通植物- [x] 向日葵- [x] 双子向日葵- [x] 豌豆射手- [x] 双发射手- [x] 三线射手- [x] 机枪射手- [x] 寒冰射手- [x] 坚果墙- [x] 高坚果- [x] 食人花- [x] 樱桃炸弹- [x] 火爆辣椒- [x] 土豆雷- [x] 火炬树桩- [ ] 夜间植物- [x] 小喷菇- [x] 胆小菇- [ ] 大喷菇- [x] 阳光菇
僵尸- [x] 普通僵尸- [x] 旗帜僵尸- [x] 路障僵尸- [x] 铁桶僵尸- [x] 橄榄球僵尸- [ ] 小丑僵尸- [x] 读报僵尸- [ ] 撑杆跳僵尸
子弹类- [x] 豌豆- [x] 冰豌豆- [x] 燃烧豌豆- [x] 孢子- [ ] 大孢子(大喷菇)
四、附录
(魔幻)植物大战(成精)僵尸扩展编程不Van全指南
原理简介
一、名词解释
- FSM,有限状态自动机,一个FSM相当于一个独立的AI系统,每一个能够独立动作个体都拥有属于自己的FSM系统。举几个例子
- 豌豆射手拥有以下几种状态
- 0:待机态,没有可以攻击的僵尸
- 1:攻击态,攻击态=攻击+CD
- 2:HP耗尽,立即被回收
- 普通僵尸拥有以下几种状态
- 0 : 待机态,未出场
- 1 : 有头行走
- 2 : 有头攻击
- 3 : 无头行走
- 4 : 无头攻击
- 5 : 被炸死,立即被回收
- 6 : 无头死亡(正常死亡),立即被回收
- 一个状态又两部分组成,一是表示状态的数字,这个数字是这个状态的唯一标示,二是状态附带的动作,即个体被判定处于这个状态后应该执行的操作。例子接上面
- 对于豌豆射手
- 0/1:
- 当HP耗尽 -> 2
- 0:
- 当观测到有可攻击的僵尸 -> 1
- 1:
- 当不再有可攻击的僵尸(上面的检测条件添加
.negate()
即可实现) -> 0
- 当不再有可攻击的僵尸(上面的检测条件添加
- 0/1:
- 对于普通僵尸
- 1/2/3/4:
- 当受到足以致命的爆炸伤害 -> 5
- 3/4:
- 当HP耗尽 -> 6
- 1:
- 观测到可攻击 -> 2
- HP低于阈值 -> 3(掉头行走)
- 2:
- 不再可攻击(等价于(1->2)
.negate()
) -> 1 - HP低于阈值 -> 4(掉头攻击)
- 不再可攻击(等价于(1->2)
- 3:
- 观测到可攻击 -> 4
- 4:
- 不再可攻击(等价于(3->4)
.negate()
) -> 3
- 不再可攻击(等价于(3->4)
- 1/2/3/4:
- 要求:
- 任何对于死亡的检测必须写在前面,因为没有实现状态转移的优先级,当检测到可满足的转移条件后就不再检测其他条件
- 对于豌豆射手
- 豌豆射手拥有以下几种状态
- 函数式编程,本项目使用函数编程接口
Predicate
:- 接受参数并返回
true/false
- 用作检测是否满足转移条件
- 程序中使用
BiPredicate
,接受两个参数,一是游戏棋盘的总体,二是实体本身
- 接受参数并返回
Consumer
- 接受参数并执行,无返回值
- 用作状态的执行
- 程序中使用
BiConsumer
,接受两个参数,同上
- 音频池,用来播放游戏中的音乐与音效
- 背景音乐,同一时刻只允许存在一个背景音乐,且背景音乐自动设置为循环播放
- 游戏音效,子弹击中僵尸、僵尸啃噬植物等均为音效,一经添加立即播放,播放完毕后释放资源(由JVM接管)
二、代码组织形式
- 库组织形式
model
模型base
基本类型bullets
子弹plants
植物sound
音频zombies
僵尸level
关卡
view
视图渲染部分controller
用户交互界面
- 游戏棋盘
GameBoard
成分- 僵尸图
zombieMap
- 植物图
plantMap
- 子弹图
bulletMap
- 杂项图
extraMap
- 阳光图
sumMap
,原本设计在杂项里,但考虑到检测的效率,故独立之
- 僵尸图
核心API讲解
注意,本部分代码因项目后期没有维护,可能已过时,详情请参考具体代码
abstract void setStateTable(); //设置状态表
- 任何继承
Root
的子类都必须实现的方法 - 以豌豆射手
Pershooter
类为例:protected void setStateTable() {// 0 : 正常// 1 : 攻击// 2 : HP耗尽BiConsumer<GameBoard, Root> attack = ((gameBoard, root) ->// 攻击时应该做什么{if ((intervalCount++) % attackPerTicks == 0){Plant pt = (Plant) root;for (Object ob : gameBoard.zombieMap.getRow(pt.getY())){Zombie zb = (Zombie) ob;if (zb.getX() - pt.getX() <= MAX_PROBE_RANGE){gameBoard.bulletMap.getRow(pt.getY()).add(new BeanBullet(pt.getX() + pt.getWidth() / 2, pt.getY()));SoundPool.addSound(GameRule.choice(GameRule.pea_shoot));return;}}}});addState(0, "peashooter.gif", null);addState(1, "peashooter.gif", attack);addState(2, "peashooter.gif", (gameBoard, root) -> finish = true); }
- 类中的方法
addState
- 接受两个参数
- 方法签名为
void addState(int state, String fName, BiConsumer<GameBoard, Root> action)
state
为当前状态码fName
为状态要播放的gif,可为null
action
为BiConsumer
,是该状态要执行的操作,可为null
- 任何继承
abstract void setStateTransfer(); //设置转移条件
- 任何继承
Root
的子类都必须实现的方法 - 以豌豆射手
Pershooter
类为例:protected void setStateTransfer() {// BOTH -> HP耗尽死亡addTransfer(new int[] {0, 1}, 2, ((gameBoard, root) -> hp <= 0));// 待机 -> 开始攻击addTransfer(0, 1, getAttackTransfer(MAX_PROBE_RANGE));// 攻击 -> 待机addTransfer(1, 0, getAttackTransfer(MAX_PROBE_RANGE).negate()); }
- 类中的方法
addTransfer
- 接受三个参数
- 方法签名为
void addTransfer(int from, int to, BiPredicate<GameBoard, Root> cond)
from
为来自的状态to
为满足cond
后转移到的状态cond
为BiPredicate
,是状态转移条件- 还定义有方法
void addTransfer(int[] froms, int to, BiPredicate<GameBoard, Root> cond)
froms
数组中各元素都会被展开成原方法形式- 旨在实现快速添加对象死亡的转移条件
- 任何继承
音频池
SoundPool
系统- 音频池为游戏提供了背景音乐与游戏音效支持
public static void addSound(String fName)
- 添加音效
- 音效会被立刻播放
- 播放结束后自动回收
- 一时刻可能有很多很多音效在播放
public static void setBGmusic(String fName)
- 设置背景音乐
- 音乐会被立刻播放
- 音乐循环
- 每一时刻只能有一首正在播放的BGM,重设后会替换原BGM
- 注意
- 上述两方法为静态方法,调用方式为
SoundPool.addSound(xxxxx);
SoundPool.setBGmusic(xxxxx);
- 编码人员不用创建该类的任何实例,两静态方法会自动处理
- 上述两方法为静态方法,调用方式为
- 现状:音频系统是引起游戏很卡的罪魁祸首
[完成]初步优化:使用字典管理正在播放的音频,限制同一音频最多同时播放3个,稍有改善
[待进行]进一步构思:
- 使用线程池技术,预先开辟线程,消除线程构造与回收造成的系统资源消耗
关卡
Level & LevelManager & LevelFactory
系统Level
: 保存一个关卡的信息LevelManager
: 组合一个Level
并被多个类所传递,用于获取关卡信息与处理游戏胜负LevelFactory
: 关卡工厂,想添加新的关卡就写在这里- 如何写一个新关卡:
- 你需要提供
- 关卡的编号
- 出现在本关的所有僵尸与他们的数量
- 总波数
- 总时间
- 下一关的编号(-1代表结束)
- 可以使用的植物
- 场景图片
- 背景音乐
- 是否从天上掉落阳光
- 掉落阳光的间隔是多少
- 预先设置的植物
- 编写成代码:
Level level = new Level(); HashMap<String, Integer> zombieCount = new HashMap<>(); ArrayList<PlantInfo> cards = new ArrayList<>(); ArrayList<PreSetPlant> pres = new ArrayList<>(); zombieCount.put("normal_zombie", 10); // 10个普通僵尸 zombieCount.put("football_zombie", 10); // 10个橄榄球僵尸 zombieCount.put("buckethead_zombie", 5); // 5个铁桶僵尸 zombieCount.put("conehead_zombie", 5); // 5个路障僵尸 zombieCount.put("newspaper_zombie", 5); // 5个读报僵尸cards.add(new PlantInfo("Chomper", 50, 2)); // 可使用食人花, 花费50阳光,冷却2s cards.add(new PlantInfo("Jalapeno", 50, 2)); // 火爆辣椒 cards.add(new PlantInfo("Peashooter", 100, 2)); // 豌豆射手 cards.add(new PlantInfo("Threepeater", 100, 2)); // 三发射手 cards.add(new PlantInfo("CherryBomb", 100, 2)); // 樱桃炸弹 cards.add(new PlantInfo("ScaredyShroom", 100, 2)); // 胆小菇// 预设植物, new (name, col, row) pres.add(new PreSetPlant("PotatoMine", 5, 0)); pres.add(new PreSetPlant("PotatoMine", 5, 1)); pres.add(new PreSetPlant("PotatoMine", 5, 2)); pres.add(new PreSetPlant("PotatoMine", 5, 3)); pres.add(new PreSetPlant("PotatoMine", 5, 4));level.setLevelNumber(1) // 关卡编号1.setZombies(zombieCount) // 设置所有僵尸(见上方).setWaves(10) // 10波.setLevelTime(50) // 50秒(最后一波僵尸出现的时间).setLevelNext(2) // 下一关进入编号2.setPlantInfos(cards) // 设置可使用的植物.setlevelImg(GameRule.backgroundDay) // 关卡背景.setLevelBgmusic(GameRule.dayBG) // 背景音乐.setDropSun(true) // 白天,从天上掉阳光.setDropSunPerSeconds(5) // 第一关,阳光掉落频繁.setPrePlants(pres); // 预设植物,可为空
- 由于大量使用了Java的反射机制,使得程序具有特别强大的灵活性,可以看出,仅需要一个字符串便能调用一个类
- 所以,新建一个关卡只需要填写很少的代码
- 由于植物的花费与冷却时间可控,我们还可以做出许多有趣的小游戏,比如:
- 一关只允许使用爆炸物,且爆炸物冷却时间极短而且花费很低
- 一关的高坚果与坚果墙十分廉价,但攻击方式只有普通豌豆射手
- 更多脑洞任君开发
- 你需要提供
僵尸、植物、子弹或杂项何时被系统删除
- 在
Root
类中有一名为finish
的布尔型变量,一旦为true
,则会在最近一次的更新中被移除 - 对于动画,例如僵尸的倒下死亡或被炸死,有两种处理思路
- 转移到这个状态,播放这个gif,
sleep
对应时间后在设置为finish=true
- 转移到这个状态,立刻设置为
finish=true
,在杂项map
内添加这样的gif
- 转移到这个状态,播放这个gif,
- 本程序在简洁性与易扩展型的考量下决定使用后者,具体使用方法举例如下:
// 僵尸被炸死 addState(5, null, (gameBoard, root) -> {finish = true;gameBoard.extraMap.add(new Extra(getPath() + "boom_die.gif", 3500, getX(), getY())); });// 僵尸HP耗尽 addState(6, null, (gameBoard, root) -> {finish = true;gameBoard.extraMap.add(new Extra(getPath() + "nohead_die.gif", 1500, getX(), getY())); });
Extra
类的构造函数签名如下public Extra(String fName, int ms, int x, int y, boolean bullet)
- 与
public Extra(String fName, int ms, int x, int y)
- 其中
fName
为需要播放的gif文件ms
为gif所需执行时间,用于Thread.sleep()
x
,y
,物体坐标bullet
,是否为子弹,true
代表是,不填为否
Extra
类被构造后会在最近一次的更新中被添加- 在延迟时间到后自动被回收,实现方法同为
finish=true
- 在
raMap.add(new Extra(getPath() + “nohead_die.gif”, 1500, getX(), getY()));
});
```
- Extra
类的构造函数签名如下
- public Extra(String fName, int ms, int x, int y, boolean bullet)
- 与public Extra(String fName, int ms, int x, int y)
- 其中
- fName
为需要播放的gif文件
- ms
为gif所需执行时间,用于Thread.sleep()
- x
, y
,物体坐标
- bullet
,是否为子弹,true
代表是,不填为否
- Extra
类被构造后会在最近一次的更新中被添加
- 在延迟时间到后自动被回收,实现方法同为finish=true
END
资源下载地址:https://download.csdn.net/download/sheziqiong/86812910
资源下载地址:https://download.csdn.net/download/sheziqiong/86812910
基于Java实现的植物大战僵尸游戏相关推荐
- java设计建议植物大战僵尸_基于Java的游戏设计之植物大战僵尸
植物大战僵尸这款游戏相信大家或多或少都玩过,那么大家有没有想过自己尝试着做一下植物大战僵尸的游戏设计呢.本文将基于Java语言为大家展示如何开发出植物大战僵尸游戏的简易版本,主要内容包括规则.对象.功 ...
- 基于python的植物大战僵尸游戏开发
1 简介 今天向大家介绍一个帮助往届学生完成的毕业设计项目,基于python的植物大战僵尸游戏开发. 计算机毕业生设计,课程设计需要帮助的可以找我 2 设计概要 21世纪是信息化时代,随着信息技术和网 ...
- 用Java实现一个简易的植物大战僵尸游戏
今天给大家分享一个简易的植物大战僵尸游戏,用Java编写,还是挺好玩的. 一.设计思路 1.植物大战僵尸运用Java基础实现,通过滚轮上选择植物,随机生成各种类型僵尸,以及植物. 2.玩家可以安放各种 ...
- python版植物大战僵尸源码_基于python的植物大战僵尸游戏设计与实现.docx
湖南理工学院毕业设计(论文) PAGE PAGE 1 学 号 毕业设计(论文) 题目:基于python的植物大战僵尸游戏设计与实现 作 者 届 别 届 院 别 信息与通信工程学院 专 业 信息工程 指 ...
- java植物大战僵尸 论文_java实现植物大战僵尸游戏
植物卡片框 */ public class PlantsBar implements GuiConstnat { // 卡片格子数量 private int plantSum; // 太阳数量和卡片选 ...
- 用Java写一个植物大战僵尸简易版!
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | https://urlify.cn/byeEj ...
- 用 Java 写一个植物大战僵尸简易版!
点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:2 个月的面试亲身经历告诉大家,如何进入大厂? 有谁没玩过植物大战僵尸吗?一位读者用Java语言开发了自己的植物 ...
- 用 Java 写一个植物大战僵尸简易版
转自:公众号:程序员小灰 作者:林Lychee 前言 有谁没玩过植物大战僵尸吗? 有一位读者,用Java语言开发了自己的植物大战僵尸游戏.虽然系统相对简单,但是麻雀虽小五脏俱全,对游戏开发感兴 ...
- 【Unity3D开发小游戏】《植物大战僵尸游戏》Unity开发教程
推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 文章目录 一.前言 二.源码 三.正文 版本 1.主摄像机设置 2.创造草地 ...
- 基于Java实现的Android拼图游戏设计
资源下载地址:https://download.csdn.net/download/sheziqiong/85638665 基于Java实现的Android拼图游戏设计 游戏效果 一.Android ...
最新文章
- 【OpenCV 4开发详解】图像连接
- Java基础-流程控制
- 百练OJ:2764:数根
- 手写简版spring --6--应用上下文(BeanPostProcessor 和 BeanFactoryPostProcessor)
- @Scheduled(cron = 0/5 * * * * *)将时间改为配置
- MySQL覆盖索引:直接从索引查询到了数据
- JAVAAPI之STRING类和STRINGBUFER类
- pytorch学习 训练一个分类器(五)
- 一图解析MySQL执行查询全流程
- js中的字符串方法与数组方法总结
- 你的第一个Windows程序——绘制窗口
- ping,python实现批量ping包工具--小案例
- ajax 跨域 提交cookie,Ajax跨域请求COOKIE无法带上的完美解决办法
- BC26opencpu
- webssh的安装与使用
- LibOpenCM3(二) 项目模板 Makefile分析
- wordpress themeforest
- java 方法继承方法_java的继承原理与实现方法详解
- 853计算机综合基础包括什么,2017年南京农业大学853计算机专业基础综合硕士研究生参考书目...
- 怎样卸载腾讯网页游戏微端服务器,如何删除腾讯页游微端启动器
热门文章
- 一个SQL SERVER查询分析器非常好用的工具
- 15个基本不定积分公式和分类基本积分表
- win98 支持html5,90后第一次接触Windows98,20多年了,居然还有人使用!
- linux终端怎么设置monaco,[Linux]Vim设置Monaco字体Vim颜色模板
- 维修频谱分析仪多少钱?简单告诉你,频谱分析仪维修实例报价
- VBScript入门篇
- cesium实现自定义地球球体背景效果
- android配置网络权限管理,Android 网络权限配置
- 启动U盘更换背景图片和图标的方法
- 分享【免费】【英语听力】【背单词】练习网站和微信小程序 博主:杨中科