基于JavaFx的多线程葫芦娃打斗游戏

Jasmine

发布日期: 2019-05-14 17:41:43 浏览量: 479
评分:
star star star star star star star star star star_border
*转载请注明来自write-bug.com

关键词

  • 战斗

  • JavaFx

  • Maven

  • 多线程

  • 过程记录和过程复现

一、故事背景

狭路相逢勇者胜,葫芦兄弟和老爷爷在山洞中与众妖精决一死战!一断江湖,啊不,葫芦山恩怨!

在武侠的BGM下,葫芦娃和妖精进行搏斗,在刀光剑影中(特效),大地仿佛在颤抖,伴随刀剑声音,到底谁能最后一统江湖,啊不,葫芦山?

效果展示:BGM和战斗音效请脑补

二、类的设计

2.1 生物类的设计——没有人怎么打?

我设计了一个Creature类,它是所有生物的父类,其中葫芦娃,爷爷是继承了生物体,而蝎子精,小怪,蛇精都是它们所有都归属于一个相同的类——Monster类,从而完成了所有类的设计,在逻辑伦理上容易实现,最后我利用了动态绑定的特征,就可以使用Creature来进行相同的操作但是复写了接口,从而实现了之后移动,攻击和技能(准备附加功能)的接口,在线程中保证了安全性。

同时Creature继承了Fighting接口,里面实现了大战的方法,这是在第三次作业上的迭代,让我体会到了JAVA继承,接口等机制的方便之处。

这样,我们就可以创造葫芦娃和妖精了!

  1. public class Creature implements Fighting{
  2. int i; //在棋盘里面的位置
  3. int j;
  4. String name;
  5. boolean nature;
  6. Image image; //显示图片
  7. Image battle_Image;
  8. Image dead_Image;
  9. //引入战斗序列
  10. int total_blood; //总体的血量
  11. int cur_blood; //当前的血量
  12. boolean TypeOfAttack; //近程攻击还是远程攻击
  13. int power_of_attack; //攻击力
  14. int power_of_defence; //防御力
  15. MediaPlayer sound_of_battle; //战斗音响
  16. Media source_of_sound;
  17. boolean isAlive;
  18. //这些都是Creature的共有属性
  19. }

通过这些共有属性,我们可以创建各种有画面有战斗音效的葫芦娃了!

2.2 葫芦娃的放置

葫芦娃怎么放置呢?我设计了一个战场类Battlefield,这个战场类中有10*20大小的Position类,每个Position就是一个位置,能够作为一个容器(Holder),来存放一个Creature,这样我们就可以在战场中放置我们可爱的葫芦娃了。

  1. public class Battlefield {
  2. private int x; //宽
  3. private int y; //高
  4. private boolean war_start;
  5. private thePosition[][] field;
  6. public void ...//实现的函数
  7. }
  1. public class thePosition
  2. {
  3. private Creature creature;
  4. private int i;
  5. private int j;
  6. private boolean empty;
  7. thePosition(int i,int j) {
  8. this.i = i;
  9. this.j = j;
  10. this.empty = true;
  11. creature = null;
  12. }
  13. }

上述的理解设计是我在曹老板的启发下写的,对那句“葫芦娃每个站在一个荷叶上,通过荷叶的移动来改变位置”印象深刻,给了我很大的启发,让我明白一个战场不仅仅是一个二维数组那么简单,同时也是一个对象!万物皆对象。

2.3 葫芦娃的阵型选择

谁来指挥葫芦娃排好阵型?

万物皆对象,创建一个类告诉他们如何排就好了!

  1. enum FormationName {
  2. HEYI("鹤翼"),YANXING("雁行"),CHONGE("衝軛"),
  3. CHANGSHE("长蛇"), YULIN("鱼鳞"), FANG("方块"),
  4. YANYUE("偃月"), FENGSHI("锋矢");
  5. private String name;
  6. FormationName(String name) {
  7. this.name = name;
  8. }
  9. public String getName() {
  10. return name;
  11. }
  12. }

先用enum类型定义了所有阵型的属性名称,通过这些名称,我们就可以清楚的知道我们创建的类的名称和变量一一对应起来了!

  1. public class Formation {
  2. public void changeFormation_mon(int index, Scorpion scorpion, Follower[]follower, Battlefield ground)
  3. {
  4. switch (index)
  5. {
  6. case 0: ...;break;
  7. ...
  8. default: ;break;
  9. }
  10. }
  11. }

这个Formation类可以通过名称和下标让你控制排的阵型!所以通过这个接口来让我们的葫芦娃按照我们的阵型选择进行排序!

以上可以说是前三次代码的复用和拓展,那么如何实现本次的代码呢?

2.4 图形化:JAVAFX!

利用javaFX框架来写,进行编写,还可以用可视化的编辑器SenceBuilder进行编写,这样就可以编写出能够交互的可视化的界面

  1. public class Main extends Application {
  2. @Override
  3. public void start(Stage primaryStage) {
  4. try {
  5. Parent root = FXMLLoader.load(getClass().getResource("/MainScreen.fxml"));
  6. Scene main_sence = new Scene(root); //创建一个新的Sence
  7. primaryStage.setTitle("qun's CalaBash_Brothers");
  8. primaryStage.setScene(main_sence);
  9. primaryStage.show();
  10. } catch(Exception e) {
  11. e.printStackTrace();
  12. }
  13. }
  14. public static void main(String[] args) {
  15. launch(args);
  16. }
  17. }

界面如下,虽然丑了点,但是简洁:

