从零开始手写mmo游戏从框架到爆炸(二十)— 战斗系统一

导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客     

规则       

        我们现在设计并尝试开发战斗系统。战斗系统我们先设定几个规则

        1、多人对多人:英雄可以携带宝宝,面对的野怪也可以是成群的,故要设计成多人对多人的战斗引擎;

        2、速度快的先出手:这点应该没有异议,根据速度来判定出手间隔,但是这里要有一个数据转换的问题,比如并不是速度100的就比速度50的出手速度快一倍,应该有一个计算公式来根据英雄的速度属性计算出手间隔。

        3、急速打架:考虑到不能在后台慢慢的让两方打,这样耗时又费机器,用户也等不了这么久,所以最好的方法是在后台迅速的计算出结果,然后把打斗的过程返回给前端,前端再进行展示。笔者玩了一些小游戏也是这么做的。

       4、要有底线:如果双方攻击力都不足,或者奶量都十足,那么很有可能永远打不完,就死循环要导致内存溢出了故而应该设定一个最长打斗时间,如果到了最长打斗时间还没有分出胜负就是平局。

       5、技能的问题:技能的问题很复杂,有光环型的技能,有召唤型的技能,有单伤,都群伤,有被动,有主动,所以目前我们暂时先不考虑技能,先让咱们的游戏可以动起来,可以打怪,然后掉落宝物。之后我们再根据技能的设定重新来完善战斗系统。

       基于以上几点规则,我们先尝试写几个demo来模拟打斗的场面。

代码       

      首先我们创建测试的英雄类,简化战斗模型,只有姓名、攻击、生命值、速度这四个属性。并且增加一个攻击方法。

Hero.java

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Hero {String name = "hero";int attack =  10;int speed = 10;int hp = 100;public Hero(String name) {this.name = name;}/**** 模拟攻击* @param hero*/public void attack(Hero hero) {if(hero.getHp() > 0) {hero.setHp(hero.getHp() - getAttack());System.out.println(getName() + "攻击," + hero.getName() + "生命值减少" + getAttack());}}
}

创建一个动作接口,用于封装攻击的数据- Action

public interface Action {void run();/**** 是否继续* @return*/boolean checkContinue();int speed();
}

先实现1V1- BaseAttack

public class BaseAttack implements Action {private Hero heroA;private Hero heroB;public BaseAttack(Hero heroA, Hero heroB) {this.heroA = heroA;this.heroB = heroB;}@Overridepublic void run() {heroA.attack(heroB);}@Overridepublic boolean checkContinue() {return heroA.getHp()>0;}@Overridepublic int speed() {return heroA.getSpeed();}
}

1v1的打斗服务 - BattleOneToOne

public class BattleOneToOne {// 正式战斗是以秒为单位,但是我们不可能真的按照秒来进行战斗,会大大的影响服务器的性能,所以我们应该要做的就是缩短打架的过程把结果返回给客户端即可,并把实际打斗时间告诉给客户端,然后客户端再进行时延的播放即可// 设计一个队列,在private LinkedList<Action> actions = new LinkedList<>();private int addAction(Action action){actions.offer(action);return actions.size();}public void fight(Hero A,Hero B) throws InterruptedException {// 根据速度放入队列if(A.getSpeed() > B.getSpeed()){addAction(new BaseAttack(A,B));addAction(new BaseAttack(B,A));}else{addAction(new BaseAttack(B,A));addAction(new BaseAttack(A,B));}while(A.getHp() > 0 && B.getHp() > 0) {Action pop = actions.pop();pop.run();// 再放进去if (pop.checkContinue()) {addAction(pop);}}if(A.getHp() > 0) {System.out.println(A.getName() + "获胜:" + A.getHp());}else{System.out.println(B.getName() + "获胜:" + B.getHp());}}public static void main(String[] args) throws InterruptedException {BattleOneToOne battleOneToOne = new BattleOneToOne();Hero A = new Hero("刘备");Hero B = new Hero("关羽");B.setSpeed(20);B.setAttack(20);battleOneToOne.fight(A,B);}}

