前不久,崩坏:星穹铁道刚刚上线公测了,我也第一时间体验了这款游戏。在游戏的过程中,我偶然注意到,对局界面的左上角角色行动顺序,似乎和队列的模型比较类似(相同于队列的地方在于从队首选取下一个行动的单位,角色动作完成后重新插入队尾进行排队。不同于队列的地方在于,游戏中拥有拉取我方角色行动优先级和击退敌方角色行动优先级的机制,我们知道,java中的队列是不能插队的)。
于是,我尝试使用list集合,来实现角色行动顺序的维护。 基于此,实现了一个简单的回合制游戏逻辑。
首先,我们把场上所有的角色,设定为统一的Role类的对象,Role类的对象拥有名字、立场、职业、速度、生命值、攻击力等属性。
/**
* 己方或敌方的个体对象
*/
public class Role {
/**
* 名字
*/
private String name;
/**
* 立场(己方 - self;敌方 - enemy)
*/
private String standpoint;
/**
* 职业(不同的职业拥有不同的属性和技能)
* 1、丰饶:为最低百分比生命值的友方单位回复30%的血量
* 2、同谐:随机指定友方单位在自身行动结束后紧随行动
* 3、毁灭:单体伤害,150%自身攻击力的输出
* 4、智识:群体伤害,70%自身攻击力的输出
*/
private String profession;
/**
* 速度(决定了开局的攻击顺序)
*/
private BigDecimal speed;
/**
* 攻击力
*/
private int attack;
/**
* 生命值
*/
private int HP;
/**
* 生命值上限
*/
private int HpMax;
...get/set方法
}
根据立场不同,场上角色分为己方和敌方两种,我们创建己方角色类Self和敌方角色类Enemy,均继承Role类。己方角色拥有自己的属性“血量百分比”,计算方式为(当前剩余血量/生命值上限)x100,这是为了在回血时寻找血量最低的角色而使用的;己方全体角色共享战技点,每个单位释放技能需要消耗一点,发动普通攻击恢复一点;同时,己方角色根据职业的不同,释放技能产生不同的效果,我们根据职业,创建对应的技能方法:
1、丰饶:为最低百分比生命值的友方单位回复30%的血量
2、同谐:随机指定友方单位在自身行动结束后紧随行动
3、毁灭:单体伤害,150%自身攻击力的输出
4、智识:群体伤害,70%自身攻击力的输出
/**
* 己方的个体对象
*/
public class Self extends Role {
/**
* 战技点:友方单位释放技能需要消耗一点,普通攻击恢复一点
*/
public static int skillPoint = 5;
/**
* 当前生命值百分比 ((当前剩余血量/生命值上限)x100)
*/
private int percentageHP;
/**
* 普通攻击:单体伤害,100%自身攻击力的输出
*/
public int normalAttack(Self self, Enemy enemy) {
System.out.println(this.getName() + "使用了普通攻击");
int residueHP = enemy.getHP() - self.getAttack();
return residueHP;
}
/**
* 丰饶职业的技能:为最低百分比生命值的友方单位回复30%的血量
*
* @param self
* @param selfList
* @param attQueue
*/
public void fr(Self self, List<Self> selfList, List<Role> attQueue) {
List<Self> collect = selfList.stream()
.sorted((p1, p2) -> p1.getPercentageHP() - p2.getPercentageHP())
.limit(1).collect(Collectors.toList());
Self selfOne = collect.get(0);
selfOne.setHP((int) (selfOne.getHpMax() * 0.3 + selfOne.getHP()));
selfOne.setPercentageHP((selfOne.getHP() / self.getHpMax()) * 100);
System.out.println("[" + self.getName() + "." + self.getProfession() + "]:" + "释放了技能,为"
+ selfOne.getName() + "回复了血量");
attQueue.remove(self);
attQueue.add(self);
}
/**
* 同谐职业的技能:随机指定友方单位在自身行动结束后紧随行动
*
* @param self
* @param selfList
* @param attQueue
*/
public void tx(Self self, List<Self> selfList, List<Role> attQueue) {
Random rand = new Random();
int nextInt = rand.nextInt(selfList.size());
Self selfOne = selfList.get(nextInt);
attQueue.remove(self);
attQueue.remove(selfOne);
attQueue.add(0, selfOne);
System.out.println("[" + self.getName() + "." + self.getProfession() + "]:" + "释放了技能,拉取了"
+ selfOne.getName() + "的行动条");
attQueue.add(self);
}
/**
* 毁灭职业的技能:单体伤害,150%自身攻击力的输出
*
* @param self
* @param enemyList
* @param attQueue
*/
public void hm(Self self, List<Enemy> enemyList, List<Role> attQueue) {
Enemy enemy = enemyList.get(0);
int residueHP = (int) (enemy.getHP() - self.getAttack() * 1.5);
enemy.setHP(residueHP);
System.out.println("[" + self.getName() + "." + self.getProfession() + "]:" + "释放了技能,对"
+ enemy.getName() + "造成了" + self.getAttack() * 1.5 + "的伤害");
if (residueHP <= 0) {
enemyList.remove(enemy);
}
attQueue.remove(self);
attQueue.add(self);
}
/**
* 智识职业的技能:群体伤害,70%自身攻击力的输出
*
* @param self
* @param enemyList
* @param attQueue
*/
public void zs(Self self, List<Enemy> enemyList, List<Role> attQueue) {
for (Enemy enemyOne : enemyList) {
int residueHP = (int) (enemyOne.getHP() - self.getAttack() * 0.7);
enemyOne.setHP(residueHP);
}
System.out.println("[" + self.getName() + "." + self.getProfession() + "]:" + "释放了技能,对敌方全体造成了"
+ self.getAttack() * 0.7 + "的伤害");
ListIterator<Enemy> iterator = enemyList.listIterator();
while (iterator.hasNext()) {
if (iterator.next().getHP() <=0) {
iterator.remove();
}
}
attQueue.remove(self);
attQueue.add(self);
}
...get/set方法
}
而敌方的Enemy类,我们简单创建一下:
/**
* 敌方的个体对象
*/
public class Enemy extends Role {
/**
* 普通攻击:单体伤害,100%自身攻击力的输出
*/
public void normalAttack() {
System.out.println(this.getName() + "使用了普通攻击");
}
public void releaseSkill() {
System.out.println("[" + this.getName() + "." + this.getProfession() + "]:" + "释放了技能");
}
}
随后,我们在main方法中创建一个List<Role>代表战场,创建一个List<Self>代表己方所有角色,创建一个List<Enemy>代表敌方所有角色,在List<Role>中将所有角色按照速度降序排列,确定开场攻击顺序。创建whlie循环,每次取集合中的第一个元素发动进攻,对局结束条件为:己方单位或敌方单位全部阵亡。
public static void main(String[] args) {
// 创建一个战场环境
List<Role> attQueue = new LinkedList<>();
List<Self> selfList = createdSelf(attQueue);
List<Enemy> enemyList = createdEnemy(attQueue);
// 将所有角色按照速度降序排列,确定攻击顺序
attQueue.sort((a, b) -> b.getSpeed().compareTo(a.getSpeed()));
// 对局结束条件:己方单位或敌方单位全部阵亡
while (selfList.size() != 0 && enemyList.size() != 0) {
Role role = attQueue.get(0);
// 判断当前角色是否死亡
if (role.getHP() <= 0) {
continue;
}
// 判断当前角色是己方还是敌方
if ("self".equals(role.getStandpoint())) {
// 己方角色,先判断战技点是否大于0
Self self = (Self) role;
if (Self.skillPoint > 0) {
// todo 战技点大于0,根据职业的不同,释放技能,并消耗一点战技点
Self.skillPoint--;
if ("丰饶".equals(self.getProfession())) {
self.fr(self, selfList, attQueue);
} else if ("同谐".equals(self.getProfession())) {
self.tx(self, selfList, attQueue);
} else if ("毁灭".equals(self.getProfession())) {
self.hm(self, enemyList, attQueue);
} else {
self.zs(self, enemyList, attQueue);
}
} else {
// 战技点等于0,只能发动普通攻击,并回复一点战技点
Enemy enemy = enemyList.get(0);
int residueHP = self.normalAttack(self, enemy);
enemy.setHP(residueHP);
Self.skillPoint++;
if (residueHP <= 0) {
enemyList.remove(enemy);
}
}
} else {
// 敌方角色
Enemy enemy = (Enemy) role;
if ("毁灭".equals(enemy.getProfession())) {
Random rand = new Random();
int nextInt = rand.nextInt(selfList.size());
Self selfOne = selfList.get(nextInt);
int residueHP = (int) (selfOne.getHP() - enemy.getAttack() * 1.3);
selfOne.setHP(residueHP);
System.out.println("[" + enemy.getName() + "]:发动攻击,对"
+ selfOne.getName() + "造成了" + enemy.getAttack() * 1.3 + "的伤害");
if (residueHP <= 0) {
selfList.remove(selfOne);
}
attQueue.remove(enemy);
attQueue.add(enemy);
} else {
for (Self selfOne : selfList) {
int residueHP = (int) (selfOne.getHP() - enemy.getAttack() * 0.7);
selfOne.setHP(residueHP);
}
System.out.println("[" + enemy.getName() + "]:释放了技能,对己方全体造成了"
+ enemy.getAttack() * 0.7 + "的伤害");
ListIterator<Self> iterator = selfList.listIterator();
while (iterator.hasNext()) {
if (iterator.next().getHP() <= 0) {
iterator.remove();
}
}
attQueue.remove(enemy);
attQueue.add(enemy);
}
}
if (selfList.size() == 0) {
System.out.println("己方所有角色全部阵亡,对局结束。");
break;
} else if (enemyList.size() == 0) {
System.out.println("敌方所有角色全部阵亡,对局结束。");
break;
}
}
}
基本功能完成后,我们创建出己方和敌方的参战角色,并加入战斗:
/**
* 派出己方角色加入到战斗中
*
* @param queue
*/
private static List<Self> createdSelf(List<Role> queue) {
// 己方角色1,白露,丰饶
Self self1 = new Self();
self1.setName("白露");
self1.setStandpoint("self");
self1.setProfession("丰饶");
self1.setSpeed(BigDecimal.valueOf(3));
self1.setAttack(1);
self1.setHP(100);
self1.setHpMax(100);
self1.setPercentageHP(100);
self1.setPercentageHP(1);
// 己方角色2,布洛妮娅,同谐
Self self2 = new Self();
self2.setName("布洛妮娅");
self2.setStandpoint("self");
self2.setProfession("同谐");
self2.setSpeed(BigDecimal.valueOf(10));
self2.setAttack(10);
self2.setHP(75);
self2.setHpMax(75);
self2.setPercentageHP(100);
// 己方角色3,毁灭,爷
Self self3 = new Self();
self3.setName("爷");
self3.setStandpoint("self");
self3.setProfession("毁灭");
self3.setSpeed(BigDecimal.valueOf(6));
self3.setAttack(25);
self3.setHP(90);
self3.setHpMax(90);
self3.setPercentageHP(100);
// 己方角色4,智识,姬子
Self self4 = new Self();
self4.setName("姬子");
self4.setStandpoint("self");
self4.setProfession("智识");
self4.setSpeed(BigDecimal.valueOf(7));
self4.setAttack(18);
self4.setHP(80);
self4.setHpMax(80);
self4.setPercentageHP(100);
// 创建己方小队
List<Self> selfList = new ArrayList<>();
selfList.add(self1);
selfList.add(self2);
selfList.add(self2);
selfList.add(self2);
// 加入战斗
queue.add(self1);
queue.add(self2);
queue.add(self3);
queue.add(self4);
return selfList;
}
/**
* 派出敌方角色加入到战斗中
*
* @param queue
*/
private static List<Enemy> createdEnemy(List<Role> queue) {
// 敌方角色1,毁灭,敌人1
Enemy enemy1 = new Enemy();
enemy1.setName("敌人1");
enemy1.setStandpoint("enemy");
enemy1.setProfession("毁灭");
enemy1.setSpeed(BigDecimal.valueOf(4));
enemy1.setAttack(20);
enemy1.setHP(85);
// 敌方角色2,智识,敌人2
Enemy enemy2 = new Enemy();
enemy2.setName("敌人2");
enemy2.setStandpoint("enemy");
enemy2.setProfession("智识");
enemy2.setSpeed(BigDecimal.valueOf(5));
enemy2.setAttack(14);
enemy2.setHP(70);
// 创建敌方小队
List<Enemy> enemyList = new ArrayList<>();
enemyList.add(enemy1);
enemyList.add(enemy2);
// 加入战斗
queue.add(enemy1);
queue.add(enemy2);
return enemyList;
}
开始运行main方法(开始对局):
满是bug的代码居然能运行成功,还是挺开心的。之后有时间了慢慢优化代码,如果各位读者有更好的见解,也欢迎提出来,我们一起提高。