当前位置:   article > 正文

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

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

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

        上一章(从零开始手写mmo游戏从框架到爆炸(二十)— 战斗系统一-CSDN博客)我们只是完成了基本的战斗,速度属性并没有真正的发生作用。现在我们加入速度属性。上一章我们说过,比如速度是1000的时候是每隔2秒钟攻击一次,但是服务器不能真的等两秒再计算攻击的结果,那么这个战斗的时长将会超过几分钟,用户也可能等这么久。那么这里要解决几个问题:

        第一个就是速度和出手间隔的换算,我们使用一个比较简单的公式,就是

interval = 500 + (int) (((1 - (speed) * 1.0 / (2000 + speed)) * (1 - (speed) * 1.0 / (2000 + speed))) * 5000);

        这样可以保证最短的出手时间是500,最长也不会超过5000。

       第二个问题就是根据速度插入到队列的问题,首先我们看下对于LinkedList队列的插入demo

  1. public class Main {
  2. public static void main(String[] args) {
  3. LinkedList<Integer> queue = new LinkedList<>(); // 创建一个空的队列
  4. // 添加初始元素
  5. for (int i = 1; i <= 5; i++) {
  6. queue.addLast(i);
  7. }
  8. System.out.println("原始队列:" + queue);
  9. int targetIndex = 2; // 目标索引为2(从0开始计算)
  10. int elementToInsert = 99; // 要插入的元素值
  11. ListIterator<Integer> iterator = queue.listIterator();
  12. while (iterator.hasNext()) {
  13. if (targetIndex == 0) {
  14. iterator.next(); // 跳过第一个元素
  15. break;
  16. } else {
  17. iterator.next();
  18. targetIndex--;
  19. }
  20. if (!iterator.hasNext() && targetIndex > 0) {
  21. throw new IndexOutOfBoundsException("目标索引超出了队列长度");
  22. }
  23. }
  24. iterator.add(elementToInsert); // 在指定位置插入新元素
  25. System.out.println("插入元素后的队列:" + queue);
  26. }
  27. }

运行后结果如下:

  1. 原始队列:[1, 2, 3, 4, 5]
  2. 插入元素后的队列:[1, 2, 3, 99, 4, 5]

