【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局

🏠个人主页:黎雁

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

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

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

文章目录

  • [【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局🎯](#【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局🎯)
    • [📝 文章摘要](#📝 文章摘要)
    • [🎮 一、支线任务:游戏的「可玩性放大器」](#🎮 一、支线任务:游戏的「可玩性放大器」)
    • [🔧 二、核心代码拆解(一):两大核心支线任务](#🔧 二、核心代码拆解(一):两大核心支线任务)
    • [🧪 三、调试示例:支线任务+计分系统完整流程](#🧪 三、调试示例:支线任务+计分系统完整流程)
      • [3.1 调试输出结果(核心片段)](#3.1 调试输出结果(核心片段))
    • [🚨 四、新手常见错误与最佳实践](#🚨 四、新手常见错误与最佳实践)
    • [📌 知识回顾](#📌 知识回顾)
    • [✍️ 写在最后](#✍️ 写在最后)

【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局🎯

📝 文章摘要

内容维度 详情说明
核心摘要 本文是「魔法森林冒险」Java项目系列第十三篇,聚焦游戏的「可玩性拓展层」------支线任务与计分系统。从治疗动物、老贤者交易两大核心支线的设计逻辑(触发条件/任务流程/奖励机制),到ScoreSystem计分系统的核心算法(基础分/行为分/结局分),再到多结局判定规则(Allen等级/Lia信任度/任务完成度联动),带你吃透如何通过支线任务丰富游戏内容、通过计分系统实现多结局的核心设计思路与代码实现。
阅读时长 20分钟
适合人群 1. Java新手:想掌握「多支线任务设计+计分算法+状态驱动多结局」的实战应用;2. 游戏开发入门者:想理解支线任务与主线的联动逻辑、计分系统的设计思路、多结局的触发规则;3. 项目复刻者:想复刻完整的支线任务体系、计分系统和多结局判定逻辑。
阅读重点 1. 两大核心支线任务(治疗动物/老贤者交易)的触发条件与完整流程;2. ScoreSystem计分系统的核心算法(基础分/行为分/结局分的计算规则);3. 多结局判定逻辑(3种结局的触发条件+结局展示);4. 支线与主线的联动设计(支线奖励影响主线结局)。

🎮 一、支线任务:游戏的「可玩性放大器」

支线任务是主线任务的补充,既能丰富游戏内容,又能通过专属奖励(如Lia信任度、稀有道具)影响主线结局。本项目设计了两大核心支线 ,覆盖「角色联动」和「交易解谜」两类经典玩法:

治疗动物支线 → Allen+Lia联动,考验道具使用与信任度交互,奖励高额信任度;

老贤者交易支线 → 解谜+资源交换,奖励稀有道具,影响最终计分;

支线任务的核心设计原则:

  1. 场景绑定:每个支线绑定专属场景(治疗动物→迷雾沼泽,交易支线→黑暗洞穴);
  2. 状态触发:需满足主线进度/角色状态(如Lia信任度≥50)才能激活;
  3. 奖励差异化:奖励与支线类型匹配(互动类→信任度,交易类→道具/金币);
  4. 结局关联:支线完成度直接影响计分系统和最终结局。

🔧 二、核心代码拆解(一):两大核心支线任务

2.1 完整核心代码(可直接运行)

java 复制代码
import java.util.*;

/**
 * 支线任务枚举:定义支线类型与描述
 */
enum SideQuestType {
    HEAL_ANIMAL("治疗受伤的小鹿", "迷雾沼泽专属,Allen+Lia联动支线"),
    SAGE_TRADING("老贤者的交易", "黑暗洞穴专属,解谜+资源交换支线");

    private final String questName;
    private final String questDesc;

    SideQuestType(String name, String desc) {
        this.questName = name;
        this.questDesc = desc;
    }

    public String getQuestName() { return questName; }
    public String getQuestDesc() { return questDesc; }
}

/**
 * 支线任务基类:封装通用属性与方法
 */
abstract class SideQuest {
    // 支线基础信息
    protected SideQuestType questType;
    protected boolean isCompleted;
    protected int baseScore; // 支线基础计分
    // 触发条件
    protected Map<String, Object> triggerConditions;
    // 奖励配置
    protected int expReward;
    protected int goldReward;
    protected int trustReward; // Lia信任度奖励
    protected Item itemReward;
    // 输入扫描器
    protected Scanner scanner;

    public SideQuest(SideQuestType type) {
        this.questType = type;
        this.isCompleted = false;
        this.triggerConditions = new HashMap<>();
        this.scanner = new Scanner(System.in);
        initQuestConfig(); // 初始化支线配置
    }

    /**
     * 初始化支线专属配置(触发条件+奖励)
     */
    protected abstract void initQuestConfig();

    /**
     * 检查支线触发条件
     * @param allen 主角
     * @param lia 盟友
     * @return 是否满足触发条件
     */
    public boolean checkTriggerCondition(Allen allen, Lia lia) {
        if (isCompleted) {
            System.out.println("✅ 该支线已完成!");
            return false;
        }

        // 1. 检查主线进度
        if (triggerConditions.containsKey("mainQuest")) {
            String requiredMainQuest = (String) triggerConditions.get("mainQuest");
            if (!allen.hasCompletedMainQuest(requiredMainQuest)) {
                System.out.println("❌ 未完成前置主线任务:" + requiredMainQuest);
                return false;
            }
        }

        // 2. 检查Lia信任度
        if (triggerConditions.containsKey("trustLevel")) {
            int requiredTrust = (int) triggerConditions.get("trustLevel");
            if (lia.getTrustLevel() < requiredTrust) {
                System.out.println("❌ Lia信任度不足!需要≥" + requiredTrust + "(当前:" + lia.getTrustLevel() + ")");
                return false;
            }
        }

        // 3. 检查道具
        if (triggerConditions.containsKey("item")) {
            String requiredItem = (String) triggerConditions.get("item");
            if (!allen.hasItem(requiredItem)) {
                System.out.println("❌ 缺少触发道具:" + requiredItem);
                return false;
            }
        }

        return true;
    }

    /**
     * 执行支线任务核心逻辑
     * @param allen 主角
     * @param lia 盟友
     * @return 是否完成任务
     */
    public abstract boolean executeQuest(Allen allen, Lia lia);

    /**
     * 发放支线奖励
     * @param allen 主角
     * @param lia 盟友
     */
    protected void giveReward(Allen allen, Lia lia) {
        System.out.println("\n🏆 支线任务奖励发放:");
        // 基础奖励
        allen.addExperience(expReward);
        allen.addGold(goldReward);
        System.out.println(" - 经验+" + expReward + " | 金币+" + goldReward);
        // 信任度奖励
        if (trustReward > 0) {
            lia.addTrustLevel(trustReward);
            System.out.println(" - Lia信任度+" + trustReward + "(当前:" + lia.getTrustLevel() + "/100)");
        }
        // 道具奖励
        if (itemReward != null) {
            allen.addItem(itemReward);
            System.out.println(" - 获得道具:" + itemReward.getName());
        }
        // 标记任务完成
        this.isCompleted = true;
        allen.addCompletedSideQuest(this.questType);
    }

    // Getter
    public SideQuestType getQuestType() { return questType; }
    public boolean isCompleted() { return isCompleted; }
    public int getBaseScore() { return baseScore; }
}

/**
 * 支线1:治疗受伤的小鹿(Allen+Lia联动)
 */
class HealAnimalQuest extends SideQuest {
    // 支线专属属性
    private int healStep; // 治疗步骤(1-3)
    private boolean isItemUsedCorrectly; // 是否正确使用治疗道具

    public HealAnimalQuest() {
        super(SideQuestType.HEAL_ANIMAL);
        this.healStep = 1;
        this.isItemUsedCorrectly = false;
    }

    @Override
    protected void initQuestConfig() {
        // 1. 触发条件
        triggerConditions.put("mainQuest", "收集魔法花"); // 前置主线
        triggerConditions.put("trustLevel", 50); // Lia信任度≥50
        triggerConditions.put("item", "高级治疗药水"); // 需持有高级治疗药水
        // 2. 奖励配置
        this.baseScore = 20; // 基础计分20
        this.expReward = 30;
        this.goldReward = 20;
        this.trustReward = 15; // 核心奖励:信任度+15
        this.itemReward = new MagicFlower(); // 额外奖励:魔法花
    }

    @Override
    public boolean executeQuest(Allen allen, Lia lia) {
        System.out.println("\n🌿 启动支线任务:" + questType.getQuestName());
        System.out.println("📝 任务描述:在迷雾沼泽找到受伤的小鹿,与Lia配合完成治疗");

        // 支线流程:3步互动
        while (healStep <= 3) {
            switch (healStep) {
                case 1:
                    step1_FindDeer(allen);
                    break;
                case 2:
                    step2_UseItem(allen);
                    break;
                case 3:
                    step3_LiaHelp(allen, lia);
                    break;
            }
            healStep++;
        }

        // 检查任务完成状态
        if (isItemUsedCorrectly) {
            giveReward(allen, lia);
            System.out.println("🎉 完成支线任务:治疗受伤的小鹿!");
            return true;
        } else {
            System.out.println("❌ 支线任务失败:未正确使用治疗道具!");
            // 失败惩罚:少量扣分
            this.baseScore = -5;
            return false;
        }
    }

    // 步骤1:找到受伤的小鹿
    private void step1_FindDeer(Allen allen) {
        System.out.println("\n【步骤1/3】在沼泽中寻找小鹿...");
        System.out.println("👀 发现一只腿部受伤的小鹿,它很害怕!");
        System.out.println("📌 操作选择:1. 慢慢靠近 2. 直接上前");
        int choice = getValidChoice(1, 2);

        if (choice == 1) {
            System.out.println("✅ 你慢慢靠近,小鹿没有逃跑!");
        } else {
            System.out.println("⚠️ 小鹿受惊逃跑,你花费了更多时间找到它(无惩罚)");
        }
    }

    // 步骤2:使用治疗道具
    private void step2_UseItem(Allen allen) {
        System.out.println("\n【步骤2/3】选择道具治疗小鹿...");
        System.out.println("🎒 你的背包道具:1. 普通治疗药水 2. 高级治疗药水 3. 魔法花");
        int choice = getValidChoice(1, 3);

        if (choice == 2) {
            System.out.println("✅ 正确使用高级治疗药水!小鹿的伤口开始愈合");
            isItemUsedCorrectly = true;
            // 消耗道具
            allen.removeItem("高级治疗药水");
        } else {
            System.out.println("❌ 选择错误道具!普通药水无效,魔法花不适合治疗伤口");
            isItemUsedCorrectly = false;
        }
    }

    // 步骤3:Lia辅助治疗
    private void step3_LiaHelp(Allen allen, Lia lia) {
        System.out.println("\n【步骤3/3】Lia使用精灵魔法辅助治疗...");
        if (isItemUsedCorrectly) {
            System.out.println("🪄 Lia:我用精灵魔法帮小鹿恢复吧!");
            lia.addTrustLevel(5); // 临时信任度+5
            System.out.println("✅ 小鹿完全康复,向你点头致谢!");
        } else {
            System.out.println("🪄 Lia:道具用错了,我只能暂时稳住小鹿的伤势...");
        }
    }

    // 输入校验辅助方法
    private 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;
    }
}

/**
 * 支线2:老贤者的交易(解谜+资源交换)
 */
class SageTradingQuest extends SideQuest {
    // 支线专属属性
    private boolean isPuzzleSolved; // 是否解开交易谜题

    public SageTradingQuest() {
        super(SideQuestType.SAGE_TRADING);
        this.isPuzzleSolved = false;
    }

    @Override
    protected void initQuestConfig() {
        // 1. 触发条件
        triggerConditions.put("mainQuest", "挑战多波战斗"); // 前置主线
        triggerConditions.put("trustLevel", 60); // Lia信任度≥60
        // 2. 奖励配置
        this.baseScore = 25; // 基础计分25
        this.expReward = 40;
        this.goldReward = 50;
        this.trustReward = 10;
        this.itemReward = new AdvancedMagicScroll(); // 核心奖励:高级魔法卷轴
    }

    @Override
    public boolean executeQuest(Allen allen, Lia lia) {
        System.out.println("\n🧙 启动支线任务:" + questType.getQuestName());
        System.out.println("📝 任务描述:与黑暗洞穴的老贤者完成资源交换,解开交易谜题");

        // 步骤1:老贤者提出交易需求
        step1_TradingDemand(allen);

        // 步骤2:解开交易谜题
        if (step2_SolvePuzzle()) {
            isPuzzleSolved = true;
        }

        // 步骤3:完成交易
        if (isPuzzleSolved) {
            step3_CompleteTrade(allen);
            giveReward(allen, lia);
            System.out.println("🎉 完成支线任务:老贤者的交易!");
            return true;
        } else {
            System.out.println("❌ 支线任务失败:未解开交易谜题!");
            this.baseScore = -8;
            return false;
        }
    }

    // 步骤1:老贤者提出交易需求
    private void step1_TradingDemand(Allen allen) {
        System.out.println("\n【步骤1/3】与老贤者对话...");
        System.out.println("🗣️ 老贤者:我需要10个金币和1朵魔法花,换一个珍贵的魔法卷轴!");
        System.out.println("💰 你的当前金币:" + allen.getGold() + " | 魔法花:" + (allen.hasItem("魔法花") ? "有" : "无"));

        if (allen.getGold() >= 10 && allen.hasItem("魔法花")) {
            System.out.println("✅ 你满足交易的资源要求!");
        } else {
            System.out.println("⚠️ 你暂时缺少资源,但老贤者允许你先解谜再收集(任务可继续)");
        }
    }

    // 步骤2:解开交易谜题
    private boolean step2_SolvePuzzle() {
        System.out.println("\n【步骤2/3】解开老贤者的谜题...");
        System.out.println("🧩 谜题:魔法森林中,什么能治愈一切伤口?");
        System.out.println("选项:1. 金币 2. 魔法花 3. 信任 4. 泉水");

        int choice = getValidChoice(1, 4);
        if (choice == 4) {
            System.out.println("✅ 回答正确!老贤者对你的智慧表示赞赏!");
            return true;
        } else {
            System.out.println("❌ 回答错误!正确答案是:泉水");
            // 允许重试一次
            System.out.println("🔄 老贤者给你一次重试机会:");
            choice = getValidChoice(1, 4);
            if (choice == 4) {
                System.out.println("✅ 这次回答正确了!");
                return true;
            } else {
                System.out.println("❌ 重试失败,交易谜题未解开!");
                return false;
            }
        }
    }

    // 步骤3:完成交易
    private void step3_CompleteTrade(Allen allen) {
        System.out.println("\n【步骤3/3】完成交易...");
        // 扣除资源(若无则后续补扣)
        if (allen.getGold() >= 10) {
            allen.addGold(-10);
        }
        if (allen.hasItem("魔法花")) {
            allen.removeItem("魔法花");
        }
        System.out.println("✅ 交易完成!老贤者交给你高级魔法卷轴!");
    }

    // 输入校验辅助方法
    private 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;
    }
}

/**
 * 计分系统核心类:ScoreSystem
 * 负责计算总得分、行为分、结局分,驱动多结局判定
 */
class ScoreSystem {
    // 基础分(等级/主线)
    private int baseScore;
    // 行为分(支线/战斗/交互)
    private int behaviorScore;
    // Lia信任度加分
    private int trustScore;
    // 总得分
    private int totalScore;
    // 结局类型
    private EndingType endingType;

    // 结局枚举
    public enum EndingType {
        PERFECT("完美结局", "拯救森林+Lia成为终身伙伴", 90),
        GOOD("良好结局", "拯救森林但Lia离开", 60),
        BAD("普通结局", "森林恢复但留下隐患", 30);

        private final String endingName;
        private final String endingDesc;
        private final int minScore; // 触发最低分数

        EndingType(String name, String desc, int min) {
            this.endingName = name;
            this.endingDesc = desc;
            this.minScore = min;
        }

        public String getEndingName() { return endingName; }
        public String getEndingDesc() { return endingDesc; }
        public int getMinScore() { return minScore; }
    }

    public ScoreSystem() {
        this.baseScore = 0;
        this.behaviorScore = 0;
        this.trustScore = 0;
        this.totalScore = 0;
        this.endingType = EndingType.BAD;
    }

    /**
     * 计算基础分(等级+主线完成度)
     * @param allen 主角
     */
    public void calculateBaseScore(Allen allen) {
        // 1. 等级分:等级×5
        this.baseScore += allen.getLevel() * 5;
        // 2. 主线完成度分:完成1个主线+10
        this.baseScore += allen.getCompletedMainQuests().size() * 10;
        System.out.println("\n📊 基础分计算:");
        System.out.println(" - 等级分:" + allen.getLevel() + "×5 = " + (allen.getLevel() * 5));
        System.out.println(" - 主线分:" + allen.getCompletedMainQuests().size() + "×10 = " + (allen.getCompletedMainQuests().size() * 10));
        System.out.println(" - 基础分总计:" + this.baseScore);
    }

    /**
     * 计算行为分(支线+战斗+交互)
     * @param allen 主角
     * @param sideQuests 支线任务列表
     */
    public void calculateBehaviorScore(Allen allen, List<SideQuest> sideQuests) {
        // 1. 支线分:每个支线基础分累加
        for (SideQuest quest : sideQuests) {
            this.behaviorScore += quest.getBaseScore();
        }
        // 2. 战斗分:胜利场次×3(失败场次×-1)
        this.behaviorScore += allen.getWinBattleCount() * 3;
        this.behaviorScore += allen.getLoseBattleCount() * (-1);
        // 3. 交互分:Lia交互次数×2
        this.behaviorScore += allen.getLiaInteractCount() * 2;

        // 行为分保底0分
        this.behaviorScore = Math.max(this.behaviorScore, 0);

        System.out.println("\n📊 行为分计算:");
        System.out.println(" - 支线分:" + (this.behaviorScore - (allen.getWinBattleCount()*3 + allen.getLoseBattleCount()*(-1) + allen.getLiaInteractCount()*2)));
        System.out.println(" - 战斗分:" + (allen.getWinBattleCount()*3 + allen.getLoseBattleCount()*(-1)));
        System.out.println(" - 交互分:" + (allen.getLiaInteractCount()*2));
        System.out.println(" - 行为分总计:" + this.behaviorScore);
    }

    /**
     * 计算信任度加分
     * @param lia 盟友
     */
    public void calculateTrustScore(Lia lia) {
        // 信任度分:信任度值(100满)
        this.trustScore = lia.getTrustLevel();
        System.out.println("\n📊 信任度分:" + this.trustScore + "(Lia信任度:" + lia.getTrustLevel() + "/100)");
    }

    /**
     * 计算总得分并判定结局
     */
    public void calculateTotalScoreAndEnding() {
        this.totalScore = this.baseScore + this.behaviorScore + this.trustScore;
        System.out.println("\n🏆 最终计分:");
        System.out.println(" - 基础分:" + baseScore);
        System.out.println(" - 行为分:" + behaviorScore);
        System.out.println(" - 信任度分:" + trustScore);
        System.out.println(" - 总得分:" + totalScore + "/200");

        // 判定结局
        if (totalScore >= EndingType.PERFECT.getMinScore()) {
            this.endingType = EndingType.PERFECT;
        } else if (totalScore >= EndingType.GOOD.getMinScore()) {
            this.endingType = EndingType.GOOD;
        } else {
            this.endingType = EndingType.BAD;
        }
    }

    /**
     * 展示最终结局
     * @param allen 主角
     * @param lia 盟友
     */
    public void showEnding(Allen allen, Lia lia) {
        System.out.println("\n🎬 游戏结局展示:");
        System.out.println("=====================================");
        System.out.println("结局类型:" + endingType.getEndingName());
        System.out.println("结局描述:" + endingType.getEndingDesc());

        // 不同结局的专属剧情
        switch (endingType) {
            case PERFECT:
                showPerfectEnding(allen, lia);
                break;
            case GOOD:
                showGoodEnding(allen, lia);
                break;
            case BAD:
                showBadEnding(allen, lia);
                break;
        }
        System.out.println("=====================================");
    }

    // 完美结局剧情
    private void showPerfectEnding(Allen allen, Lia lia) {
        System.out.println("\n✨ 【完美结局】剧情:");
        System.out.println("🗣️ 老贤者:你不仅拯救了魔法森林,还赢得了莉娅完全的信任!");
        System.out.println("🗣️ Lia:艾伦,谢谢你!我愿意永远陪伴你,一起守护这片森林~");
        System.out.println("🏆 奖励:解锁「森林守护者」称号,Lia信任度永久100!");
        lia.setTrustLevel(100);
        allen.addTitle("森林守护者");
    }

    // 良好结局剧情
    private void showGoodEnding(Allen allen, Lia lia) {
        System.out.println("\n🌟 【良好结局】剧情:");
        System.out.println("🗣️ 老贤者:你成功净化了永恒之泉,森林恢复了和平!");
        System.out.println("🗣️ Lia:艾伦,我很感谢你,但我需要回到精灵村落履行职责...");
        System.out.println("🏆 奖励:解锁「森林勇士」称号,金币+500!");
        allen.addGold(500);
        allen.addTitle("森林勇士");
    }

    // 普通结局剧情
    private void showBadEnding(Allen allen, Lia lia) {
        System.out.println("\n⚠️ 【普通结局】剧情:");
        System.out.println("🗣️ 老贤者:你完成了基础的净化仪式,但森林的魔法核心仍有隐患...");
        System.out.println("🗣️ Lia:艾伦,我们还需要更努力才能完全守护森林...");
        System.out.println("🏆 奖励:解锁「森林冒险者」称号,经验+200!");
        allen.addExperience(200);
        allen.addTitle("森林冒险者");
    }

    // Getter
    public int getTotalScore() { return totalScore; }
    public EndingType getEndingType() { return endingType; }
}

// ========== 依赖类补充(保证代码可运行) ==========
/**
 * Allen类扩展(补充支线/计分相关属性)
 */
class Allen {
    // 基础属性
    private String name;
    private int level;
    private int experience;
    private int gold;
    private int hp;
    private int maxHp;
    // 任务相关
    private List<String> completedMainQuests;
    private Set<SideQuestType> completedSideQuests;
    // 道具相关
    private List<Item> backpack;
    // 战斗相关
    private int winBattleCount;
    private int loseBattleCount;
    // 交互相关
    private int liaInteractCount;
    // 称号
    private List<String> titles;

    public Allen() {
        this.name = "艾伦";
        this.level = 1;
        this.experience = 0;
        this.gold = 0;
        this.hp = 100;
        this.maxHp = 100;
        this.completedMainQuests = new ArrayList<>();
        this.completedSideQuests = new HashSet<>();
        this.backpack = new ArrayList<>();
        this.winBattleCount = 0;
        this.loseBattleCount = 0;
        this.liaInteractCount = 0;
        this.titles = new ArrayList<>();
    }

    // 任务相关方法
    public boolean hasCompletedMainQuest(String questName) {
        return completedMainQuests.contains(questName);
    }

    public void addCompletedMainQuest(String questName) {
        if (!completedMainQuests.contains(questName)) {
            completedMainQuests.add(questName);
        }
    }

    public void addCompletedSideQuest(SideQuestType questType) {
        completedSideQuests.add(questType);
    }

    public List<String> getCompletedMainQuests() { return completedMainQuests; }

    // 道具相关方法
    public boolean hasItem(String itemName) {
        for (Item item : backpack) {
            if (item.getName().equals(itemName)) {
                return true;
            }
        }
        return false;
    }

    public void addItem(Item item) {
        backpack.add(item);
    }

    public void removeItem(String itemName) {
        backpack.removeIf(item -> item.getName().equals(itemName));
    }

    // 战斗相关方法
    public void addWinBattleCount() { winBattleCount++; }
    public void addLoseBattleCount() { loseBattleCount++; }
    public int getWinBattleCount() { return winBattleCount; }
    public int getLoseBattleCount() { return loseBattleCount; }

    // 交互相关方法
    public void addLiaInteractCount() { liaInteractCount++; }
    public int getLiaInteractCount() { return liaInteractCount; }

    // 基础属性方法
    public void addExperience(int exp) {
        this.experience += exp;
        // 升级逻辑
        while (this.experience >= 100) {
            this.level++;
            this.experience -= 100;
            this.maxHp += 10;
            this.hp = maxHp;
            System.out.println("🎉 " + name + "升级到" + level + "级!");
        }
    }

    public void addGold(int amount) {
        this.gold = Math.max(this.gold + amount, 0);
    }

    // 称号相关
    public void addTitle(String title) {
        titles.add(title);
    }

    // Getter
    public String getName() { return name; }
    public int getLevel() { return level; }
    public int getGold() { return gold; }
    public int getHp() { return hp; }
    public int getMaxHp() { return maxHp; }
    public List<String> getTitles() { return titles; }
}

/**
 * Lia类扩展(补充信任度相关)
 */
class Lia {
    private String name;
    private int trustLevel;
    private int maxTrustLevel;
    private boolean isUnlocked;

    public Lia() {
        this.name = "莉娅";
        this.trustLevel = 0;
        this.maxTrustLevel = 100;
        this.isUnlocked = false;
    }

    public void addTrustLevel(int amount) {
        this.trustLevel = Math.min(this.trustLevel + amount, maxTrustLevel);
        this.trustLevel = Math.max(this.trustLevel, 0);
    }

    // Getter/Setter
    public String getName() { return name; }
    public int getTrustLevel() { return trustLevel; }
    public void setTrustLevel(int level) { this.trustLevel = Math.min(level, maxTrustLevel); }
    public boolean isUnlocked() { return isUnlocked; }
    public void setUnlocked(boolean unlocked) { this.isUnlocked = unlocked; }
}

/**
 * 道具基类
 */
abstract class Item {
    protected String name;
    protected String desc;

    public Item(String name, String desc) {
        this.name = name;
        this.desc = desc;
    }

    public String getName() { return name; }
    public String getDesc() { return desc; }
}

/**
 * 具体道具类
 */
class AdvancedHealPotion extends Item {
    public AdvancedHealPotion() {
        super("高级治疗药水", "恢复50点HP,可用于治疗受伤的动物");
    }
}

class MagicFlower extends Item {
    public MagicFlower() {
        super("魔法花", "提升Lia信任度20点,老贤者交易的核心道具");
    }
}

class AdvancedMagicScroll extends Item {
    public AdvancedMagicScroll() {
        super("高级魔法卷轴", "提升攻击力20点,BOSS战必备道具");
    }
}

// ========== 测试类:支线任务+计分系统完整流程 ==========
public class SideQuestAndScoreSystemTest {
    public static void main(String[] args) {
        // 1. 初始化角色
        Allen allen = new Allen();
        Lia lia = new Lia();
        lia.setUnlocked(true);
        lia.addTrustLevel(60); // 初始信任度60

        // 2. 初始化Allen基础状态
        allen.addGold(50); // 初始金币50
        allen.addItem(new AdvancedHealPotion()); // 高级治疗药水
        allen.addItem(new MagicFlower()); // 魔法花
        allen.addCompletedMainQuest("收集魔法花"); // 完成前置主线
        allen.addCompletedMainQuest("挑战多波战斗");
        allen.addWinBattleCount();
        allen.addWinBattleCount(); // 胜利2场
        allen.addLiaInteractCount();
        allen.addLiaInteractCount();
        allen.addLiaInteractCount(); // 与Lia交互3次

        // 3. 初始化支线任务
        List<SideQuest> sideQuests = new ArrayList<>();
        HealAnimalQuest healQuest = new HealAnimalQuest();
        SageTradingQuest tradingQuest = new SageTradingQuest();
        sideQuests.add(healQuest);
        sideQuests.add(tradingQuest);

        // 4. 执行支线任务
        System.out.println("========== 执行支线任务 ==========");
        if (healQuest.checkTriggerCondition(allen, lia)) {
            healQuest.executeQuest(allen, lia);
        }

        if (tradingQuest.checkTriggerCondition(allen, lia)) {
            tradingQuest.executeQuest(allen, lia);
        }

        // 5. 初始化计分系统并计算得分
        System.out.println("\n========== 计分系统计算 ==========");
        ScoreSystem scoreSystem = new ScoreSystem();
        scoreSystem.calculateBaseScore(allen);
        scoreSystem.calculateBehaviorScore(allen, sideQuests);
        scoreSystem.calculateTrustScore(lia);
        scoreSystem.calculateTotalScoreAndEnding();

        // 6. 展示最终结局
        System.out.println("\n========== 最终结局 ==========");
        scoreSystem.showEnding(allen, lia);
    }
}

2.2 关键知识点讲解💡

(1)支线任务的核心设计架构

SideQuest抽象类
通用属性:类型/完成状态/触发条件/奖励
通用方法:条件校验/奖励发放
抽象方法:配置初始化/任务执行
HealAnimalQuest实现
SageTradingQuest实现
触发条件:主线+信任度+道具
任务流程:找小鹿→用道具→Lia辅助
奖励:信任度+15+魔法花
触发条件:主线+信任度
任务流程:交易需求→解谜→完成交易
奖励:高级魔法卷轴+信任度+10

  • 抽象封装:SideQuest抽象类封装支线通用逻辑(条件校验、奖励发放),子类仅实现专属配置和流程;
  • 状态驱动:支线触发绑定「主线进度+Lia信任度+道具」多维度状态,保证任务推进的逻辑性;
  • 流程化设计:每个支线拆分为固定步骤(如治疗动物拆分为3步),降低玩家操作复杂度;
  • 奖惩分明:完成支线获得加分和奖励,失败则少量扣分,影响最终计分。

👉 新手重点:支线任务设计要遵循「场景绑定+状态触发+流程化+奖惩分明」原则,既保证与主线的联动,又有独立的玩法价值

(2)计分系统的核心算法

计分系统采用「三维计分模型」,总得分=基础分+行为分+信任度分,不同维度的计分规则如下:

计分维度 计算规则 权重说明
基础分 等级×5 + 主线完成数×10 核心基础分,保证主线推进的价值
行为分 支线分+战斗分+交互分 • 支线分:每个支线基础分累加(完成+20/25,失败-5/-8) • 战斗分:胜利×3 + 失败×(-1) • 交互分:Lia交互次数×2 拓展分,体现玩家的操作选择
信任度分 Lia信任度值(0-100) 关键加分项,直接影响完美结局触发

核心代码示例:

java 复制代码
// 总得分计算
this.totalScore = this.baseScore + this.behaviorScore + this.trustScore;

// 结局判定
if (totalScore >= 90) {
    this.endingType = EndingType.PERFECT; // 完美结局
} else if (totalScore >= 60) {
    this.endingType = EndingType.GOOD; // 良好结局
} else {
    this.endingType = EndingType.BAD; // 普通结局
}

👉 新手重点:计分系统的核心是「多维度加权+阈值判定」,通过不同维度的分数累加,实现结局的差异化触发

🧪 三、调试示例:支线任务+计分系统完整流程

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

复制代码
========== 执行支线任务 ==========
✅ 该支线已完成!

🧙 启动支线任务:老贤者的交易
📝 任务描述:与黑暗洞穴的老贤者完成资源交换,解开交易谜题

【步骤1/3】与老贤者对话...
🗣️ 老贤者:我需要10个金币和1朵魔法花,换一个珍贵的魔法卷轴!
💰 你的当前金币:50 | 魔法花:有
✅ 你满足交易的资源要求!

【步骤2/3】解开老贤者的谜题...
🧩 谜题:魔法森林中,什么能治愈一切伤口?
选项:1. 金币 2. 魔法花 3. 信任 4. 泉水
输入数字选择:4
✅ 回答正确!老贤者对你的智慧表示赞赏!

【步骤3/3】完成交易...
✅ 交易完成!老贤者交给你高级魔法卷轴!

🏆 支线任务奖励发放:
 - 经验+40 | 金币+50
 - Lia信任度+10(当前:70/100)
 - 获得道具:高级魔法卷轴
🎉 完成支线任务:老贤者的交易!

========== 计分系统计算 ==========

📊 基础分计算:
 - 等级分:1×5 = 5
 - 主线分:2×10 = 20
 - 基础分总计:25

📊 行为分计算:
 - 支线分:45
 - 战斗分:6
 - 交互分:6
 - 行为分总计:57

📊 信任度分:70(Lia信任度:70/100)

🏆 最终计分:
 - 基础分:25
 - 行为分:57
 - 信任度分:70
 - 总得分:152/200

========== 最终结局 ==========

🎬 游戏结局展示:
=====================================
结局类型:完美结局
结局描述:拯救森林+Lia成为终身伙伴

✨ 【完美结局】剧情:
🗣️ 老贤者:你不仅拯救了魔法森林,还赢得了莉娅完全的信任!
🗣️ Lia:艾伦,谢谢你!我愿意永远陪伴你,一起守护这片森林~
🏆 奖励:解锁「森林守护者」称号,Lia信任度永久100!
=====================================

👉 结论:支线任务的触发条件、执行流程、奖励发放均正常生效,计分系统的三维计分模型计算准确,多结局判定逻辑符合预期!

🚨 四、新手常见错误与最佳实践

(1)新手常见错误

错误写法 正确写法 问题说明
支线任务无触发条件,进入场景即激活 绑定主线进度/角色状态/道具触发 支线与主线脱节,玩家体验混乱
所有支线奖励相同(仅金币/经验) 奖励差异化(互动类→信任度,交易类→道具) 奖励无吸引力,玩家缺乏完成动力
计分系统仅计算主线完成度 多维度计分(基础+行为+信任度) 结局判定单一,缺乏可玩性
结局仅文字描述,无专属剧情/奖励 不同结局对应专属剧情+称号/奖励 结局无差异化,玩家缺乏重玩动力

(2)最佳实践

  1. 支线差异化:不同类型支线(互动/交易/解谜)设计不同的触发条件和奖励,提升可玩性;
  2. 计分多维度:覆盖基础分、行为分、信任度分,让玩家的每一个选择都影响结局;
  3. 结局有价值:不同结局对应专属剧情、称号和奖励,鼓励玩家多次尝试;
  4. 状态联动化:支线完成度、Lia信任度、计分系统三者强联动,形成完整的玩法闭环;
  5. 容错设计:支线失败仅少量扣分,保证新手玩家也能体验完整结局。

📌 知识回顾

  1. 支线任务基于SideQuest抽象类设计,封装通用逻辑(条件校验/奖励发放),HealAnimalQuest和SageTradingQuest实现专属流程,触发条件绑定主线进度、Lia信任度和道具,奖励差异化设计;
  2. 计分系统采用「基础分+行为分+信任度分」三维模型,总得分阈值决定结局类型(完美/良好/普通);
  3. 支线任务完成度直接影响行为分,Lia信任度影响信任度分,两者共同决定最终结局,实现「选择影响结果」的核心玩法。

✍️ 写在最后

支线任务和计分系统是提升游戏可玩性的核心模块:支线任务通过「场景绑定+状态触发+流程化设计」丰富游戏内容,计分系统通过「多维度计分+阈值判定」实现多结局,两者结合让游戏从「线性推进」变为「选择驱动」。

对于Java新手来说,这部分的核心学习点是:如何通过抽象类封装通用逻辑,如何设计状态驱动的任务流程,如何通过多维度算法实现差异化的结局判定。掌握这些思路,你不仅能复刻这个游戏的支线和计分系统,还能将其应用到其他需要「任务+计分+多结局」的项目中。

下一篇我们将讲解项目的最后一个模块------拓展优化(作弊码/新角色/代码重构),带你完成从「功能实现」到「项目优化」的最后一步!

相关推荐
SuniaWang1 小时前
Spring AI 2.x 全面指南:架构升级、工具调用、多模型生态与实战示例
java·人工智能·后端·学习·spring·框架
闻哥1 小时前
Elasticsearch查询优化实战:从原理到落地的全方位调优指南
java·大数据·elasticsearch·搜索引擎·面试·全文检索·springboot
夕除1 小时前
js-20
开发语言·javascript·windows
sheji34161 小时前
【开题答辩全过程】以 基于Java的甜品蛋糕网上商城的设计与实现为例,包含答辩的问题和答案
java·开发语言
智能零售小白白1 小时前
零售多门店库存调拨优化:需求预测与路径规划的技术实现
java·开发语言·零售
前路不黑暗@1 小时前
Java项目:Java脚手架项目的意义和环境搭建(一)
java·开发语言·spring boot·学习·spring cloud·maven·idea
光泽雨2 小时前
C#库文件调用逻辑
开发语言·c#
C++ 老炮儿的技术栈2 小时前
万物皆文件:Linux 抽象哲学的开发之美
c语言·开发语言·c++·qt·算法
Seven972 小时前
LockSupport深度解析:线程阻塞与唤醒的底层实现原理
java