利用MyController进行交互!

  1. public class MyController implements Initializable {
  2. @FXML private Canvas mycanvas;
  3. @FXML private MenuBar mymenu;
  4. @FXML private MenuItem change;
  5. @FXML private MenuItem init;
  6. ... //其他
  7. }

MyController类中对于所有的变量我们都可以进行引用,比如利用Canvas来进行图片的绘制,利用change来实现整型的改变,利用init来实现战斗初始化的相应,加载等等方法,真的好用。利用Mycanvas还能够进行绘制出自己想要的东西。

2.5 线程!让葫芦娃动起来!

在线程的设计中,我设计了两种线程,一个是GUIrefresh,这个线程是用来进行画面的刷新的函数,根据固定时间进行刷新战场,让葫芦娃看起来动起来了!因为Canvas的绘制不会覆盖,所以必须采用一个线程进行刷新。二是myThread继承了Thread方法,利用了CRAP原则,内存了一个Creature的引用类型,通过对每个Creature修改访问从而实现了葫芦娃的交互。同时还有一个战场的引用,来进行操作。

葫芦娃就可以动起来了!

不过多线程调的BUG是最久的因为,它会不安全,造成死锁,让我很苦恼。

利用SYN锁实现同步,在访问共有变量,进行上锁,保证安全!

例如下面的GUIrefreshshowBattleground()方法,刷新的时候会对ground(公有战场)上锁保证了安全性。

  1. public void showBattleground() {
  2. synchronized (this.ground) {
  3. this.mycanvas.getGraphicsContext2D().clearRect(0, 0, 1100, 600); //清空画布
  4. //画gezi
  5. this.mycanvas.getGraphicsContext2D().setStroke(Color.WHITE); //白线
  6. for (int i = 0; i <= 10; i++) {
  7. this.mycanvas.getGraphicsContext2D().strokeLine(0, i * 50, 1000, i * 50);
  8. }
  9. for (int j = 0; j <= 20; j++) {
  10. this.mycanvas.getGraphicsContext2D().strokeLine(j * 50, 0, j * 50, 500);
  11. }
  12. for (int i = 0; i < 10; i++) {
  13. for (int j = 0; j < 20; j++) {
  14. this.ground.showThecreature(i, j, this.mycanvas);
  15. }
  16. }
  17. }
  18. }

除此以外,GUIrefresh会进行读取文件,进行复盘操作!

2.6 回放接口

实现了SAVE_actionSAVE_init这两个类,从而根据这个类进行保存,下面具体讲了。

以上就是我设计的主要类和接口,后面可能会进行迭代拓展!

三、战斗的设计

3.1 BGM和战斗音效

在BGM和战斗音效的烘托下,整个气氛变得武侠了起来。BGM为胡伟的偷功,战斗音效为刀剑声和皮鞭声,从而能够实现BGM,使好玩了起来。

3.2 打斗特效

如何看出谁掉血了?那就使用攻击特效来展示吧!

可以看出葫芦娃可以向敌人攻击是喷射火焰的,妖怪是喷射水滴的,但是这样并不是很美观,在以后的版本会进行修改。还可能加入技能特效!

3.3 血量和死亡

葫芦娃会有血量条来反映当前的状态,同时死亡的葫芦娃会变成墓碑,来实现死亡之后留下实体

3.4 如何移动?

设计了一个伪智能算法,我设计了一个检测敌人进行移动的算法,而不是随机或者向中间走动,保证了葫芦娃战斗是可以寻找敌人并且可以绕过墓碑的!让他看起来不那么傻!

但是还是有需要优化的地方,比如出现极低的概率情况,还没想好措施,以后会完善。

3.5 如何攻击?

生物会先检测周围的敌人,再进行攻击,攻击实现了接口,可以轻松写出,注意同步就OK

3.6 胜利!

会显示图片,虽然有点丑,以后会改进。

3.7 回放

在战斗的时候,会先保存一个初始的位置的二维矩阵写入,然后根据每一帧的动作列表存放进一个ArrayList<Save_aciton>,SAVE_action保存了动作类型,动作起始坐标和动作结束坐标,从而实现了移动和攻击的统一,从某种意义上也是一种封装。最后写入结果。然后利用读取操作进行读取,保证了能够实现复盘操作。

四、期望的拓展(TODO)

  • 技能的释放,每个人更加独立

  • 打斗的特效,每个人的不同

  • 会不会有额外的惊喜?(血瓶加血,攻击BUFF等等)

  • 更加美观和更加容易实现

  • 说明文档(帮助操作还没写,尴尬)

五、设计模式和原则

  • ARP原则,不能利用多个方法改变

  • SCRP原则,聚合方法来写线程

  • LIP模式,父类型指针一定可以指向子类型

  • 迭代器模式

  • 适配器模式

  • 工厂模式等

六、致谢!

虽然java考试让我有点绝望,但是看着我亲手写出来的葫芦娃还是有一种自豪感的!虽然压力也是很大,看着大佬们做的java也是很羡慕,但是自己码出来的代码宛如亲儿子怎么也好看!但是代码还是追求完美的过程,我会重新不断的改进我的代码并且逐步利用新的机制和设计模式,让我的葫芦娃更好看!

彩蛋

当最后3个葫芦娃围剿蛇精的时候,我以为葫芦娃稳了,但是蛇精利用走位和高攻击低护甲的特性,逐个击破实现反杀

上传的附件 cloud_download 基于JavaFx的多线程葫芦娃打斗游戏.zip ( 6.80mb, 1次下载 )
error_outline 下载需要8点积分

发送私信

当你成功时,谁还在乎你的过去

11
文章数
13
评论数
最近文章
eject