赞
踩
导航:从零开始手写mmo游戏从框架到爆炸(零)—— 导航-CSDN博客
上一章(从零开始手写mmo游戏从框架到爆炸(二十)— 战斗系统一-CSDN博客)我们只是完成了基本的战斗,速度属性并没有真正的发生作用。现在我们加入速度属性。上一章我们说过,比如速度是1000的时候是每隔2秒钟攻击一次,但是服务器不能真的等两秒再计算攻击的结果,那么这个战斗的时长将会超过几分钟,用户也可能等这么久。那么这里要解决几个问题:
第一个就是速度和出手间隔的换算,我们使用一个比较简单的公式,就是
这样可以保证最短的出手时间是500,最长也不会超过5000。
第二个问题就是根据速度插入到队列的问题,首先我们看下对于LinkedList队列的插入demo
- public class Main {
- public static void main(String[] args) {
- LinkedList<Integer> queue = new LinkedList<>(); // 创建一个空的队列
-
- // 添加初始元素
- for (int i = 1; i <= 5; i++) {
- queue.addLast(i);
- }
-
- System.out.println("原始队列:" + queue);
-
- int targetIndex = 2; // 目标索引为2(从0开始计算)
- int elementToInsert = 99; // 要插入的元素值
-
- ListIterator<Integer> iterator = queue.listIterator();
- while (iterator.hasNext()) {
- if (targetIndex == 0) {
- iterator.next(); // 跳过第一个元素
- break;
- } else {
- iterator.next();
- targetIndex--;
- }
-
- if (!iterator.hasNext() && targetIndex > 0) {
- throw new IndexOutOfBoundsException("目标索引超出了队列长度");
- }
- }
-
- iterator.add(elementToInsert); // 在指定位置插入新元素
-
- System.out.println("插入元素后的队列:" + queue);
-
- }
- }
运行后结果如下:
- 原始队列:[1, 2, 3, 4, 5]
- 插入元素后的队列:[1, 2, 3, 99, 4, 5]
那么根据这个方法我们来尝试改造战斗引擎。
首先Action接口中增加一个interval()的方法,用于获取时间间隔,这个时间间隔是预计攻击时间距离战斗开始时间的间隔,例如计算出来的攻击间隔是500,那么每次计算的结果就是500,1000,1500,2000...以此类推。
- public interface Action {
-
- boolean run();
-
- /***
- * 是否继续
- * @return
- */
- boolean checkContinue();
-
- int speed();
-
- /***
- *
- * @return
- */
- int intervalTime();
- }
同时创建一个抽象类来抽象部分功能:
- public abstract class Attack implements Action{
-
- private int intervalTime;
-
- private int speed;
-
- public int getIntervalTime() {
- return intervalTime;
- }
-
- public void setIntervalTime(int intervalTime) {
- this.intervalTime = intervalTime;
- }
-
- public int getSpeed() {
- return speed;
- }
-
- public void setSpeed(int speed) {
- this.speed = speed;
- }
-
- @Override
- public int intervalTime() {
- return intervalTime;
- }
-
- @Override
- public int speed() {
- return speed;
- }
-
- public int computeInterval(int speed) {
- return 500 + (int) (((1 - (speed) * 1.0 / (2000 + speed))
- * (1 - (speed) * 1.0 / (2000 + speed))) * 5000);
- }
- }
修改 GroupAttack 在创建的时候要不是速度和间隔两个字段
- public class GroupAttack extends Attack {
-
- private Hero heroA;
-
- private List<Hero> defenceList;
-
- public GroupAttack(Hero heroA, List<Hero> defenceList) {
- this.heroA = heroA;
- this.defenceList = defenceList;
- setIntervalTime(computeInterval(heroA.getSpeed()));
- setSpeed(heroA.getSpeed());
- }
-
- @Override
- public 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;
- }
-
- @Override
- public boolean checkContinue() {
- return heroA.getHp() > 0 && defenceList.stream().anyMatch(e -> e.getHp() > 0);
- }
-
- }
最后我们再创建一个战斗服务:
- public class BattleManyToManyTwo {
-
- // 队列不变
- private final LinkedList<Attack> actions = new LinkedList<>();
-
- private int addAction(Attack action){
- actions.offer(action);
- return actions.size();
- }
-
- public void fight(List<Hero> listA, List<Hero> listB) throws InterruptedException {
- // 先初始化
- listA.sort(Comparator.comparing(Hero::getSpeed).reversed());
- for (int i = 0; i < listA.size(); i++) {
- addAction(new GroupAttack(listA.get(i),listB));
- }
-
- // 再放入listB
- listB.sort(Comparator.comparing(Hero::getSpeed).reversed());
- for (int i = 0; i < listB.size(); i++) {
- GroupAttack attack = new GroupAttack(listB.get(i), listA);
- insertAction(attack);
- }
-
- // 如果A集合和B集合的生命值都还大于0
-
- while(listA.stream().anyMatch(e -> e.getHp() > 0) && listB.stream().anyMatch(e -> e.getHp() > 0)) {
- Attack pop = actions.pop();
- boolean run = pop.run();
- if(run) {
- // 再放进去
- if (pop.checkContinue()) {
- // 要重新计算interval的时间
- pop.setIntervalTime(pop.getIntervalTime() + pop.computeInterval(pop.speed()));
- insertAction(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));
- }
- }
-
- private void insertAction(Attack attack) {
- int intervalTime = attack.getIntervalTime();
-
- // 如果第一个就大于attack的interval
- if(actions.get(0).getIntervalTime() > attack.intervalTime()){
- // 在头插入一个
- actions.push(attack);
- }
- else {
- ListIterator<Attack> iterator = actions.listIterator();
- while (iterator.hasNext()) {
- Attack next = iterator.next();
-
- if (next.getIntervalTime() > intervalTime) {
- break;
- }
- }
- // 在指定位置插入新元素
- iterator.add(attack);
- }
- }
-
- public static void main(String[] args) throws InterruptedException {
- BattleManyToManyTwo battle = new BattleManyToManyTwo();
-
- Hero A = new Hero("A");
- Hero B = new Hero("B");
- B.setSpeed(2000);
- B.setAttack(20);
-
- Hero C = new Hero("C");
- C.setSpeed(500);
- C.setAttack(20);
-
- Hero D = new Hero("D");
- D.setSpeed(10);
- D.setAttack(15);
- battle.fight(Arrays.asList(A,C),Arrays.asList(B,D));
- }
-
- }
运行main方法,查看效果:
- B攻击,C生命值减少20
- B攻击,C生命值减少20
- C攻击,B生命值减少20
- A攻击,B生命值减少10
- B攻击,C生命值减少20
- D攻击,C生命值减少15
- C攻击,B生命值减少20
- B攻击,C生命值减少20
- B攻击,C生命值减少20
- B攻击,A生命值减少20
- A攻击,B生命值减少10
- D攻击,A生命值减少15
- B攻击,A生命值减少20
- B攻击,A生命值减少20
- B攻击,A生命值减少20
- A攻击,B生命值减少10
- D攻击,A生命值减少15
- B集团 获胜:[{"attack":20,"hp":30,"name":"B","speed":2000},{"attack":15,"hp":100,"name":"D","speed":10}]
-
- Process finished with exit code 0
全部源码详见:
gitee : eternity-online: 多人在线mmo游戏 - Gitee.com
分支:step-11
请各位帅哥靓女帮忙去gitee上点个星星,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。