 效果如下:

关羽攻击,刘备生命值减少20
刘备攻击,关羽生命值减少10
关羽攻击,刘备生命值减少20
刘备攻击,关羽生命值减少10
关羽攻击,刘备生命值减少20
刘备攻击,关羽生命值减少10
关羽攻击,刘备生命值减少20
刘备攻击,关羽生命值减少10
关羽攻击,刘备生命值减少20
关羽获胜:60

我们再来写一个多人对战的- GroupAttack

public class GroupAttack implements Action {private Hero heroA;private List<Hero> defenceList;public GroupAttack(Hero heroA, List<Hero> defenceList) {this.heroA = heroA;this.defenceList = defenceList;}@Overridepublic boolean run() {// 自己血量少于0 返回if(heroA.getHp() > 0) {        // 遍历并找到血量最少的攻击defenceList = defenceList.stream().filter(e -> e.getHp() > 0).collect(Collectors.toList());if (!CollectionUtils.isEmpty(defenceList)) {defenceList.sort(Comparator.comparing(Hero::getHp));heroA.attack(defenceList.get(0));return true;}}return false;}@Overridepublic boolean checkContinue() {return heroA.getHp() > 0 && defenceList.stream().anyMatch(e -> e.getHp() > 0);}@Overridepublic int speed() {return heroA.getSpeed();}
}

BattleManyToMany

public class BattleManyToMany {// 队列不变private LinkedList<Action> actions = new LinkedList<>();private int addAction(Action action){actions.offer(action);return actions.size();}public void fight(List<Hero> listA, List<Hero> listB) throws InterruptedException {// 先放入listAlistA.sort(Comparator.comparing(Hero::getSpeed).reversed());for (int i = 0; i < listA.size(); i++) {addAction(new GroupAttack(listA.get(i),listB));}// 再放入listBlistB.sort(Comparator.comparing(Hero::getSpeed).reversed());for (int i = 0; i < listB.size(); i++) {addAction(new GroupAttack(listB.get(i),listA));}// 如果A集合和B集合的生命值都还大于0while(listA.stream().anyMatch(e -> e.getHp() > 0) && listB.stream().anyMatch(e -> e.getHp() > 0)) {Action pop = actions.pop();boolean run = pop.run();if(run) {// 再放进去if (pop.checkContinue()) {addAction(pop);}// 打印System.out.println("A集团 :" + JSON.toJSONString(listA));System.out.println("B集团 :" + JSON.toJSONString(listB));}}if(listA.stream().anyMatch(e -> e.getHp() > 0)) {System.out.println("A集团 获胜:" + JSON.toJSONString(listA));}else{System.out.println("B集团 获胜:" + JSON.toJSONString(listB));}}public static void main(String[] args) throws InterruptedException {BattleManyToMany battle = new BattleManyToMany();Hero A = new Hero("A");Hero B = new Hero("B");B.setSpeed(20);B.setAttack(20);Hero C = new Hero("C");C.setSpeed(5);C.setAttack(20);Hero D = new Hero("D");D.setSpeed(10);D.setAttack(15);battle.fight(Arrays.asList(A,C),Arrays.asList(B,D));}}

运行结果如下:

A攻击,B生命值减少10
A集团 :[{"attack":10,"hp":100,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":90,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
C攻击,B生命值减少20
A集团 :[{"attack":10,"hp":100,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":70,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
B攻击,A生命值减少20
A集团 :[{"attack":10,"hp":80,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":70,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
D攻击,A生命值减少15
A集团 :[{"attack":10,"hp":65,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":70,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
A攻击,B生命值减少10
A集团 :[{"attack":10,"hp":65,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":60,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
C攻击,B生命值减少20
A集团 :[{"attack":10,"hp":65,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":40,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
B攻击,A生命值减少20
A集团 :[{"attack":10,"hp":45,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":40,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
D攻击,A生命值减少15
A集团 :[{"attack":10,"hp":30,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":40,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
A攻击,B生命值减少10
A集团 :[{"attack":10,"hp":30,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":30,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
C攻击,B生命值减少20
A集团 :[{"attack":10,"hp":30,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":10,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
B攻击,A生命值减少20
A集团 :[{"attack":10,"hp":10,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":10,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
D攻击,A生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":10,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
C攻击,B生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":100,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
D攻击,C生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":85,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":100,"name":"D","speed":10}]
C攻击,D生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":85,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":80,"name":"D","speed":10}]
D攻击,C生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":70,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":80,"name":"D","speed":10}]
C攻击,D生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":70,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":60,"name":"D","speed":10}]
D攻击,C生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":55,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":60,"name":"D","speed":10}]
C攻击,D生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":55,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":40,"name":"D","speed":10}]
D攻击,C生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":40,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":40,"name":"D","speed":10}]
C攻击,D生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":40,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":20,"name":"D","speed":10}]
D攻击,C生命值减少15
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":25,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":20,"name":"D","speed":10}]
C攻击,D生命值减少20
A集团 :[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":25,"name":"C","speed":5}]
B集团 :[{"attack":20,"hp":-10,"name":"B","speed":20},{"attack":15,"hp":0,"name":"D","speed":10}]
A集团 获胜:[{"attack":10,"hp":-5,"name":"A","speed":10},{"attack":20,"hp":25,"name":"C","speed":5}]Process finished with exit code 0

全部源码详见:

gitee : eternity-online: 多人在线mmo游戏 - Gitee.com

分支:step-11

请各位帅哥靓女帮忙去gitee上点个星星,谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/701567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ //练习 8.3 什么情况下,下面的while循环会终止?

C Primer&#xff08;第5版&#xff09; 练习 8.3 练习 8.3 什么情况下&#xff0c;下面的while循环会终止&#xff1f; while(cin>>i) /* ... */环境&#xff1a;Linux Ubuntu&#xff08;云服务器&#xff09; 工具&#xff1a;vim 解释 当输入条件不为真的时候&am…

AI:134-基于深度学习的社交媒体图像内容分析

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

【右一的电子笔记】全导航,持续更新...

文章目录 &#x1f4da;计算机基础&#x1f407;高程&#xff08;c&#xff09;&#x1f407;python基础&#x1f407;数据结构&#x1f407;数据库系统概念&#x1f407;计算机网络&#x1f407;计算机组成原理&#x1f407;操作系统 &#x1f4da;大数据&#x1f407;大数据管…

C语言——实用调试技巧——第2篇——(第23篇)

坚持就是胜利 文章目录 一、实例二、如何写出好&#xff08;易于调试&#xff09;的代码1、优秀的代码2、示范&#xff08;1&#xff09;模拟 strcpy 函数方法一&#xff1a;方法二&#xff1a;方法三&#xff1a;有弊端方法四&#xff1a;对方法三进行优化assert 的使用 方法五…

Spring之AOP源码解析(下)

前言 在上一遍文章中,我们主要讲解了ProxyFactory在Spring完成AOP动态代理的过程中发挥的作用。这一篇我们主要讲解这些注解都是如何注入Advisors,然后分析这些Advisors生效的条件 注解都是如何注入Advisor并匹配的 EnableTransactionManagement注解 我们在之前提到EnableT…

C++ const关键字

在C中&#xff0c;const是一个关键字&#xff0c;用于声明常量或者修饰变量、指针、引用等&#xff0c;表示其数值是不可修改的。const关键字的主要作用包括一下几个方面&#xff1a; 一、修饰基本数据类型 基本数据类型&#xff0c;修饰符const可以用在类型说明符前&#xf…

STM32 TCP实现OTA

芯片&#xff1a;stm32f407 开发平台&#xff1a;stm32cubeide 上位机开发平台&#xff1a;visual studio 2017 1. FLASH分配 将flash划分为四个部分&#xff1a; bootloader: 0x8000000-0x800ffff app1: 0x8010000-0x805ffff app2: …

一流的财务:搞数据!!!(干货)

“三流财务给数据&#xff0c;二流财务给分析报告&#xff0c;一流财务给....&#xff08;解决方案&#xff09;“这些文章应该很多人都看到过&#xff0c;这个口号粗看好像很有道理&#xff0c;但笔者并不认同&#xff0c;因为大家都忽略了一个重要的概念&#xff1a;数据&…

什么是rouge metric

采用分类任务的指标评估生成任务的问题 举个例子&#xff0c;在一个seq2seq模型中&#xff0c;黄金标签是“police killed the gunman”&#xff0c;模型输出是"the gunman police killed"&#xff0c;两句话的意思是有差别的&#xff0c;但是从unigram的角度&#…

数字化浪潮下的企业变革:深度解析ERP的崭新篇章

引言&#xff1a; 随着科技的飞速发展&#xff0c;企业正迎来前所未有的数字化浪潮。在这个数字时代&#xff0c;企业资源规划&#xff08;ERP&#xff09;被认为是企业应对挑战、实现创新的重要工具。本文将深入研究ERP的发展历程&#xff0c;聚焦不同行业和场景下的创新应用…

Atomic-flag-tutorial

本文介绍 <atomic> 头文件中最简单的原子类型: atomic_flag。atomic_flag 一种简单的原子布尔类型&#xff0c;只支持两种操作&#xff0c;test_and_set 和 clear。 std::atomic_flag 详解 std::atomic_flag 构造函数 std::atomic_flag 构造函数如下&#xff1a; ato…

ROS2 学习笔记13:创建 ROS2 包

ROS2 学习笔记13&#xff1a;创建 ROS2 包 Background 背景1 什么是ROS2 包2 ROS2包的组成3 工作空间的包 Prerequisites 前提Tasks 任务1 Create a package2 Build a package3 Source the setup file4 Use the package5 Examine package contents6 Customize package.xml Summ…

虚 拟 化原理

1 概念&#xff1a; ①通俗理解&#xff1a; 虚拟化是在硬件和操作系统之间的实践 ②通过对计算机的服务层级的理解&#xff0c;理解虚拟化概念 抽离层级之间的依赖关系&#xff08;服务器虚拟化&#xff09; 2 虚拟化分类 ①按架构分类 ◆寄居架构&#xff1a;装在操作系统上…

pytest.param作为pytest.mark.parametrize的参数进行调用

pytest.param&#xff1a;在 pytest.mark.parametrize 中可以作为一个指定的参数进行调用 获取数据库&#xff08;网页端&#xff09;数据&#xff0c;通过pytest.param包装成数据包用于pytest.mark.parametrize 中实现数据驱动调用。 import os import pytest import json fr…

OSCP靶场--Nickel

OSCP靶场–Nickel 考点(1.POST方法请求信息 2.ftp&#xff0c;ssh密码复用 3.pdf文件密码爆破) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap 192.168.237.99 -sV -sC -p- --min-rate 5000 Starting Nmap 7.92 ( https://nmap.org ) at 2024-02-22 04:06 EST Nm…

5.1 Ajax数据爬取之初介绍

目录 1. Ajax 数据介绍 2. Ajax 分析 2.1 Ajax 例子 2.2 Ajax 分析方法 &#xff08;1&#xff09;在网页页面右键&#xff0c;检查 &#xff08;2&#xff09;找到network&#xff0c;ctrl R刷新 &#xff08;3&#xff09;找 Ajax 数据包 &#xff08;4&#xff09;…

【前后端的那些事】文件上传组件封装

文章目录 效果前端代码后端代码组件封装 效果 前端代码 /views/file/file.vue <template><el-row><el-uploadv-model:file-list"fileList"class"upload-demo"multiple:auto-upload"false":on-preview"handlePreview"…

Javascript[ECMAScript] ES6、ES7、ES8、ES9、ES10、ES11、ES12、ES13、ES14[2023]新特性

# 前言 鉴于找不到ES6-ES14 的新特性集合&#xff0c;所以有了这篇文章&#xff0c;后续会持续更新每年的新特性 # 背景 ## JS1.1&#xff08;1997&#xff09; [第一版基于Netscape Navigator 3.0中实现的JAVASCRIPT 1.1](https://web.archive.org/web/19970614042441/http:/…

数据结构之:跳表

跳表&#xff08;Skip List&#xff09;是一种概率性数据结构&#xff0c;它通过在普通有序链表的基础上增加多级索引层来实现快速的查找、插入和删除操作。跳表的效率可以与平衡树相媲美&#xff0c;其操作的时间复杂度也是O(log n)&#xff0c;但跳表的结构更简单&#xff0c…

Swiper.js:不识这个轮播图js库,说明你的前端还未入门

hello&#xff0c;我是贝格前端工场&#xff0c;本期给大家带来轮播图的s库&#xff1a;Swiper.js&#xff0c;用这个类库处理轮播图、幻灯片、画廊那是得心应手&#xff0c;非常的easy&#xff0c;欢迎老铁们点赞关注&#xff0c;如有前端定制开发需求可以私信我们。 一、Swip…