欢迎光临
我们一直在努力

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

在这里插入图片描述

🏠个人主页:黎雁 🎬作者简介:C/C++/JAVA后端开发学习者 ❄️个人专栏:C语言、数据结构(C语言)、EasyX、JAVA、游戏、规划、程序人生 ✨ 从来绝巘须孤往,万里同尘即玉京

在这里插入图片描述

文章目录

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

在这里插入图片描述

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

📝 文章摘要

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

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

支线任务是主线任务的补充,既能丰富游戏内容,又能通过专属奖励(如Lia信任度、稀有道具)影响主线结局。本项目设计了两大核心支线,覆盖「角色联动」和「交易解谜」两类经典玩法: ✅ 治疗动物支线 → Allen+Lia联动,考验道具使用与信任度交互,奖励高额信任度; ✅ 老贤者交易支线 → 解谜+资源交换,奖励稀有道具,影响最终计分;

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

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

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

    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)支线任务的核心设计架构

    #mermaid-svg-i4Wg2WmMuU56g9Nc{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-i4Wg2WmMuU56g9Nc .error-icon{fill:#552222;}#mermaid-svg-i4Wg2WmMuU56g9Nc .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i4Wg2WmMuU56g9Nc .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .marker.cross{stroke:#333333;}#mermaid-svg-i4Wg2WmMuU56g9Nc svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i4Wg2WmMuU56g9Nc p{margin:0;}#mermaid-svg-i4Wg2WmMuU56g9Nc .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster-label text{fill:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster-label span{color:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster-label span p{background-color:transparent;}#mermaid-svg-i4Wg2WmMuU56g9Nc .label text,#mermaid-svg-i4Wg2WmMuU56g9Nc span{fill:#333;color:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .node rect,#mermaid-svg-i4Wg2WmMuU56g9Nc .node circle,#mermaid-svg-i4Wg2WmMuU56g9Nc .node ellipse,#mermaid-svg-i4Wg2WmMuU56g9Nc .node polygon,#mermaid-svg-i4Wg2WmMuU56g9Nc .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .rough-node .label text,#mermaid-svg-i4Wg2WmMuU56g9Nc .node .label text,#mermaid-svg-i4Wg2WmMuU56g9Nc .image-shape .label,#mermaid-svg-i4Wg2WmMuU56g9Nc .icon-shape .label{text-anchor:middle;}#mermaid-svg-i4Wg2WmMuU56g9Nc .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .rough-node .label,#mermaid-svg-i4Wg2WmMuU56g9Nc .node .label,#mermaid-svg-i4Wg2WmMuU56g9Nc .image-shape .label,#mermaid-svg-i4Wg2WmMuU56g9Nc .icon-shape .label{text-align:center;}#mermaid-svg-i4Wg2WmMuU56g9Nc .node.clickable{cursor:pointer;}#mermaid-svg-i4Wg2WmMuU56g9Nc .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .arrowheadPath{fill:#333333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i4Wg2WmMuU56g9Nc .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-i4Wg2WmMuU56g9Nc .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i4Wg2WmMuU56g9Nc .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster text{fill:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc .cluster span{color:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i4Wg2WmMuU56g9Nc .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-i4Wg2WmMuU56g9Nc rect.text{fill:none;stroke-width:0;}#mermaid-svg-i4Wg2WmMuU56g9Nc .icon-shape,#mermaid-svg-i4Wg2WmMuU56g9Nc .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i4Wg2WmMuU56g9Nc .icon-shape p,#mermaid-svg-i4Wg2WmMuU56g9Nc .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-i4Wg2WmMuU56g9Nc .icon-shape rect,#mermaid-svg-i4Wg2WmMuU56g9Nc .image-shape rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i4Wg2WmMuU56g9Nc .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-i4Wg2WmMuU56g9Nc .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-i4Wg2WmMuU56g9Nc :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

    SideQuest抽象类

    通用属性:类型/完成状态/触发条件/奖励

    通用方法:条件校验/奖励发放

    抽象方法:配置初始化/任务执行

    HealAnimalQuest实现

    SageTradingQuest实现

    触发条件:主线+信任度+道具

    任务流程:找小鹿→用道具→Lia辅助

    奖励:信任度+15+魔法花

    触发条件:主线+信任度

    任务流程:交易需求→解谜→完成交易

    奖励:高级魔法卷轴+信任度+10

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

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

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

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

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

    核心代码示例:

    // 总得分计算
    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)最佳实践

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

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

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

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

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

    赞(0)
    未经允许不得转载:171主机测评 » 【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址