最近忙于各种学业问题,算法只能先搁置一波了……
本文出现的全部代码只是当时写完的版本,不是最终版本,最终版本(始终在更新)请移步github:MyPVZ
本来对大作业一筹莫展,在周日出去玩回来的地铁上被某人一语点醒:“可以做个植物大战僵尸呀!”
好,似乎植物大战僵尸也就是几个格子,判断一下碰撞之类的东西,应该比较好写,那就收集一下图片啥的资源开始做吧。(然而到现在还没写到判断碰撞的逻辑……真是太低估这东西的难度了)
2019.11.10
既然要写java,那得先会这门语言吧…还好两天前(周五)考过了java的期末,稍微搞明白了一点java与C系列语言直接面向过程编写代码的不同之处:首先得把一种东西视作对象,实现这个对象所要的需求,然后将这个对象实例化(new一个出来),进行所需要的一系列操作。
好像确实没什么的,那就开始写吧。
先找到了一份有img的源码,拿走img。
既然是个游戏,我寻思不然就用前几天刚分析的2048的套路,controller+view+model吧(不过搞到后来似乎都没有model)。
首先植物是个模型,先写个植物再说。
Plant.java
于是去学了一手JLabel和runnable实现动画效果,写了一下。
对于植物,实现了一些属性:名字name、价格price、血量hp、当前外观照片pic、产出冷却时间CD(产阳光、发射子弹等等)、图像是否可以修改canChange(update:当时觉得card类需要extend一下,所以留了这么一个接口,没想到以后card没用到,倒是其他地方起了作用)、控制器controller、位置row column、两次动画间隔时间sleepTime、对应卡片冷却时间cardCD。由于它们都是private的,需要很多public的接口供外面使用,所以添加了一堆东西,但这不是主要的。
1 | //active model of Plants |
同时实现了一些SunFlower、Plant初始化的小问题。
1 | public Plant getPlant(String name) { |
主要的就是两部分:重写paintComponent和重写run。这也是贯穿整个项目外观的两个重要部分:线程运行run,外观通过paintComponent改变。
paintComponent主要实现了当前JLabel标签的image,在植物方面大概只需要画底部阴影shadow和植物主体img就可以了。
run是Runnable接口调用的关键,是线程运行的主体。当植物存活的时候,不停积累产出冷却所需时间并重画(repaint),期间需要让线程sleep一段时间保证计算不过于频繁。
关于线程,参考资料:Java Thread线程使用、线程安全(一) - 简书
1 | void picChange() { |
大概plant部分就到此为止。
Controller.java
接下来就是最主要的控制器了。
控制器是各个部件的中枢,所有的对象通过这个控制器对其他对象产生影响。
所以除了要实现植物的矩阵之外,也要预留一下卡片、小车、僵尸、太阳等的位置(在此没有预留小车位置),同时在种植过程中,图片应当跟随鼠标进行显示,因此还需要一个鼠标事件监听器和JPanel。
同时,控制器需要向gameboardview传输信号,因此将整个gameboard作为一个JLayeredPane处理。
关于JFrame的层次结构,参考资料:JFrame 的层次结构 - CSDN
关于鼠标事件监听器,参考资料:MouseListener与MouseAdapter的区别 - CSDN
1 | package controller; |
2019.11.11
GameboardView.java
我就是调参大师.jpg
实现了上来左右摇摆对准的功能以及倒计时,并分配了cardboard的进入动画和鼠标图片topPanel。
移动方面有待改进……效果还可以,留到以后再改。
这部分对准参数之后没啥好说的。每个动画效果都是在不停的对坐标进行修改、对Panel进行repaint做出来的。
这里panel、Panel分别表示了背景图片和Panel,cardboard和Cardboard同理。这里命名有问题,以后再做修改。
1 | package view; |
LaunchFrame.java
实现了一个开始界面(留了很多余地给之后分配,这里不是游戏主体先不去做扩展)。
1 | package view; |
Main.java
?
1 | import view.*; |
写完这些之后终于可以运行了……感觉还不错(疯狂debug)
2019.11.12
把卡片和太阳给做了(
Card.java
卡片类,实现选中/非选中状态的图片切换,在Controller.java、Plant.java中也有对应修改,在此不放出。
TO-DO:实现进度条式改变冷却图片,不是只有一黑一白(注释掉了一行失败的尝试)。
1 | package view; |
Sun.java
阳光有两种方式生成,向日葵掉落或者随机从天上生成。分为三个阶段,掉落、停留、消失。掉落阶段一个是抛物线,一个是直线,分别模拟一下就可以了,这里抛物线用若干条线段进行模拟;停留阶段进行旋转;消失阶段进行边收集边消失或者直接淡出。
这里太阳逐渐消失用到了一个神秘函数:g2.setComposite(AlphaComposite.SrcOver.derive((float) alpha / 100));
其中alpha表示不透明度。
1 | package view; |
SunProducer.java
负责从天上随机掉落阳光。
1 | package view; |
到此为止,基本的向日葵有关的操作已经结束了。然后又向Plant、controller、card里面加了点关于豌豆射手的东西,接下来就该添加僵尸和子弹了。
这里用了个map存名字和植物类型的关系,大概可以参考一下java笔记–Map的用法 - CSDN
2019.11.15
由于前几天考计组,又在补作业,被迫停了一段时间。这段时间里,梳理了一下大致需要做的方向:
普通僵尸位置、碰撞、啃食、死亡逻辑;普通僵尸生成;子弹发射、碰撞逻辑;done
新植物及其逻辑;新僵尸及其逻辑;
对向日葵将要产出太阳时的动画进行优化;
设置关卡;
在初始界面设置其他操作;
在游戏中设置暂停、退出、重新开始、返回主菜单等功能。
不知道这些东西能实现到哪里?
Zombie.java
本以为僵尸不是那么难写,结果又要掉胳膊又要掉头还要有啃食动画,搞不好被樱桃炸弹炸糊了还得有个特殊的动画,这还不算多,搜了一下还有临界血量,低于这个血量虽然失去攻击力但还能吸收伤害并不断掉血……
好麻烦……
(还没写完,正在写)
(感觉真的好难写)
update: 写完了。
实现了走动、掉头(走动时及啃食时)、死亡的动画,实现了临界血量。
没掉胳膊,,,不想实现了(没图源),如果需要实现还要实现一个状态自动机。
1 | package view; |
ZombieProducer.java
实现随机生成一堆僵尸的功能,以后还需要改成一波波僵尸的样子来配合关卡。
1 | package view; |
Bullet.java
配合plant、controller对僵尸进行打击。
1 | package view; |
其他的controller、plant等部分也有很多调整,其中controller中实现了对于僵尸群的列表表示,使用了ArrayList类型的List分别表示五行中的僵尸,详情还是见github上的源码吧。
2019.11.16
添加了双发射手,修复了各种逻辑的小bug
并添加了etz阳光和xsy僵尸的逻辑(照片不上传)