那么根据这个方法我们来尝试改造战斗引擎。

       首先Action接口中增加一个interval()的方法,用于获取时间间隔,这个时间间隔是预计攻击时间距离战斗开始时间的间隔,例如计算出来的攻击间隔是500,那么每次计算的结果就是500,1000,1500,2000...以此类推。

  1. public interface Action {
  2. boolean run();
  3. /***
  4. * 是否继续
  5. * @return
  6. */
  7. boolean checkContinue();
  8. int speed();
  9. /***
  10. *
  11. * @return
  12. */
  13. int intervalTime();
  14. }

   同时创建一个抽象类来抽象部分功能:

  1. public abstract class Attack implements Action{
  2. private int intervalTime;
  3. private int speed;
  4. public int getIntervalTime() {
  5. return intervalTime;
  6. }
  7. public void setIntervalTime(int intervalTime) {
  8. this.intervalTime = intervalTime;
  9. }
  10. public int getSpeed() {
  11. return speed;
  12. }
  13. public void setSpeed(int speed) {
  14. this.speed = speed;
  15. }
  16. @Override
  17. public int intervalTime() {
  18. return intervalTime;
  19. }
  20. @Override
  21. public int speed() {
  22. return speed;
  23. }
  24. public int computeInterval(int speed) {
  25. return 500 + (int) (((1 - (speed) * 1.0 / (2000 + speed))
  26. * (1 - (speed) * 1.0 / (2000 + speed))) * 5000);
  27. }
  28. }

         修改 GroupAttack 在创建的时候要不是速度和间隔两个字段

  1. public class GroupAttack extends Attack {
  2. private Hero heroA;
  3. private List<Hero> defenceList;
  4. public GroupAttack(Hero heroA, List<Hero> defenceList) {
  5. this.heroA = heroA;
  6. this.defenceList = defenceList;
  7. setIntervalTime(computeInterval(heroA.getSpeed()));
  8. setSpeed(heroA.getSpeed());
  9. }
  10. @Override
  11. public boolean run() {
  12. // 自己血量少于0 返回
  13. if(heroA.getHp() > 0) { // 遍历并找到血量最少的攻击
  14. defenceList = defenceList.stream().filter(e -> e.getHp() > 0).collect(Collectors.toList());
  15. if (!CollectionUtils.isEmpty(defenceList)) {
  16. defenceList.sort(Comparator.comparing(Hero::getHp));
  17. heroA.attack(defenceList.get(0));
  18. return true;
  19. }
  20. }
  21. return false;
  22. }
  23. @Override
  24. public boolean checkContinue() {
  25. return heroA.getHp() > 0 && defenceList.stream().anyMatch(e -> e.getHp() > 0);
  26. }
  27. }

 最后我们再创建一个战斗服务:

  1. public class BattleManyToManyTwo {
  2. // 队列不变
  3. private final LinkedList<Attack> actions = new LinkedList<>();
  4. private int addAction(Attack action){
  5. actions.offer(action);
  6. return actions.size();
  7. }
  8. public void fight(List<Hero> listA, List<Hero> listB) throws InterruptedException {
  9. // 先初始化
  10. listA.sort(Comparator.comparing(Hero::getSpeed).reversed());
  11. for (int i = 0; i < listA.size(); i++) {
  12. addAction(new GroupAttack(listA.get(i),listB));
  13. }
  14. // 再放入listB
  15. listB.sort(Comparator.comparing(Hero::getSpeed).reversed());
  16. for (int i = 0; i < listB.size(); i++) {
  17. GroupAttack attack = new GroupAttack(listB.get(i), listA);
  18. insertAction(attack);
  19. }
  20. // 如果A集合和B集合的生命值都还大于0
  21. while(listA.stream().anyMatch(e -> e.getHp() > 0) && listB.stream().anyMatch(e -> e.getHp() > 0)) {
  22. Attack pop = actions.pop();
  23. boolean run = pop.run();
  24. if(run) {
  25. // 再放进去
  26. if (pop.checkContinue()) {
  27. // 要重新计算interval的时间
  28. pop.setIntervalTime(pop.getIntervalTime() + pop.computeInterval(pop.speed()));
  29. insertAction(pop);
  30. }
  31. // 打印
  32. System.out.println("A集团 :" + JSON.toJSONString(listA));
  33. System.out.println("B集团 :" + JSON.toJSONString(listB));
  34. }
  35. }
  36. if(listA.stream().anyMatch(e -> e.getHp() > 0)) {
  37. System.out.println("A集团 获胜:" + JSON.toJSONString(listA));
  38. }else{
  39. System.out.println("B集团 获胜:" + JSON.toJSONString(listB));
  40. }
  41. }
  42. private void insertAction(Attack attack) {
  43. int intervalTime = attack.getIntervalTime();
  44. // 如果第一个就大于attack的interval
  45. if(actions.get(0).getIntervalTime() > attack.intervalTime()){
  46. // 在头插入一个
  47. actions.push(attack);
  48. }
  49. else {
  50. ListIterator<Attack> iterator = actions.listIterator();
  51. while (iterator.hasNext()) {
  52. Attack next = iterator.next();
  53. if (next.getIntervalTime() > intervalTime) {
  54. break;
  55. }
  56. }
  57. // 在指定位置插入新元素
  58. iterator.add(attack);
  59. }
  60. }
  61. public static void main(String[] args) throws InterruptedException {
  62. BattleManyToManyTwo battle = new BattleManyToManyTwo();
  63. Hero A = new Hero("A");
  64. Hero B = new Hero("B");
  65. B.setSpeed(2000);
  66. B.setAttack(20);
  67. Hero C = new Hero("C");
  68. C.setSpeed(500);
  69. C.setAttack(20);
  70. Hero D = new Hero("D");
  71. D.setSpeed(10);
  72. D.setAttack(15);
  73. battle.fight(Arrays.asList(A,C),Arrays.asList(B,D));
  74. }
  75. }

 运行main方法,查看效果:

  1. B攻击,C生命值减少20
  2. B攻击,C生命值减少20
  3. C攻击,B生命值减少20
  4. A攻击,B生命值减少10
  5. B攻击,C生命值减少20
  6. D攻击,C生命值减少15
  7. C攻击,B生命值减少20
  8. B攻击,C生命值减少20
  9. B攻击,C生命值减少20
  10. B攻击,A生命值减少20
  11. A攻击,B生命值减少10
  12. D攻击,A生命值减少15
  13. B攻击,A生命值减少20
  14. B攻击,A生命值减少20
  15. B攻击,A生命值减少20
  16. A攻击,B生命值减少10
  17. D攻击,A生命值减少15
  18. B集团 获胜:[{"attack":20,"hp":30,"name":"B","speed":2000},{"attack":15,"hp":100,"name":"D","speed":10}]
  19. Process finished with exit code 0

全部源码详见:

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

分支:step-11

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/145723
推荐阅读
相关标签
  

闽ICP备14008679号