【魔法森林冒险】11/14 战斗系统(二):多波战斗与BOSS战

🏠个人主页:黎雁

🎬作者简介:C/C++/JAVA后端开发学习者

❄️个人专栏:C语言数据结构(C语言)EasyXJAVA游戏规划程序人生

✨ 从来绝巘须孤往,万里同尘即玉京

文章目录

  • [【魔法森林冒险】11/14 战斗系统(二):多波战斗与BOSS战⚜️](#【魔法森林冒险】11/14 战斗系统(二):多波战斗与BOSS战⚜️)
    • [📝 文章摘要](#📝 文章摘要)
    • [⚜️ 一、多波战斗与BOSS战的核心定位:游戏的「难度高峰」](#⚜️ 一、多波战斗与BOSS战的核心定位:游戏的「难度高峰」)
    • [🔧 二、核心代码拆解(一):多波战斗系统 - WaveBattleSystem类](#🔧 二、核心代码拆解(一):多波战斗系统 - WaveBattleSystem类)
    • [🔧 三、核心代码拆解(二):Allen+Lia联合作战逻辑](#🔧 三、核心代码拆解(二):Allen+Lia联合作战逻辑)
      • [3.1 仇恨分担机制](#3.1 仇恨分担机制)
      • [3.2 Lia辅助攻击/治疗](#3.2 Lia辅助攻击/治疗)
    • [🧪 四、调试示例:多波战斗+BOSS战完整流程](#🧪 四、调试示例:多波战斗+BOSS战完整流程)
      • [4.1 调试输出结果(核心片段)](#4.1 调试输出结果(核心片段))
    • [🚨 五、多波战斗&BOSS战设计的「新手坑」与最佳实践](#🚨 五、多波战斗&BOSS战设计的「新手坑」与最佳实践)
    • [📌 知识回顾](#📌 知识回顾)
    • [✍️ 写在最后](#✍️ 写在最后)

【魔法森林冒险】11/14 战斗系统(二):多波战斗与BOSS战⚜️

📝 文章摘要

内容维度 详情说明
核心摘要 本文是「魔法森林冒险」Java项目系列第十一篇,聚焦战斗系统的进阶玩法------多波战斗与BOSS战。从黑暗洞穴的多波敌人战斗流程设计,到树灵BOSS的特殊战斗规则(阶段回血/技能释放),再到Allen+Lia的联合作战逻辑(仇恨分担/技能配合),带你吃透高难度战斗的核心设计思路与代码实现。
阅读时长 17分钟
适合人群 1. Java新手:想掌握「多波循环+状态机+角色协作」的实战应用;2. 游戏开发入门者:想理解BOSS战的阶段设计、多波敌人的难度梯度控制;3. 项目复刻者:想复刻完整的高难度战斗流程,包括多波敌人刷新、BOSS阶段技能、联合作战奖励等核心功能。
阅读重点 1. 多波战斗的流程框架(波次初始化→敌人刷新→波次结算→下一波);2. 树灵BOSS的状态机设计(普通阶段/狂暴阶段/回血机制);3. Allen+Lia联合作战逻辑(仇恨分担/辅助治疗/组合技能);4. BOSS战的结算规则(稀有道具掉落/高额经验奖励)。

⚜️ 一、多波战斗与BOSS战的核心定位:游戏的「难度高峰」

在「魔法森林冒险」中,多波战斗和BOSS战是战斗系统的进阶玩法,也是游戏难度和趣味性的核心体现:

难度梯度化 → 多波敌人逐波强化(数量/攻击力提升),BOSS战分阶段(普通→狂暴),符合玩家成长曲线;

协作深度化 → Allen主输出+Lia辅助治疗/仇恨分担,联合作战策略性拉满;

奖励稀缺化 → BOSS战掉落稀有道具(魔法花/高级卷轴),多波战斗结算额外经验,驱动玩家挑战;

规则特殊化 → BOSS拥有专属技能(范围攻击/回血)、多波敌人有刷新规则,区别于基础回合制战斗。

多波战斗与BOSS战的核心是「波次循环+状态机+角色协作」:以波次为单位驱动多波战斗,以状态机控制BOSS行为,以角色状态联动实现协作,接下来拆解核心代码,吃透这个设计思路!

🔧 二、核心代码拆解(一):多波战斗系统 - WaveBattleSystem类

2.1 完整核心代码(未修改,拆分讲解)

java 复制代码
import java.util.Scanner;
import java.util.List;
import java.util.ArrayList;
import java.util.Random;

/**
 * 多波战斗系统核心类:WaveBattleSystem
 * 继承基础战斗系统,实现黑暗洞穴多波敌人战斗逻辑
 */
public class WaveBattleSystem extends BattleSystem {
    // ========== 多波战斗核心属性 ==========
    // 总波次
    private final int totalWaves;
    // 当前波次
    private int currentWave;
    // 敌人列表(每波可能有多个敌人)
    private List<Enemy> currentWaveEnemies;
    // 波次奖励(逐波提升)
    private final int baseWaveReward = 10;
    // 随机数生成器
    private Random random;

    // ========== 构造方法:初始化多波战斗 ==========
    public WaveBattleSystem(Allen allen, Lia lia, int totalWaves) {
        // 基础战斗系统初始化(传入第一个敌人占位)
        super(allen, lia, new Goblin());
        this.totalWaves = totalWaves;
        this.currentWave = 0;
        this.currentWaveEnemies = new ArrayList<>();
        this.random = new Random();
        
        // 多波战斗初始化提示
        System.out.println("\n🌋 进入黑暗洞穴 - 多波战斗模式!");
        System.out.println("🎯 总波次:" + totalWaves + " | 每波敌人强度逐次提升!");
        System.out.println("🏆 通关奖励:稀有道具 + 高额经验值!");
    }

    // ========== 核心方法:启动多波战斗 ==========
    @Override
    public void startBattle() {
        // 多波战斗主循环
        while (currentWave < totalWaves) {
            // 1. 刷新当前波次敌人
            spawnWaveEnemies();
            
            // 2. 波次战斗初始化
            System.out.println("\n=====================================");
            System.out.println("🌊 第" + (currentWave + 1) + "/" + totalWaves + "波战斗开始!");
            System.out.println("👹 本波敌人:" + getEnemiesDesc());
            System.out.println("=====================================");
            
            // 3. 进行当前波次战斗
            boolean waveVictory = fightCurrentWave();
            
            // 4. 波次结算
            if (waveVictory) {
                waveSettlement();
                currentWave++;
                
                // 5. 波次间休整(可使用道具/查看状态)
                if (currentWave < totalWaves) {
                    interWaveRest();
                }
            } else {
                // 波次失败,整体战斗失败
                System.out.println("\n💀 第" + (currentWave + 1) + "波战斗失败!");
                super.setBattleOver(true);
                super.setVictory(false);
                break;
            }
        }
        
        // 6. 多波战斗最终结算
        finalSettlement();
    }

    // ========== 辅助方法:刷新当前波次敌人 ==========
    private void spawnWaveEnemies() {
        // 清空上一波敌人
        currentWaveEnemies.clear();
        
        // 波次越强,敌人数量/等级越高
        int enemyCount = 1 + currentWave; // 第1波1个,第2波2个...(最多3个)
        enemyCount = Math.min(enemyCount, 3);
        
        for (int i = 0; i < enemyCount; i++) {
            Enemy enemy;
            // 波次≤2:仅哥布林;波次>2:混合哥布林+精灵;波次≥5:精英敌人
            if (currentWave <= 2) {
                // 普通/首领哥布林(概率随波次提升)
                boolean isLeader = random.nextDouble() < (0.1 * currentWave);
                enemy = isLeader ? new Goblin(true) : new Goblin();
            } else {
                // 混合敌人:60%哥布林(含首领),40%精灵
                if (random.nextDouble() < 0.6) {
                    boolean isLeader = random.nextDouble() < (0.2 * currentWave);
                    enemy = isLeader ? new Goblin(true) : new Goblin();
                } else {
                    enemy = new Elf();
                }
            }
            
            // 敌人属性强化(每波提升10%攻击力/血量)
           强化敌人属性(enemy);
            currentWaveEnemies.add(enemy);
        }
    }

    // ========== 辅助方法:敌人属性强化 ==========
    private void 强化敌人属性(Enemy enemy) {
        double enhanceRate = 1 + (currentWave * 0.1);
        enemy.setMaxHp((int) (enemy.getMaxHp() * enhanceRate));
        enemy.setCurrentHp(enemy.getMaxHp());
        enemy.setBaseAttack((int) (enemy.getBaseAttack() * enhanceRate));
        System.out.println("⚠️ " + enemy.getName() + "属性强化" + (currentWave * 10) + "%!");
    }

    // ========== 辅助方法:获取敌人描述 ==========
    private String getEnemiesDesc() {
        StringBuilder desc = new StringBuilder();
        for (int i = 0; i < currentWaveEnemies.size(); i++) {
            desc.append(currentWaveEnemies.get(i).getName());
            if (i < currentWaveEnemies.size() - 1) {
                desc.append(" + ");
            }
        }
        return desc.toString();
    }

    // ========== 核心方法:当前波次战斗 ==========
    private boolean fightCurrentWave() {
        // 波次战斗主循环:直到所有敌人被击败或Allen死亡
        while (true) {
            // 1. 检查Allen是否存活
            if (super.getAllen().getHp() <= 0) {
                return false;
            }
            
            // 2. 检查当前波次所有敌人是否被击败
            if (areAllEnemiesDead()) {
                return true;
            }
            
            // 3. 玩家回合(选择攻击目标)
            playerTurnWithTarget();
            
            // 4. 敌人回合(所有存活敌人依次攻击)
            enemiesTurn();
        }
    }

    // ========== 辅助方法:玩家回合(可选攻击目标) ==========
    private void playerTurnWithTarget() {
        System.out.println("\n👉 艾伦的行动回合!");
        super.showActionMenu();
        
        int choice = super.getValidChoice(1, 4);
        switch (choice) {
            case 1:
                // 攻击:选择目标
                attackWithTarget();
                break;
            case 2:
                // 使用道具
                super.useItem();
                break;
            case 3:
                // 逃跑(多波战斗中逃跑视为失败)
                System.out.println("❌ 多波战斗中无法逃跑!");
                playerTurnWithTarget();
                break;
            case 4:
                // 查看状态
                showWaveStatus();
                playerTurnWithTarget();
                break;
        }
    }

    // ========== 辅助方法:选择攻击目标 ==========
    private void attackWithTarget() {
        // 展示存活敌人列表
        System.out.println("\n🎯 选择攻击目标:");
        List<Enemy> aliveEnemies = getAliveEnemies();
        for (int i = 0; i < aliveEnemies.size(); i++) {
            Enemy enemy = aliveEnemies.get(i);
            System.out.println((i + 1) + ". " + enemy.getName() + " | HP:" + enemy.getCurrentHp() + "/" + enemy.getMaxHp());
        }
        
        // 选择目标
        int targetChoice = super.getValidChoice(1, aliveEnemies.size());
        Enemy targetEnemy = aliveEnemies.get(targetChoice - 1);
        
        // 执行攻击
        super.allenAttack(targetEnemy);
        
        // 触发Lia辅助攻击(随机攻击一个存活敌人)
        triggerLiaRandomHelpAttack();
    }

    // ========== 辅助方法:敌人回合 ==========
    private void enemiesTurn() {
        System.out.println("\n👹 敌人行动回合!");
        List<Enemy> aliveEnemies = getAliveEnemies();
        
        for (Enemy enemy : aliveEnemies) {
            // 检查敌人是否逃跑
            if (enemy.isFleeing()) {
                if (random.nextDouble() <= 0.7) {
                    System.out.println("🏃 " + enemy.getName() + "成功逃跑!");
                    continue;
                }
            }
            
            // 敌人攻击(优先攻击仇恨目标)
            if (enemy.getHateTarget() == 1 && super.getLia().getTrustLevel() >= 60) {
                // 攻击Lia
                attackLia(enemy);
            } else {
                // 攻击Allen
                enemy.attackEnemy(super.getAllen());
            }
            
            // 检查Allen/Lia是否存活
            if (super.getAllen().getHp() <= 0 || super.getLia().getHp() <= 0) {
                return;
            }
        }
    }

    // ========== 辅助方法:敌人攻击Lia ==========
    private void attackLia(Enemy enemy) {
        int damage = enemy.getBaseAttack();
        Lia lia = super.getLia();
        lia.setHp(lia.getHp() - damage);
        System.out.println("👹 " + enemy.getName() + "攻击莉娅!造成" + damage + "点伤害!");
        System.out.println("❤️ 莉娅当前HP:" + lia.getHp() + "/" + lia.getMaxHp());
        
        // Lia血量过低时,Allen可选择保护
        if (lia.getHp() <= 20) {
            System.out.println("\n⚠️ 莉娅血量危急!是否保护莉娅?(1. 是 2. 否)");
            int protectChoice = super.getValidChoice(1, 2);
            if (protectChoice == 1) {
                // 保护:承受50%伤害
                int protectDamage = (int) (damage * 0.5);
                super.getAllen().setHp(super.getAllen().getHp() - protectDamage);
                lia.setHp(lia.getHp() + damage - protectDamage);
                System.out.println("🛡️ 艾伦保护莉娅!承受" + protectDamage + "点伤害!");
            }
        }
    }

    // ========== 辅助方法:获取存活敌人 ==========
    private List<Enemy> getAliveEnemies() {
        List<Enemy> aliveEnemies = new ArrayList<>();
        for (Enemy enemy : currentWaveEnemies) {
            if (enemy.getCurrentHp() > 0) {
                aliveEnemies.add(enemy);
            }
        }
        return aliveEnemies;
    }

    // ========== 辅助方法:检查所有敌人是否死亡 ==========
    private boolean areAllEnemiesDead() {
        return getAliveEnemies().isEmpty();
    }

    // ========== 辅助方法:展示波次状态 ==========
    private void showWaveStatus() {
        System.out.println("\n📊 第" + (currentWave + 1) + "波战斗状态:");
        super.showStatus();
        System.out.println("👹 存活敌人数量:" + getAliveEnemies().size() + "/" + currentWaveEnemies.size());
    }

    // ========== 辅助方法:触发Lia随机辅助攻击 ==========
    private void triggerLiaRandomHelpAttack() {
        Lia lia = super.getLia();
        if (lia.getTrustLevel() >= 50 && random.nextDouble() <= (0.3 + (lia.getTrustLevel() - 50) * 0.01)) {
            List<Enemy> aliveEnemies = getAliveEnemies();
            if (!aliveEnemies.isEmpty()) {
                // 随机选择一个存活敌人攻击
                Enemy randomEnemy = aliveEnemies.get(random.nextInt(aliveEnemies.size()));
                int helpDamage = lia.helpAllenFight(randomEnemy);
                System.out.println("🤝 莉娅随机辅助攻击!对" + randomEnemy.getName() + "造成" + helpDamage + "点伤害!");
            }
        }
    }

    // ========== 核心方法:波次结算 ==========
    private void waveSettlement() {
        System.out.println("\n🎉 第" + (currentWave + 1) + "波战斗胜利!");
        // 波次奖励:金币+经验(逐波提升)
        int waveGold = baseWaveReward * (currentWave + 1);
        int waveExp = 15 * (currentWave + 1);
        
        Allen allen = super.getAllen();
        allen.setGold(allen.getGold() + waveGold);
        allen.addExperience(waveExp);
        
        System.out.println("💰 获得" + waveGold + "金币!当前金币:" + allen.getGold());
        System.out.println("📚 获得" + waveExp + "经验值!当前等级:" + allen.getLevel());
        
        // 低概率掉落道具
        if (random.nextDouble() <= 0.2) {
            Item rewardItem = new HealPotion();
            allen.pickItem(rewardItem);
            System.out.println("🎁 额外奖励:" + rewardItem.getName() + "!");
        }
    }

    // ========== 核心方法:波次间休整 ==========
    private void interWaveRest() {
        System.out.println("\n🛌 波次间休整!");
        System.out.println("1. ❤️ 莉娅为你恢复10点HP(信任度≥50)");
        System.out.println("2. 📊 查看状态");
        System.out.println("3. ⏭️ 继续下一波战斗");
        
        int choice = super.getValidChoice(1, 3);
        switch (choice) {
            case 1:
                // Lia治疗
                if (super.getLia().getTrustLevel() >= 50) {
                    Allen allen = super.getAllen();
                    allen.setHp(allen.getHp() + 10);
                    System.out.println("❤️ 莉娅为你恢复10点HP!当前HP:" + allen.getHp() + "/" + allen.getMaxHp());
                } else {
                    System.out.println("❌ 莉娅信任度不足,无法治疗!");
                }
                interWaveRest();
                break;
            case 2:
                showWaveStatus();
                interWaveRest();
                break;
            case 3:
                // 继续下一波
                break;
        }
    }

    // ========== 核心方法:多波战斗最终结算 ==========
    private void finalSettlement() {
        System.out.println("\n=====================================");
        System.out.println("🏁 多波战斗结算!");
        System.out.println("=====================================");
        
        if (super.isVictory()) {
            System.out.println("🎉 恭喜!通关所有" + totalWaves + "波战斗!");
            // 最终奖励:稀有道具(魔法花)
            Item rareItem = new MagicFlower();
            super.getAllen().pickItem(rareItem);
            System.out.println("🎁 通关奖励:" + rareItem.getName() + "(提升莉娅信任度20点)!");
            // 高额经验奖励
            super.getAllen().addExperience(50);
            System.out.println("📚 额外获得50点经验值!");
        } else {
            System.out.println("💀 多波战斗失败!");
            // 失败惩罚:损失20%金币
            int loseGold = (int) (super.getAllen().getGold() * 0.2);
            super.getAllen().setGold(Math.max(super.getAllen().getGold() - loseGold, 0));
            System.out.println("💰 损失" + loseGold + "金币!剩余金币:" + super.getAllen().getGold());
        }
    }

    // ========== 辅助方法:展示波次状态 ==========
    private void showWaveStatus() {
        System.out.println("\n📊 第" + (currentWave + 1) + "波战斗状态:");
        System.out.println("【艾伦】HP:" + super.getAllen().getHp() + "/" + super.getAllen().getMaxHp() +
                " | 攻击力:" + super.getAllen().getAttackPower() +
                " | 金币:" + super.getAllen().getGold());
        System.out.println("【莉娅】信任度:" + super.getLia().getTrustLevel() + "/100" +
                " | HP:" + super.getLia().getHp() + "/" + super.getLia().getMaxHp());
        System.out.println("【当前波次敌人】:");
        for (Enemy enemy : currentWaveEnemies) {
            System.out.println(" - " + enemy.getName() + " | HP:" + enemy.getCurrentHp() + "/" + enemy.getMaxHp() +
                    " | 攻击力:" + enemy.getBaseAttack());
        }
    }

    // ========== 辅助方法:获取存活敌人 ==========
    private List<Enemy> getAliveEnemies() {
        List<Enemy> alive = new ArrayList<>();
        for (Enemy enemy : currentWaveEnemies) {
            if (enemy.getCurrentHp() > 0) {
                alive.add(enemy);
            }
        }
        return alive;
    }

    // ========== 辅助方法:检查所有敌人是否死亡 ==========
    private boolean areAllEnemiesDead() {
        return getAliveEnemies().isEmpty();
    }
}

/**
 * BOSS战斗系统:TreeSpiritBattleSystem
 * 实现树灵BOSS的特殊战斗规则
 */
class TreeSpiritBattleSystem extends BattleSystem {
    // BOSS阶段:0-普通,1-狂暴(HP<50%)
    private int bossPhase;
    // BOSS回血冷却回合
    private int healCooldown;
    // 随机数生成器
    private Random random;

    public TreeSpiritBattleSystem(Allen allen, Lia lia) {
        // 初始化树灵BOSS
        TreeSpirit treeSpirit = new TreeSpirit();
        super(allen, lia, treeSpirit);
        
        this.bossPhase = 0;
        this.healCooldown = 0;
        this.random = new Random();
        
        System.out.println("\n🌳 遭遇森林守护者 - 树灵BOSS!");
        System.out.println("⚠️ BOSS特性:HP<50%进入狂暴状态 | 每5回合尝试回血 | 范围攻击!");
    }

    @Override
    public void startBattle() {
        int round = 1;
        while (!super.isBattleOver()) {
            System.out.println("\n🔄 BOSS战第" + round + "回合!");
            
            // 1. 检查BOSS阶段
            checkBossPhase();
            
            // 2. 玩家回合
            super.playerTurn();
            
            if (super.isBattleOver()) break;
            
            // 3. BOSS回合(特殊技能)
            bossTurn(round);
            
            if (super.isBattleOver()) break;
            
            // 4. 冷却回合更新
            updateCooldown();
            round++;
        }
        
        // BOSS战结算
        bossBattleSettlement();
    }

    // ========== 辅助方法:检查BOSS阶段 ==========
    private void checkBossPhase() {
        TreeSpirit boss = (TreeSpirit) super.getEnemy();
        if (boss.getCurrentHp() <= boss.getMaxHp() * 0.5 && bossPhase == 0) {
            // 进入狂暴阶段
            bossPhase = 1;
            boss.setBaseAttack((int) (boss.getBaseAttack() * 1.5));
            System.out.println("🔥 树灵进入狂暴状态!攻击力提升50%!");
        }
    }

    // ========== 核心方法:BOSS回合 ==========
    private void bossTurn(int round) {
        TreeSpirit boss = (TreeSpirit) super.getEnemy();
        System.out.println("\n🌳 树灵BOSS行动回合!");
        
        // 1. 回血判定(冷却结束且HP<80%)
        if (healCooldown <= 0 && boss.getCurrentHp() < boss.getMaxHp() * 0.8) {
            int healValue = boss.heal();
            System.out.println("🌱 树灵使用自然之力回血!恢复" + healValue + "点HP!");
            healCooldown = 5; // 重置冷却
            return;
        }
        
        // 2. 技能判定(狂暴阶段有概率释放范围攻击)
        if (bossPhase == 1 && random.nextDouble() <= 0.3) {
            // 范围攻击:同时攻击Allen和Lia
            int rangeDamage = (int) (boss.getBaseAttack() * 0.8);
            System.out.println("🌪️ 树灵释放范围攻击!");
            
            // 攻击Allen
            super.getAllen().setHp(super.getAllen().getHp() - rangeDamage);
            System.out.println("💥 对艾伦造成" + rangeDamage + "点伤害!HP:" + super.getAllen().getHp() + "/" + super.getAllen().getMaxHp());
            
            // 攻击Lia
            super.getLia().setHp(super.getLia().getHp() - rangeDamage);
            System.out.println("💥 对莉娅造成" + rangeDamage + "点伤害!HP:" + super.getLia().getHp() + "/" + super.getLia().getMaxHp());
            
            // 检查是否战败
            if (super.getAllen().getHp() <= 0 || super.getLia().getHp() <= 0) {
                super.setBattleOver(true);
                super.setVictory(false);
            }
            return;
        }
        
        // 3. 普通攻击
        boss.attackEnemy(super.getAllen());
        
        // 检查Allen是否存活
        if (super.getAllen().getHp() <= 0) {
            super.setBattleOver(true);
            super.setVictory(false);
        }
    }

    // ========== 辅助方法:更新冷却回合 ==========
    private void updateCooldown() {
        if (healCooldown > 0) {
            healCooldown--;
            System.out.println("⏳ 树灵回血冷却剩余:" + healCooldown + "回合");
        }
    }

    // ========== 核心方法:BOSS战结算 ==========
    private void bossBattleSettlement() {
        System.out.println("\n=====================================");
        System.out.println("🏁 树灵BOSS战结算!");
        System.out.println("=====================================");
        
        if (super.isVictory()) {
            System.out.println("🎉 恭喜!击败树灵BOSS!");
            // BOSS专属奖励
            Allen allen = super.getAllen();
            // 高额金币
            allen.setGold(allen.getGold() + 100);
            System.out.println("💰 获得100金币奖励!");
            // 稀有魔法卷轴
            Item scroll = new AdvancedMagicScroll();
            allen.pickItem(scroll);
            System.out.println("🎁 获得稀有道具:" + scroll.getName() + "!");
            // 大量经验
            allen.addExperience(100);
            System.out.println("📚 获得100点经验值!");
            // Lia信任度满值
            super.getLia().setTrustLevel(100);
            System.out.println("❤️ 莉娅信任度提升至100!解锁全部辅助技能!");
        } else {
            System.out.println("💀 BOSS战失败!");
            // 惩罚:损失50%金币
            int loseGold = (int) (super.getAllen().getGold() * 0.5);
            super.getAllen().setGold(Math.max(super.getAllen().getGold() - loseGold, 0));
            System.out.println("💰 损失" + loseGold + "金币!剩余金币:" + super.getAllen().getGold());
        }
    }
}

// ========== 依赖类补充(保证代码可运行) ==========
// 基础战斗系统父类(简化版)
class BattleSystem {
    private Allen allen;
    private Lia lia;
    private Enemy enemy;
    protected boolean isBattleOver;
    protected boolean isVictory;
    private Scanner scanner;

    public BattleSystem(Allen allen, Lia lia, Enemy enemy) {
        this.allen = allen;
        this.lia = lia;
        this.enemy = enemy;
        this.isBattleOver = false;
        this.isVictory = false;
        this.scanner = new Scanner(System.in);
    }

    public void startBattle() {}

    protected void showActionMenu() {
        System.out.println("1. ⚔️ 攻击");
        System.out.println("2. 🎒 使用道具");
        System.out.println("3. 🏃 尝试逃跑");
        System.out.println("4. 📊 查看状态");
        System.out.print("输入数字选择:");
    }

    protected int getValidChoice(int min, int max) {
        int choice = -1;
        while (true) {
            if (scanner.hasNextInt()) {
                choice = scanner.nextInt();
                if (choice >= min && choice <= max) break;
                else System.out.print("❌ 输入无效!请输入" + min + "-" + max + "之间的数字:");
            } else {
                scanner.next();
                System.out.print("❌ 输入无效!请输入数字:");
            }
        }
        return choice;
    }

    protected void useItem() {
        System.out.println("\n🎒 背包:");
        List<Item> backpack = allen.getBackpack();
        if (backpack.isEmpty()) {
            System.out.println("📦 背包为空!");
            return;
        }
        for (int i = 0; i < backpack.size(); i++) {
            System.out.println((i+1) + ". " + backpack.get(i).getName() + " - " + backpack.get(i).getEffectDesc());
        }
        System.out.println((backpack.size()+1) + ". ❌ 取消");
        
        int choice = getValidChoice(1, backpack.size()+1);
        if (choice == backpack.size()+1) return;
        
        Item item = backpack.get(choice-1);
        item.use(allen);
        System.out.println("✅ 使用" + item.getName() + "成功!");
        if (item.isConsumable()) backpack.remove(choice-1);
    }

    protected void allenAttack(Enemy target) {
        int baseDamage = Math.max(allen.getAttackPower() - getEnemyDefense(target), 1);
        double critChance = Math.random();
        int finalDamage = baseDamage;
        if (critChance <= 0.15) {
            finalDamage = (int) (baseDamage * 1.5);
            System.out.println("💥 暴击!");
        }
        target.takeDamage(finalDamage);
        System.out.println("⚔️ 对" + target.getName() + "造成" + finalDamage + "点伤害!");
    }

    private int getEnemyDefense(Enemy enemy) {
        return enemy instanceof Goblin ? 3 : 5;
    }

    protected void showStatus() {
        System.out.println("\n📊 战斗状态:");
        System.out.println("【艾伦】HP:" + allen.getHp() + "/" + allen.getMaxHp());
        System.out.println("【莉娅】信任度:" + lia.getTrustLevel() + "/100");
        System.out.println("【" + enemy.getName() + "】HP:" + enemy.getCurrentHp() + "/" + enemy.getMaxHp());
    }

    public Allen getAllen() { return allen; }
    public Lia getLia() { return lia; }
    public Enemy getEnemy() { return enemy; }
    public boolean isVictory() { return isVictory; }
    public void setBattleOver(boolean over) { this.isBattleOver = over; }
    public void setVictory(boolean victory) { this.isVictory = victory; }
}

// 树灵BOSS类
class TreeSpirit extends Enemy {
    public TreeSpirit() {
        super("树灵守护者", "森林的古老BOSS", 200, 20);
    }

    // BOSS回血方法
    public int heal() {
        int healValue = 30;
        this.setCurrentHp(Math.min(this.getCurrentHp() + healValue, this.getMaxHp()));
        return healValue;
    }

    @Override
    public boolean takeDamage(int damage) {
        // BOSS有10%概率减免50%伤害
        if (Math.random() <= 0.1) {
            damage = (int) (damage * 0.5);
            System.out.println("🌳 树灵的自然护甲减免50%伤害!");
        }
        this.setCurrentHp(this.getCurrentHp() - damage);
        if (this.getCurrentHp() <= 0) {
            this.setCurrentHp(0);
            return false;
        }
        return true;
    }
}

// 高级魔法卷轴道具
class AdvancedMagicScroll extends Item {
    public AdvancedMagicScroll() {
        super("高级魔法卷轴", "提升20点攻击力,持续3回合", true, "稀有");
    }

    @Override
    public boolean use(Person target) {
        if (target instanceof Allen) {
            Allen allen = (Allen) target;
            allen.setAttackPower(allen.getAttackPower() + 20);
            System.out.println("⚡ 攻击力提升20点!持续3回合!");
            return true;
        }
        return false;
    }

    @Override
    public String getEffectDesc() {
        return "提升20点攻击力,持续3回合";
    }
}

// 魔法花道具
class MagicFlower extends Item {
    public MagicFlower() {
        super("魔法花", "提升莉娅信任度20点", false, "稀有");
    }

    @Override
    public boolean use(Person target) {
        if (target instanceof Lia) {
            Lia lia = (Lia) target;
            lia.setTrustLevel(lia.getTrustLevel() + 20);
            System.out.println("❤️ 莉娅信任度+20!当前:" + lia.getTrustLevel() + "/100");
            return true;
        }
        return false;
    }

    @Override
    public String getEffectDesc() {
        return "提升莉娅信任度20点";
    }
}

// 其他基础类(简化版,保证代码可运行)
abstract class Enemy extends Figure {
    protected int currentHp;
    protected int maxHp;
    protected int baseAttack;
    protected boolean isFleeing;
    protected int hateTarget;

    public Enemy(String name, String description, int maxHp, int baseAttack) {
        super(name, description);
        this.maxHp = maxHp;
        this.currentHp = maxHp;
        this.baseAttack = baseAttack;
        this.isFleeing = false;
        this.hateTarget = 0;
    }

    public abstract boolean takeDamage(int damage);

    public void attackEnemy(Person target) {
        target.setHp(target.getHp() - this.baseAttack);
        System.out.println("👹 " + this.name + "对" + target.getName() + "造成" + this.baseAttack + "点伤害!");
    }

    public int getCurrentHp() { return currentHp; }
    public void setCurrentHp(int hp) { this.currentHp = hp; }
    public int getMaxHp() { return maxHp; }
    public void setMaxHp(int hp) { this.maxHp = hp; }
    public int getBaseAttack() { return baseAttack; }
    public void setBaseAttack(int attack) { this.baseAttack = attack; }
    public boolean isFleeing() { return isFleeing; }
    public int getHateTarget() { return hateTarget; }
}

class Goblin extends Enemy {
    public Goblin() {
        super("普通哥布林", "低智商小怪", 50, 10);
    }

    public Goblin(boolean isLeader) {
        super(isLeader ? "哥布林首领" : "普通哥布林", 
                isLeader ? "哥布林头目" : "低智商小怪", 
                isLeader ? 80 : 50, 
                isLeader ? 15 : 10);
    }

    @Override
    public boolean takeDamage(int damage) {
        this.currentHp -= damage;
        return this.currentHp > 0;
    }
}

class Elf extends Enemy {
    public Elf() {
        super("精灵弓箭手", "魔法弓箭手", 60, 12);
    }

    @Override
    public boolean takeDamage(int damage) {
        if (Math.random() <= 0.15) {
            System.out.println("💨 精灵闪避攻击!");
            return true;
        }
        this.currentHp -= damage;
        return this.currentHp > 0;
    }
}

abstract class Person extends Figure {
    protected int hp;
    protected int maxHp;
    protected int gold;

    public Person(String name, String description) {
        super(name, description);
    }

    public int getHp() { return hp; }
    public void setHp(int hp) { this.hp = Math.max(hp, 0); }
    public int getMaxHp() { return maxHp; }
    public int getGold() { return gold; }
    public void setGold(int gold) { this.gold = gold; }
}

class Allen extends Person {
    private int attackPower;
    private int skillLevel;
    private int experience;
    private int level;
    private List<Item> backpack;

    public Allen() {
        super("艾伦", "冒险者");
        this.maxHp = 100;
        this.hp = 100;
        this.attackPower = 15;
        this.skillLevel = 1;
        this.experience = 0;
        this.level = 1;
        this.backpack = new ArrayList<>();
    }

    public int getAttackPower() { return attackPower; }
    public void setAttackPower(int power) { this.attackPower = power; }
    public int getSkillLevel() { return skillLevel; }
    public List<Item> getBackpack() { return backpack; }
    public void pickItem(Item item) { backpack.add(item); }
    public int getLevel() { return level; }
    public void addExperience(int exp) {
        this.experience += exp;
        if (this.experience >= 100) {
            this.level++;
            this.experience -= 100;
            this.attackPower += 2;
            this.maxHp += 10;
            this.hp = this.maxHp;
            System.out.println("🎉 升级到" + level + "级!");
        }
    }
}

class Lia extends Person {
    private int trustLevel;

    public Lia() {
        super("莉娅", "精灵盟友");
        this.maxHp = 80;
        this.hp = 80;
        this.trustLevel = 0;
    }

    public int getTrustLevel() { return trustLevel; }
    public void setTrustLevel(int level) { this.trustLevel = Math.min(level, 100); }
    public int helpAllenFight(Enemy enemy) {
        int damage = 10;
        enemy.takeDamage(damage);
        return damage;
    }
}

abstract class Item {
    protected String name;
    protected String description;
    protected boolean isConsumable;

    public Item(String name, String description, boolean isConsumable, String rarity) {
        this.name = name;
        this.description = description;
        this.isConsumable = isConsumable;
    }

    public abstract boolean use(Person target);
    public abstract String getEffectDesc();
    public String getName() { return name; }
    public boolean isConsumable() { return isConsumable; }
}

class HealPotion extends Item {
    public HealPotion() {
        super("普通治疗药水", "恢复20点HP", true, "普通");
    }

    @Override
    public boolean use(Person target) {
        target.setHp(target.getHp() + 20);
        return true;
    }

    @Override
    public String getEffectDesc() {
        return "恢复20点HP";
    }
}

abstract class Figure {
    protected String name;
    protected String description;

    public Figure(String name, String description) {
        this.name = name;
        this.description = description;
    }

    public String getName() { return name; }
}

// ========== 测试类 ==========
class WaveAndBossBattleTest {
    public static void main(String[] args) {
        // 1. 创建角色
        Allen allen = new Allen();
        Lia lia = new Lia();
        lia.setTrustLevel(70);
        allen.pickItem(new HealPotion());

        // 2. 多波战斗测试(3波)
        WaveBattleSystem waveBattle = new WaveBattleSystem(allen, lia, 3);
        waveBattle.startBattle();

        // 3. BOSS战测试
        TreeSpiritBattleSystem bossBattle = new TreeSpiritBattleSystem(allen, lia);
        bossBattle.startBattle();
    }
}

2.2 关键知识点讲解💡

(1)多波战斗的核心流程





多波战斗初始化
当前波次=0
当前波次 < 总波次?
刷新当前波次敌人(属性强化)
当前波次战斗
波次胜利?
波次结算(奖励)
波次间休整
当前波次+1
多波战斗失败结算
多波战斗胜利最终结算
战斗结束

  • 敌人刷新阶段:每波敌人数量/属性随波次提升(10%攻击力/血量加成);
  • 波次战斗阶段:玩家可选择攻击目标,所有存活敌人依次攻击;
  • 波次结算阶段:奖励逐波提升,波次间可休整(Lia治疗/查看状态);
  • 最终结算阶段:通关所有波次获得稀有道具,失败则损失金币。

👉 新手重点:多波战斗的核心是「波次循环+敌人强化+阶段奖励」,通过逐波提升难度增加挑战性

(2)BOSS战的状态机设计

HP < 50%
无(不可逆)
基础攻击 | 每5回合回血
攻击力+50% | 30%概率范围攻击 | 每5回合回血

  • 阶段触发:BOSS血量低于50%时进入狂暴阶段,攻击力永久提升50%;
  • 技能规则:普通阶段每5回合尝试回血,狂暴阶段额外有30%概率释放范围攻击;
  • 防御特性:BOSS有10%概率减免50%伤害,区别于普通敌人。

👉 新手重点:BOSS战的核心是「状态机+特殊技能」,通过阶段变化和专属技能体现BOSS的独特性

🔧 三、核心代码拆解(二):Allen+Lia联合作战逻辑

3.1 仇恨分担机制

java 复制代码
private void enemiesTurn() {
    for (Enemy enemy : aliveEnemies) {
        // 仇恨目标为1且Lia信任度≥60 → 攻击Lia
        if (enemy.getHateTarget() == 1 && super.getLia().getTrustLevel() >= 60) {
            attackLia(enemy);
        } else {
            // 否则攻击Allen
            enemy.attackEnemy(super.getAllen());
        }
    }
}
  • 触发条件:Lia信任度≥60时,敌人仇恨目标可切换为Lia;
  • 协作价值:Lia分担伤害,保护Allen的输出环境,体现角色协作的策略性;
  • 保护机制:Lia血量≤20时,Allen可选择保护(承受50%伤害)。

3.2 Lia辅助攻击/治疗

java 复制代码
// 随机辅助攻击
private void triggerLiaRandomHelpAttack() {
    if (lia.getTrustLevel() >= 50 && random.nextDouble() <= (0.3 + (lia.getTrustLevel() - 50) * 0.01)) {
        Enemy randomEnemy = aliveEnemies.get(random.nextInt(aliveEnemies.size()));
        int helpDamage = lia.helpAllenFight(randomEnemy);
        System.out.println("🤝 莉娅随机辅助攻击!造成" + helpDamage + "点伤害!");
    }
}

// 波次间治疗
private void interWaveRest() {
    if (lia.getTrustLevel() >= 50) {
        allen.setHp(allen.getHp() + 10);
        System.out.println("❤️ 莉娅为你恢复10点HP!");
    }
}
  • 辅助攻击:信任度越高,辅助概率越高(50→30%,100→80%),随机攻击一个敌人;
  • 波次间治疗:信任度≥50时,Allen可选择让Lia恢复10点HP,提升续航能力;
  • BOSS战奖励:击败树灵后Lia信任度直接拉满,解锁全部辅助技能。

🧪 四、调试示例:多波战斗+BOSS战完整流程

4.1 调试输出结果(核心片段)

复制代码
🌋 进入黑暗洞穴 - 多波战斗模式!
🎯 总波次:3 | 每波敌人强度逐次提升!
🏆 通关奖励:稀有道具 + 高额经验值!

=====================================
🌊 第1/3波战斗开始!
👹 本波敌人:普通哥布林
=====================================
⚠️ 普通哥布林属性强化0%!

👉 艾伦的行动回合!
1. ⚔️ 攻击
2. 🎒 使用道具
3. 🏃 尝试逃跑
4. 📊 查看状态
输入数字选择:1

🎯 选择攻击目标:
1. 普通哥布林 | HP:50/50
输入数字选择:1

💥 暴击!
💥 普通哥布林受到18点伤害!当前HP:32/50
⚔️ 对普通哥布林造成18点伤害!

👹 敌人行动回合!
👹 普通哥布林对艾伦造成10点伤害!

👉 艾伦的行动回合!
...

🎉 第1波战斗胜利!
💰 获得10金币!当前金币:10
📚 获得15经验值!当前等级:1

🛌 波次间休整!
1. ❤️ 莉娅为你恢复10点HP(信任度≥50)
2. 📊 查看状态
3. ⏭️ 继续下一波战斗
输入数字选择:1
❤️ 莉娅为你恢复10点HP!当前HP:90/100

=====================================
🌊 第2/3波战斗开始!
👹 本波敌人:普通哥布林 + 精灵弓箭手
=====================================
⚠️ 普通哥布林属性强化10%!
⚠️ 精灵弓箭手属性强化10%!
...

🎉 第3波战斗胜利!
💰 获得30金币!当前金币:55
📚 获得45经验值!当前等级:1

=====================================
🏁 多波战斗结算!
=====================================
🎉 恭喜!通关所有3波战斗!
🎁 通关奖励:魔法花(提升莉娅信任度20点)!
📚 额外获得50点经验值!

🌳 遭遇森林守护者 - 树灵BOSS!
⚠️ BOSS特性:HP<50%进入狂暴状态 | 每5回合尝试回血 | 范围攻击!

🔄 BOSS战第1回合!

👉 艾伦的行动回合!
1. ⚔️ 攻击
2. 🎒 使用道具
3. 🏃 尝试逃跑
4. 📊 查看状态
输入数字选择:1

💥 暴击!
🌳 树灵的自然护甲减免50%伤害!
💥 树灵守护者受到18点伤害!当前HP:182/200
⚔️ 对树灵守护者造成18点伤害!

🌳 树灵BOSS行动回合!
👹 树灵守护者对艾伦造成20点伤害!

🔄 BOSS战第6回合!
🔥 树灵进入狂暴状态!攻击力提升50%!

👉 艾伦的行动回合!
...

🌳 树灵BOSS行动回合!
🌱 树灵使用自然之力回血!恢复30点HP!

🔄 BOSS战第10回合!
🌳 树灵BOSS行动回合!
🌪️ 树灵释放范围攻击!
💥 对艾伦造成24点伤害!HP:26/100
💥 对莉娅造成24点伤害!HP:56/80

👉 艾伦的行动回合!
...

✅ 树灵守护者被击败!

=====================================
🏁 树灵BOSS战结算!
=====================================
🎉 恭喜!击败树灵BOSS!
💰 获得100金币奖励!
🎁 获得稀有道具:高级魔法卷轴!
📚 获得100点经验值!
❤️ 莉娅信任度提升至100!解锁全部辅助技能!

👉 结论:多波战斗的逐波强化、BOSS战的阶段变化、Allen+Lia的联合作战等核心逻辑均正常生效,符合设计预期!

🚨 五、多波战斗&BOSS战设计的「新手坑」与最佳实践

(1)新手常见错误

错误写法 正确写法 问题说明
多波敌人属性无强化(每波难度相同) 每波提升10%攻击力/血量 战斗无挑战性,玩家体验差
BOSS阶段不可逆但未做状态标记 使用bossPhase标记阶段,触发后永久生效 BOSS反复进入狂暴阶段,逻辑混乱
联合作战无策略性(Lia仅单纯加血) 绑定信任度+仇恨分担+随机辅助 角色协作无价值,玩法单一
BOSS技能无冷却(无限回血) 增加healCooldown冷却回合 BOSS无敌,战斗无法获胜

(2)最佳实践

  1. 难度梯度化:多波敌人逐波强化,BOSS分阶段提升难度,符合玩家成长曲线;
  2. 状态标记化 :使用状态变量(bossPhase/healCooldown)控制BOSS行为,避免逻辑混乱;
  3. 协作策略化:Lia的辅助/治疗/仇恨分担与信任度强绑定,体现协作价值;
  4. 奖励差异化:普通战斗→基础奖励,多波战斗→稀有道具,BOSS战→高额奖励,驱动玩家挑战;
  5. 规则透明化:战斗前明确提示BOSS特性/多波规则,让玩家有策略准备。

📌 知识回顾

  1. 多波战斗的核心流程是「波次初始化→敌人刷新→波次战斗→波次结算→休整→下一波」,敌人属性随波次逐次强化(10%/波);
  2. 树灵BOSS战采用状态机设计,HP<50%进入狂暴阶段(攻击力+50%),每5回合尝试回血,狂暴阶段有30%概率释放范围攻击;
  3. Allen+Lia联合作战体现在「仇恨分担(Lia吸引伤害)+ 辅助攻击(信任度驱动)+ 波次间治疗」,信任度是核心联动指标;
  4. 多波战斗通关奖励稀有魔法花(提升Lia信任度),BOSS战通关解锁Lia满信任度,形成玩法闭环;
  5. 多波战斗中无法逃跑,BOSS战有专属防御特性(10%概率减免50%伤害),区别于基础战斗规则。

✍️ 写在最后

多波战斗与BOSS战是「魔法森林冒险」战斗系统的进阶玩法,其「难度梯度化+协作深度化+规则特殊化」的设计思路,既保证了战斗的挑战性,又通过Allen+Lia的联合作战体现了角色联动的趣味性。

下一篇我们会聚焦「场景系统:5大场景的任务串联」,带你拆解Region抽象类的设计、各场景的任务触发逻辑、场景切换规则,以及Lia/老贤者在不同场景中的触发时机🌲。

新手建议:

  1. 在IDE中运行本文的调试示例,尝试修改BOSS的狂暴阈值(从50%改为40%)和回血冷却(从5回合改为4回合),观察战斗难度变化;
  2. 思考:如果新增「BOSS弱点机制」(使用火系道具造成双倍伤害),该如何修改takeDamage()方法?

🔥 系列文章导航:

  1. 项目总览:设计与架构
  2. 抽象层设计:Figure/Person类
  3. Allen类(一):核心属性与初始化
  4. Allen类(二):道具交互核心逻辑
  5. Allen类(三):任务进度与状态管理
  6. Lia类深度解析:盟友角色的设计与交互
  7. 老贤者 & 树灵:NPC/BOSS角色的设计
  8. 道具系统:基础/关键/特殊道具的实现
  9. 敌人系统:Goblin/Elf的AI与战斗基础
  10. 战斗系统(一):基础回合制逻辑
  11. 战斗系统(二):多波战斗与BOSS战(本文)
  12. 场景系统:5大场景的任务串联
    ...(后续篇章持续更新)
    💬 评论区互动:你觉得多波战斗/BOSS战还可以增加哪些趣味功能?比如「BOSS阶段掉落增益道具」「多波战斗随机事件(如宝箱/陷阱)」,或者「Allen+Lia组合技能(信任度满触发)」?
相关推荐
csbysj20203 小时前
PHP Mail - 发送邮件的最佳实践指南
开发语言
我命由我123453 小时前
Android多进程开发 - AIDL 最简单的实现、传递数据大小限制
android·java·java-ee·kotlin·android studio·android jetpack·android-studio
jdbcaaa3 小时前
Go 语言 runtime 包的使用与注意事项
开发语言·后端·golang·runtime
ZHOUPUYU5 小时前
PHP 8.3网关优化:我用JIT将QPS提升300%的真实踩坑录
开发语言·php
寻寻觅觅☆9 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
l1t10 小时前
在wsl的python 3.14.3容器中使用databend包
开发语言·数据库·python·databend
青云计划10 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿10 小时前
Jsoniter(java版本)使用介绍
java·开发语言
ceclar12311 小时前
C++使用format
开发语言·c++·算法