
通过装饰器来实现技能动态增减词条效果
最近一直在玩一款微信小游戏,具体哪个就不多说了,该游戏在升级的时候可供玩家自主选择技能或者词条,来提升攻击效果,之前在给的时候,也想做出类似的效果,当时没有想到什么好的办法,今天花了点时间问了问豆包和deepseek,算是用装饰器实现了这个功能吧.
·
最近一直在玩一款微信小游戏,具体哪个就不多说了,该游戏在升级的时候可供玩家自主选择技能或者词条,来提升攻击效果,之前在给IDEA插件开发大乐斗的时候,也想做出类似的效果,当时没有想到什么好的办法,今天花了点时间问了问豆包和deepseek,算是用装饰器实现了这个功能吧.
1. 技能相关
测试技能接口,仅添加了一些通用的属性。
如 名称,基础伤害,暴击倍数,冷却时间,真实伤害,技能等级之类的
1. 实现一个技能接口
定义一些技能的基本行为,方便后续扩展
package net.lesscoding.xeGame.common.skill;
import net.lesscoding.xeGame.common.decorator.SkillEntryDecorator;
public interface Skill {
String getName();
int getBaseDamage();
double getCoolDown();
double getCritMultiplier();
int getTrueDamage();
int getSkillLevel();
void setBaseDamage(int baseDamage);
void setCoolDown(double coolDown);
void setCritMultiplier(double critMultiplier);
void setTrueDamage(int trueDamage);
void addDecorator(SkillEntryDecorator decorator);
void reduceDecoratorDurations();
}
2. 基础技能 BaseSkill
基础技能类 提供了两个方法
- 添加装饰器,如果装饰器是首次被添加的话则变更技能得到基础属性
- 刷新回合数,每一回合后要将某些装饰器的回合数 -1 。 这个应该可以优化,这里只是简单记录一下
package net.lesscoding.xeGame.common.skill;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.lesscoding.xeGame.common.decorator.SkillEntryDecorator;
import java.util.ArrayList;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = false)
public class BaseSkill implements Skill {
private String name;
private int baseDamage;
private double coolDown;
private double critMultiplier;
private int trueDamage;
private int skillLevel;
private List<SkillEntryDecorator> decorators;
public BaseSkill(String name, int baseDamage, double coolDown, double critMultiplier, int trueDamage, int skillLevel) {
this.name = name;
this.baseDamage = baseDamage;
this.coolDown = coolDown;
this.critMultiplier = critMultiplier;
this.trueDamage = trueDamage;
this.skillLevel = skillLevel;
this.decorators = new ArrayList<>();
}
@Override
public void addDecorator(SkillEntryDecorator decorator) {
decorators.add(decorator);
decorator.applyEffectIfNotApplied();
}
@Override
public void reduceDecoratorDurations() {
for (SkillEntryDecorator decorator : decorators) {
decorator.reduceDuration();
}
}
}
2. 装饰器
通过将技能对象传递过来,给装饰器配置是否永久生效,还是回合生效,技能描述,百分比/固定伤害 提升(未添加)等。
1. 词条装饰器接口
具体的生效和实效逻辑交由具体的装饰器子类来实现。接口里边只对初次添加和生效回合为0时做处理
package net.lesscoding.xeGame.common.decorator;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.NoArgsConstructor;
import net.lesscoding.xeGame.common.skill.Skill;
@Data
@NoArgsConstructor
public abstract class SkillEntryDecorator {
protected Skill decoratedSkill;
protected int duration;
protected boolean isPermanent;
protected boolean hasApplied;
protected String description;
public SkillEntryDecorator(Skill decoratedSkill, int duration, boolean isPermanent) {
this.decoratedSkill = decoratedSkill;
this.duration = duration;
this.isPermanent = isPermanent;
this.hasApplied = false;
}
public void applyEffectIfNotApplied() {
if (!hasApplied) {
applyEffect();
hasApplied = true;
}
}
public void reduceDuration() {
if (!isPermanent) {
this.duration--;
if (duration <= 0) {
removeEffect();
}
}
}
public abstract void applyEffect();
public abstract void removeEffect();
String description(String name, int duration, boolean permanent, double rate) {
String applyStr = rate < 0 ? "减少" : "增加";
if (permanent) {
return StrUtil.format("{} 永久 {} {}", name, applyStr, rateStr(rate));
} else {
return StrUtil.format("{} {} {} {} 回合", name, applyStr, rateStr(rate), duration);
}
}
String rateStr(double rate) {
if (rate - (int) rate != 0) {
// 小数
return rate * 100 + "%";
} else {
return rate + "%";
}
}
}
2. 技能冷却装饰器
package net.lesscoding.xeGame.common.decorator;
import lombok.Data;
import net.lesscoding.xeGame.common.skill.Skill;
@Data
public class CoolDownReductionDecorator extends SkillEntryDecorator {
private double reductionRate;
public CoolDownReductionDecorator(Skill decoratedSkill, int duration, boolean isPermanent, double reductionRate) {
super(decoratedSkill, duration, isPermanent);
super.setDescription(description("冷却时间", duration, isPermanent, reductionRate));
this.reductionRate = reductionRate;
}
@Override
public void applyEffect() {
int newCoolDown = (int) (decoratedSkill.getCoolDown() * (1 - reductionRate));
decoratedSkill.setCoolDown(newCoolDown);
}
@Override
public void removeEffect() {
int originalCoolDown = (int) (decoratedSkill.getCoolDown() / (1 - reductionRate));
decoratedSkill.setCoolDown(originalCoolDown);
}
}
3. 暴击率装饰器
package net.lesscoding.xeGame.common.decorator;
import lombok.Data;
import net.lesscoding.xeGame.common.skill.Skill;
@Data
public class CritDamageIncreaseDecorator extends SkillEntryDecorator {
private double increaseRate;
public CritDamageIncreaseDecorator(Skill decoratedSkill, int duration,
boolean isPermanent, double increaseRate) {
super(decoratedSkill, duration, isPermanent);
super.setDescription(description("暴击率", duration, isPermanent, increaseRate));
this.increaseRate = increaseRate;
}
@Override
public void applyEffect() {
double newCritMultiplier = decoratedSkill.getCritMultiplier() * (1 + increaseRate);
decoratedSkill.setCritMultiplier(newCritMultiplier);
}
@Override
public void removeEffect() {
double originalCritMultiplier = decoratedSkill.getCritMultiplier() / (1 + increaseRate);
decoratedSkill.setCritMultiplier(originalCritMultiplier);
}
}
4.伤害提升装饰器
package net.lesscoding.xeGame.common.decorator;
import lombok.Data;
import net.lesscoding.xeGame.common.skill.Skill;
@Data
public class CritDamageIncreaseDecorator extends SkillEntryDecorator {
private double increaseRate;
public CritDamageIncreaseDecorator(Skill decoratedSkill, int duration,
boolean isPermanent, double increaseRate) {
super(decoratedSkill, duration, isPermanent);
super.setDescription(description("暴击率", duration, isPermanent, increaseRate));
this.increaseRate = increaseRate;
}
@Override
public void applyEffect() {
double newCritMultiplier = decoratedSkill.getCritMultiplier() * (1 + increaseRate);
decoratedSkill.setCritMultiplier(newCritMultiplier);
}
@Override
public void removeEffect() {
double originalCritMultiplier = decoratedSkill.getCritMultiplier() / (1 + increaseRate);
decoratedSkill.setCritMultiplier(originalCritMultiplier);
}
}
5.爆炸真伤
package net.lesscoding.xeGame.common.decorator;
import lombok.Data;
import net.lesscoding.xeGame.common.skill.Skill;
@Data
public class ExplosionDamageDecorator extends SkillEntryDecorator {
private int explosionDamage;
public ExplosionDamageDecorator(Skill decoratedSkill, int duration, boolean isPermanent, int explosionDamage) {
super(decoratedSkill, duration, isPermanent);
super.setDescription(description("爆炸伤害", duration, isPermanent, explosionDamage));
this.explosionDamage = explosionDamage;
}
@Override
public void applyEffect() {
int newTrueDamage = decoratedSkill.getTrueDamage() + explosionDamage;
decoratedSkill.setTrueDamage(newTrueDamage);
}
@Override
public void removeEffect() {
int originalTrueDamage = decoratedSkill.getTrueDamage() - explosionDamage;
decoratedSkill.setTrueDamage(originalTrueDamage);
}
}
3. 测试类
实现一个测试类,10回合在其中某4个回合随机添加词条,对激光技能进行提升
package net.lesscoding.xeGame.common;
import cn.hutool.core.util.StrUtil;
import net.lesscoding.xeGame.common.decorator.*;
import net.lesscoding.xeGame.common.skill.BaseSkill;
import net.lesscoding.xeGame.common.skill.Skill;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class GameApp {
public static void main(String[] args) {
// 创建基础技能
Skill laser = new BaseSkill("激光", 100, 10, 3, 0, 1);
System.out.println("初始技能信息:" + laser);
// 模拟 10 个回合
Random random = new Random();
Set<Integer> randomRounds = new HashSet<>();
while (randomRounds.size() < 4) {
randomRounds.add(random.nextInt(10));
}
for (int round = 0; round < 10; round++) {
if (randomRounds.contains(round)) {
// 随机选择一个词条添加
SkillEntryDecorator decorator = getRandomDecorator(laser);
laser.addDecorator(decorator);
System.out.println(StrUtil.format("第 {} 回合添加词条,【{}】\n当前技能信息\n {}", round + 1, decorator.getDescription(), laser));
} else {
System.out.println(StrUtil.format("第 {} 回合,当前技能信息:\n{}", round + 1, laser));
}
// 减少词条持续时间
laser.reduceDecoratorDurations();
}
}
private static SkillEntryDecorator getRandomDecorator(Skill skill) {
Random random = new Random();
int choice = random.nextInt(4);
int duration = random.nextInt(3) + 1; // 随机 1 - 3 回合持续时间
boolean isPermanent = random.nextBoolean(); // 随机是否永久
switch (choice) {
case 0:
return new CoolDownReductionDecorator(skill, duration, isPermanent, 0.25);
case 1:
return new DamageIncreaseDecorator(skill, duration, isPermanent, 0.6);
case 2:
return new CritDamageIncreaseDecorator(skill, duration, isPermanent, 1);
case 3:
return new ExplosionDamageDecorator(skill, duration, isPermanent, 25);
default:
throw new IllegalStateException("Unexpected value: " + choice);
}
}
}
更多推荐
所有评论(0)