导航:从零开始手写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上点个星星,谢谢!