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

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

【魔法森林冒险】13/14 支线任务 & 计分系统:丰富性与结局🎯
📝 文章摘要
| 内容维度 | 详情说明 |
|---|---|
| 核心摘要 | 本文是「魔法森林冒险」Java项目系列第十三篇,聚焦游戏的「可玩性拓展层」------支线任务与计分系统。从治疗动物、老贤者交易两大核心支线的设计逻辑(触发条件/任务流程/奖励机制),到ScoreSystem计分系统的核心算法(基础分/行为分/结局分),再到多结局判定规则(Allen等级/Lia信任度/任务完成度联动),带你吃透如何通过支线任务丰富游戏内容、通过计分系统实现多结局的核心设计思路与代码实现。 |
| 阅读时长 | 20分钟 |
| 适合人群 | 1. Java新手:想掌握「多支线任务设计+计分算法+状态驱动多结局」的实战应用;2. 游戏开发入门者:想理解支线任务与主线的联动逻辑、计分系统的设计思路、多结局的触发规则;3. 项目复刻者:想复刻完整的支线任务体系、计分系统和多结局判定逻辑。 |
| 阅读重点 | 1. 两大核心支线任务(治疗动物/老贤者交易)的触发条件与完整流程;2. ScoreSystem计分系统的核心算法(基础分/行为分/结局分的计算规则);3. 多结局判定逻辑(3种结局的触发条件+结局展示);4. 支线与主线的联动设计(支线奖励影响主线结局)。 |
🎮 一、支线任务:游戏的「可玩性放大器」
支线任务是主线任务的补充,既能丰富游戏内容,又能通过专属奖励(如Lia信任度、稀有道具)影响主线结局。本项目设计了两大核心支线 ,覆盖「角色联动」和「交易解谜」两类经典玩法:
✅ 治疗动物支线 → Allen+Lia联动,考验道具使用与信任度交互,奖励高额信任度;
✅ 老贤者交易支线 → 解谜+资源交换,奖励稀有道具,影响最终计分;
支线任务的核心设计原则:
- 场景绑定:每个支线绑定专属场景(治疗动物→迷雾沼泽,交易支线→黑暗洞穴);
- 状态触发:需满足主线进度/角色状态(如Lia信任度≥50)才能激活;
- 奖励差异化:奖励与支线类型匹配(互动类→信任度,交易类→道具/金币);
- 结局关联:支线完成度直接影响计分系统和最终结局。
🔧 二、核心代码拆解(一):两大核心支线任务
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)最佳实践
- 支线差异化:不同类型支线(互动/交易/解谜)设计不同的触发条件和奖励,提升可玩性;
- 计分多维度:覆盖基础分、行为分、信任度分,让玩家的每一个选择都影响结局;
- 结局有价值:不同结局对应专属剧情、称号和奖励,鼓励玩家多次尝试;
- 状态联动化:支线完成度、Lia信任度、计分系统三者强联动,形成完整的玩法闭环;
- 容错设计:支线失败仅少量扣分,保证新手玩家也能体验完整结局。
📌 知识回顾
- 支线任务基于SideQuest抽象类设计,封装通用逻辑(条件校验/奖励发放),HealAnimalQuest和SageTradingQuest实现专属流程,触发条件绑定主线进度、Lia信任度和道具,奖励差异化设计;
- 计分系统采用「基础分+行为分+信任度分」三维模型,总得分阈值决定结局类型(完美/良好/普通);
- 支线任务完成度直接影响行为分,Lia信任度影响信任度分,两者共同决定最终结局,实现「选择影响结果」的核心玩法。
✍️ 写在最后
支线任务和计分系统是提升游戏可玩性的核心模块:支线任务通过「场景绑定+状态触发+流程化设计」丰富游戏内容,计分系统通过「多维度计分+阈值判定」实现多结局,两者结合让游戏从「线性推进」变为「选择驱动」。
对于Java新手来说,这部分的核心学习点是:如何通过抽象类封装通用逻辑,如何设计状态驱动的任务流程,如何通过多维度算法实现差异化的结局判定。掌握这些思路,你不仅能复刻这个游戏的支线和计分系统,还能将其应用到其他需要「任务+计分+多结局」的项目中。
下一篇我们将讲解项目的最后一个模块------拓展优化(作弊码/新角色/代码重构),带你完成从「功能实现」到「项目优化」的最后一步!