最近一直在玩一款微信小游戏,具体哪个就不多说了,该游戏在升级的时候可供玩家自主选择技能或者词条,来提升攻击效果,之前在给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. 添加装饰器,如果装饰器是首次被添加的话则变更技能得到基础属性
  2. 刷新回合数,每一回合后要将某些装饰器的回合数 -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);
        }
    }


}
Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