欢迎光临
我们一直在努力

【魔法森林冒险】12/14 场景系统:5大场景的任务串联

在这里插入图片描述

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

在这里插入图片描述

文章目录

  • 【魔法森林冒险】12/14 场景系统:5大场景的任务串联🌍
    • 📝 文章摘要
    • 🌲 一、场景系统核心设计:Region抽象类(所有场景的基石)
      • 1.1 Region抽象类完整代码
      • 1.2 核心设计思路💡
    • 🗺️ 二、5大核心场景的专属实现(从新手引导到最终结局)
      • 2.1 5大场景完整实现代码
      • 2.2 场景联动核心规则💡
    • 🧪 三、场景系统完整测试代码
    • 🚨 四、新手常见错误与最佳实践
      • 4.1 新手常见错误
      • 4.2 最佳实践
    • 📌 知识回顾
    • ✍️ 写在最后

在这里插入图片描述

【魔法森林冒险】12/14 场景系统:5大场景的任务串联🌍

📝 文章摘要

内容维度详情说明
核心摘要 本文是「魔法森林冒险」Java项目系列第十二篇,聚焦游戏的「空间叙事层」——场景系统。从Region抽象类的核心设计(通用属性/场景切换/任务触发),到5大核心场景(入口林地→迷雾沼泽→黑暗洞穴→精灵山谷→永恒之泉)的专属逻辑,再到场景与角色(Lia/老贤者)、任务的联动机制,带你吃透「场景驱动任务、角色赋能场景」的核心设计思路,掌握游戏场景系统的完整实现方案。
阅读时长 18分钟
适合人群 1. Java新手:想掌握「抽象类封装+状态驱动+场景联动」的实战应用;2. 游戏开发入门者:想理解场景系统的设计逻辑、场景切换与任务触发的联动机制;3. 项目复刻者:想复刻完整的多场景任务串联体系。
阅读重点 1. Region抽象类的核心设计(通用属性/方法封装、场景切换逻辑);2. 5大场景的专属实现(触发条件/任务绑定/角色交互);3. 场景与Lia/老贤者的联动触发时机;4. 场景切换的状态校验与过渡效果实现。

🌲 一、场景系统核心设计:Region抽象类(所有场景的基石)

场景是游戏的「空间容器」,所有角色交互、任务推进都依附于场景展开。本项目通过Region抽象类封装所有场景的通用逻辑,再通过子类实现5大场景的专属特性,既保证代码复用,又实现场景差异化。

1.1 Region抽象类完整代码

import java.util.*;

/**
* 场景类型枚举:定义5大核心场景
*/

enum RegionType {
ENTRY_FOREST("入口林地", "魔法森林的起点,新手引导场景", 1),
MIST_MARSH("迷雾沼泽", "布满迷雾的沼泽,治疗动物支线场景", 2),
DARK_CAVE("黑暗洞穴", "阴森的洞穴,老贤者交易支线+BOSS战场景", 3),
ELF_VALLEY("精灵山谷", "Lia的故乡,信任度提升交互场景", 4),
ETERNAL_SPRING("永恒之泉", "最终场景,主线任务完成+结局触发场景", 5);

private final String regionName; // 场景名称
private final String regionDesc; // 场景描述
private final int unlockLevel; // 解锁等级

RegionType(String name, String desc, int level) {
this.regionName = name;
this.regionDesc = desc;
this.unlockLevel = level;
}

// Getter
public String getRegionName() { return regionName; }
public String getRegionDesc() { return regionDesc; }
public int getUnlockLevel() { return unlockLevel; }
}

/**
* 场景基类(抽象):封装所有场景的通用属性与方法
*/

abstract class Region {
// 场景基础信息
protected RegionType regionType;
protected boolean isUnlocked; // 是否解锁
protected boolean isCurrent; // 是否为当前场景
protected String bgDesc; // 场景背景描述
// 场景关联
protected Region prevRegion; // 上一个场景
protected Region nextRegion; // 下一个场景
// 任务绑定
protected List<String> bindMainQuests; // 绑定的主线任务
protected List<String> bindSideQuests; // 绑定的支线任务
// 角色交互
protected Map<String, Boolean> npcTriggered; // NPC是否已触发(Lia/老贤者)
// 状态管理
protected Scanner scanner;
protected static final String SCENE_SEPARATOR = "=====================================";

public Region(RegionType type) {
this.regionType = type;
this.isUnlocked = false;
this.isCurrent = false;
this.bgDesc = type.getRegionDesc();
this.prevRegion = null;
this.nextRegion = null;
this.bindMainQuests = new ArrayList<>();
this.bindSideQuests = new ArrayList<>();
this.npcTriggered = new HashMap<>();
this.scanner = new Scanner(System.in);
// 初始化NPC触发状态
initNpcTriggerStatus();
// 初始化场景配置(子类实现)
initRegionConfig();
}

/**
* 初始化NPC触发状态(Lia/老贤者)
*/

private void initNpcTriggerStatus() {
npcTriggered.put("Lia", false);
npcTriggered.put("OldSage", false);
}

/**
* 初始化场景专属配置(子类实现)
* – 绑定任务
* – 设置解锁条件
* – 自定义背景描述
*/

protected abstract void initRegionConfig();

/**
* 解锁场景(需满足等级条件)
* @param allenLevel Allen当前等级
* @return 是否解锁成功
*/

public boolean unlockRegion(int allenLevel) {
if (isUnlocked) {
System.out.println("✅ 【" + regionType.getRegionName() + "】已解锁!");
return true;
}
if (allenLevel >= regionType.getUnlockLevel()) {
this.isUnlocked = true;
System.out.println("🎉 解锁新场景:【" + regionType.getRegionName() + "】");
System.out.println("📝 场景描述:" + regionType.getRegionDesc());
return true;
} else {
System.out.println("❌ 解锁失败!【" + regionType.getRegionName() + "】需要等级≥" + regionType.getUnlockLevel() + "(当前等级:" + allenLevel + ")");
return false;
}
}

/**
* 进入场景(核心方法)
* @param allen 主角对象
* @param lia 盟友对象
* @param oldSage 老贤者对象
*/

public void enterRegion(Allen allen, Lia lia, OldSage oldSage) {
// 1. 基础校验
if (!isUnlocked) {
System.out.println("❌ 无法进入【" + regionType.getRegionName() + "】:场景未解锁!");
return;
}

// 2. 切换当前场景状态
if (this.isCurrent) {
System.out.println("\\n🔄 你已在【" + regionType.getRegionName() + "】中");
} else {
// 取消上一个场景的当前状态
if (this.prevRegion != null) {
this.prevRegion.setCurrent(false);
}
this.isCurrent = true;
// 场景进入动画/描述
showEnterAnimation();
}

// 3. 触发场景专属逻辑(子类实现)
triggerRegionLogic(allen, lia, oldSage);

// 4. 显示场景操作菜单
showRegionMenu(allen, lia, oldSage);
}

/**
* 场景进入动画/描述(增强沉浸感)
*/

protected void showEnterAnimation() {
System.out.println("\\n" + SCENE_SEPARATOR);
System.out.println("🏞️ 进入场景:【" + regionType.getRegionName() + "】");
System.out.println("🌿 " + bgDesc);
System.out.println(SCENE_SEPARATOR);
// 模拟加载延迟(增强体验)
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}

/**
* 触发场景专属逻辑(子类实现)
* – 任务触发
* – NPC交互
* – 场景事件
*/

protected abstract void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage);

/**
* 显示场景操作菜单
*/

protected void showRegionMenu(Allen allen, Lia lia, OldSage oldSage) {
while (this.isCurrent) {
System.out.println("\\n📋 【" + regionType.getRegionName() + "】操作菜单:");
System.out.println("1. 探索场景(触发交互/任务)");
System.out.println("2. 切换场景");
System.out.println("3. 查看场景信息");
System.out.println("4. 退出当前场景");

int choice = getValidChoice(1, 4);
switch (choice) {
case 1:
exploreRegion(allen, lia, oldSage);
break;
case 2:
switchRegion(allen, lia, oldSage);
break;
case 3:
showRegionInfo();
break;
case 4:
exitRegion();
break;
}
}
}

/**
* 探索场景(核心交互逻辑)
*/

protected abstract void exploreRegion(Allen allen, Lia lia, OldSage oldSage);

/**
* 切换场景
*/

protected void switchRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n🗺️ 可切换的场景:");
List<Region> availableRegions = getAvailableRegions(allen.getLevel());

if (availableRegions.isEmpty()) {
System.out.println("❌ 暂无可切换的场景!请先提升等级解锁新场景");
return;
}

// 显示可切换场景列表
for (int i = 0; i < availableRegions.size(); i++) {
Region r = availableRegions.get(i);
System.out.println((i+1) + ". " + r.getRegionType().getRegionName() + "(解锁等级:" + r.getRegionType().getUnlockLevel() + ")");
}

System.out.println("请选择要切换的场景(输入序号):");
int choice = getValidChoice(1, availableRegions.size());
Region targetRegion = availableRegions.get(choice–1);

// 执行场景切换
System.out.println("\\n🚶 正在前往【" + targetRegion.getRegionType().getRegionName() + "】…");
this.isCurrent = false;
targetRegion.enterRegion(allen, lia, oldSage);
}

/**
* 获取可切换的场景(根据等级解锁)
*/

protected List<Region> getAvailableRegions(int allenLevel) {
List<Region> regions = new ArrayList<>();
// 模拟场景列表(实际项目中可通过场景管理器获取)
regions.add(new EntryForestRegion(RegionType.ENTRY_FOREST));
regions.add(new MistMarshRegion(RegionType.MIST_MARSH));
regions.add(new DarkCaveRegion(RegionType.DARK_CAVE));
regions.add(new ElfValleyRegion(RegionType.ELF_VALLEY));
regions.add(new EternalSpringRegion(RegionType.ETERNAL_SPRING));

// 过滤已解锁的场景
List<Region> available = new ArrayList<>();
for (Region r : regions) {
if (r.getRegionType().getUnlockLevel() <= allenLevel && !r.isCurrent()) {
r.unlockRegion(allenLevel); // 自动解锁符合等级的场景
available.add(r);
}
}
return available;
}

/**
* 显示场景信息
*/

protected void showRegionInfo() {
System.out.println("\\n📖 【" + regionType.getRegionName() + "】详细信息:");
System.out.println("🔍 描述:" + regionType.getRegionDesc());
System.out.println("🔓 解锁等级:" + regionType.getUnlockLevel());
System.out.println("📌 绑定主线任务:" + (bindMainQuests.isEmpty() ? "无" : String.join(", ", bindMainQuests)));
System.out.println("📌 绑定支线任务:" + (bindSideQuests.isEmpty() ? "无" : String.join(", ", bindSideQuests)));
System.out.println("🤝 可交互NPC:" + getInteractableNpcs());
}

/**
* 获取可交互的NPC
*/

protected String getInteractableNpcs() {
List<String> npcs = new ArrayList<>();
if (npcTriggered.containsKey("Lia") && !npcTriggered.get("Lia")) {
npcs.add("Lia(莉娅)");
}
if (npcTriggered.containsKey("OldSage") && !npcTriggered.get("OldSage")) {
npcs.add("OldSage(老贤者)");
}
return npcs.isEmpty() ? "无" : String.join(", ", npcs);
}

/**
* 退出当前场景
*/

protected void exitRegion() {
System.out.println("\\n🚪 退出【" + regionType.getRegionName() + "】");
this.isCurrent = false;
// 返回上一个场景(若无则回到主菜单)
if (this.prevRegion != null) {
this.prevRegion.setCurrent(true);
System.out.println("🔙 回到上一个场景:【" + this.prevRegion.getRegionType().getRegionName() + "】");
} else {
System.out.println("🔙 回到游戏主菜单");
}
}

/**
* 输入校验辅助方法
*/

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

// Getter/Setter
public RegionType getRegionType() { return regionType; }
public boolean isUnlocked() { return isUnlocked; }
public void setUnlocked(boolean unlocked) { this.isUnlocked = unlocked; }
public boolean isCurrent() { return isCurrent; }
public void setCurrent(boolean current) { this.isCurrent = current; }
public void setPrevRegion(Region prev) { this.prevRegion = prev; }
public void setNextRegion(Region next) { this.nextRegion = next; }
}

1.2 核心设计思路💡

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

Region抽象类

通用属性:类型/解锁状态/场景关联/任务绑定

通用方法:解锁/进入/切换/探索/退出

抽象方法:场景配置/专属逻辑/探索交互

EntryForestRegion实现

MistMarshRegion实现

DarkCaveRegion实现

ElfValleyRegion实现

EternalSpringRegion实现

场景状态:解锁/当前/上一个/下一个

关联关系:任务绑定/NPC触发

场景生命周期:解锁→进入→探索→切换→退出

交互核心:探索场景触发NPC/任务

  • 抽象封装:将场景的通用逻辑(解锁、进入、切换、退出)封装在抽象类中,子类只需实现专属配置和交互逻辑;
  • 状态驱动:通过isUnlocked(解锁状态)、isCurrent(当前场景)等状态变量控制场景行为;
  • 任务绑定:每个场景绑定专属的主线/支线任务,进入场景自动校验任务触发条件;
  • NPC联动:记录NPC触发状态,保证每个NPC只在特定场景/时机触发一次,避免重复交互;
  • 等级解锁:场景按等级梯度解锁(1-5级),保证游戏节奏的合理性。

👉 新手重点:场景系统设计要遵循「抽象通用逻辑+差异化专属实现+状态驱动交互」的原则,让场景成为任务和角色的「载体」而非孤立的空间。

🗺️ 二、5大核心场景的专属实现(从新手引导到最终结局)

基于Region抽象类,我们实现5个核心场景的专属逻辑,每个场景都有独特的任务绑定、NPC交互和解锁条件,形成完整的游戏空间叙事链。

2.1 5大场景完整实现代码

/**
* 场景1:入口林地(新手引导场景)
*/

class EntryForestRegion extends Region {
public EntryForestRegion(RegionType type) {
super(type);
}

@Override
protected void initRegionConfig() {
// 绑定新手引导主线任务
this.bindMainQuests.add("新手引导:熟悉基本操作");
this.bindMainQuests.add("收集第一朵魔法花");
// 自定义背景描述
this.bgDesc = "阳光透过树叶洒下,脚下是松软的草地,远处传来精灵的歌声——这里是魔法森林的起点。";
// 初始解锁(新手场景)
this.isUnlocked = true;
}

@Override
protected void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage) {
// 新手引导触发(仅第一次进入)
if (allen.getLevel() == 1 && !npcTriggered.get("Lia")) {
System.out.println("\\n👋 你遇到了精灵少女Lia!");
System.out.println("🗣️ Lia:你好呀,勇敢的冒险者!我是莉娅,愿意陪你一起探索这片森林~");
lia.setUnlocked(true); // 解锁Lia
npcTriggered.put("Lia", true); // 标记Lia已触发
// 新手奖励
allen.addGold(10);
allen.addItem(new HealPotion());
System.out.println("🎁 Lia送给你10金币和1瓶治疗药水!");
}
}

@Override
protected void exploreRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n🌱 你在入口林地探索…");
System.out.println("👀 你发现了一朵闪闪发光的魔法花!");

System.out.println("📌 操作选择:1. 采摘魔法花 2. 继续探索 3. 与Lia对话");
int choice = getValidChoice(1, 3);

switch (choice) {
case 1:
// 收集魔法花(主线任务)
allen.addItem(new MagicFlower());
allen.addCompletedMainQuest("收集第一朵魔法花");
System.out.println("✅ 你采摘了魔法花!主线任务「收集第一朵魔法花」完成");
System.out.println("📈 经验+5,等级提升!");
allen.addExperience(5);
break;
case 2:
// 随机事件:遇到小动物
System.out.println("🐰 你遇到了一只迷路的小兔子,它给你指引了前往迷雾沼泽的方向");
// 解锁下一个场景的提示
System.out.println("💡 提示:等级达到2级可解锁「迷雾沼泽」场景!");
break;
case 3:
if (lia.isUnlocked()) {
System.out.println("\\n🗣️ Lia:入口林地很安全,但迷雾沼泽有很多危险,一定要小心哦~");
// 提升Lia信任度
lia.addTrustLevel(2);
System.out.println("💖 Lia信任度+2(当前:" + lia.getTrustLevel() + "/100)");
} else {
System.out.println("❌ Lia还未出现,无法对话!");
}
break;
}
}
}

/**
* 场景2:迷雾沼泽(治疗动物支线场景)
*/

class MistMarshRegion extends Region {
public MistMarshRegion(RegionType type) {
super(type);
}

@Override
protected void initRegionConfig() {
// 绑定治疗动物支线
this.bindSideQuests.add("治疗受伤的小鹿");
// 自定义背景描述
this.bgDesc = "浓雾笼罩着整片沼泽,脚下是湿滑的泥泞,空气中弥漫着水草和泥土的气息,偶尔传来动物的叫声。";
}

@Override
protected void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage) {
// 治疗动物支线触发(需完成前置主线+Lia信任度≥50)
if (allen.hasCompletedMainQuest("收集第一朵魔法花")
&& lia.getTrustLevel() >= 50
&& !allen.hasCompletedSideQuest("治疗受伤的小鹿")) {
System.out.println("\\n🦌 你听到了微弱的鹿鸣,似乎有动物受伤了!");
System.out.println("🗣️ Lia:那是小鹿的声音!我们快去看看,我能感知到它就在附近~");
// 触发支线任务
System.out.println("📌 触发支线任务:治疗受伤的小鹿");
}
}

@Override
protected void exploreRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n☁️ 你在迷雾沼泽探索…");

// 检查是否有治疗药水
boolean hasHealPotion = allen.hasItem("高级治疗药水");

System.out.println("📌 操作选择:");
System.out.println("1. 寻找受伤的小鹿(需要高级治疗药水)");
System.out.println("2. 清理沼泽中的藤蔓(获得经验)");
System.out.println("3. 与Lia一起驱散迷雾(提升信任度)");

int choice = getValidChoice(1, 3);
switch (choice) {
case 1:
if (hasHealPotion) {
System.out.println("✅ 你找到了受伤的小鹿,准备使用高级治疗药水治疗它…");
// 触发治疗动物支线执行
HealAnimalQuest quest = new HealAnimalQuest();
quest.executeQuest(allen, lia);
} else {
System.out.println("❌ 你没有高级治疗药水!无法治疗小鹿(可在入口林地购买)");
}
break;
case 2:
System.out.println("🌿 你清理了沼泽中的藤蔓,路径变得清晰了!");
allen.addExperience(8);
System.out.println("📈 经验+8");
break;
case 3:
System.out.println("🪄 Lia使用精灵魔法驱散了部分迷雾!");
lia.addTrustLevel(5);
allen.addExperience(3);
System.out.println("💖 Lia信任度+5 | 📈 经验+3");
break;
}
}
}

/**
* 场景3:黑暗洞穴(老贤者交易支线+BOSS战场景)
*/

class DarkCaveRegion extends Region {
public DarkCaveRegion(RegionType type) {
super(type);
}

@Override
protected void initRegionConfig() {
// 绑定主线+支线
this.bindMainQuests.add("挑战洞穴中的哥布林");
this.bindSideQuests.add("老贤者的交易");
// 自定义背景描述
this.bgDesc = "洞穴内漆黑一片,只有零星的荧光蘑菇提供微弱的光线,石壁上布满奇怪的符文,空气中透着寒意。";
}

@Override
protected void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage) {
// 老贤者触发(仅第一次进入)
if (!npcTriggered.get("OldSage")) {
System.out.println("\\n🧙 你遇到了隐居在洞穴中的老贤者!");
System.out.println("🗣️ 老贤者:年轻人,我在这里等待有缘人,如果你能解开我的谜题,我会给你珍贵的奖励~");
npcTriggered.put("OldSage", true);
}

// BOSS战触发(等级≥3)
if (allen.getLevel() >= 3 && !allen.hasCompletedMainQuest("挑战洞穴中的哥布林")) {
System.out.println("\\n⚠️ 警告!洞穴深处传来哥布林首领的咆哮声!");
System.out.println("🗣️ Lia:小心!那是哥布林首领,比普通哥布林强大得多!");
}
}

@Override
protected void exploreRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n🕳️ 你在黑暗洞穴探索…");

System.out.println("📌 操作选择:");
System.out.println("1. 与老贤者交易(触发支线任务)");
System.out.println("2. 挑战哥布林首领(主线任务,等级≥3)");
System.out.println("3. 收集荧光蘑菇(制作魔法道具)");

int choice = getValidChoice(1, 3);
switch (choice) {
case 1:
// 触发老贤者交易支线
SageTradingQuest quest = new SageTradingQuest();
if (quest.checkTriggerCondition(allen, lia)) {
quest.executeQuest(allen, lia);
}
break;
case 2:
if (allen.getLevel() >= 3) {
System.out.println("⚔️ 你向哥布林首领发起挑战!");
// 触发BOSS战
BattleSystem battle = new BattleSystem();
boolean win = battle.fightBoss(allen, lia, new GoblinKing());
if (win) {
allen.addCompletedMainQuest("挑战洞穴中的哥布林");
System.out.println("✅ 主线任务「挑战洞穴中的哥布林」完成!");
}
} else {
System.out.println("❌ 等级不足!需要等级≥3才能挑战哥布林首领(当前等级:" + allen.getLevel() + ")");
}
break;
case 3:
System.out.println("🍄 你收集了荧光蘑菇,可以制作魔法卷轴!");
allen.addItem(new MagicScroll());
System.out.println("🎒 获得道具:魔法卷轴");
break;
}
}
}

/**
* 场景4:精灵山谷(Lia信任度提升场景)
*/

class ElfValleyRegion extends Region {
public ElfValleyRegion(RegionType type) {
super(type);
}

@Override
protected void initRegionConfig() {
// 绑定信任度提升任务
this.bindMainQuests.add("提升Lia信任度至80");
// 自定义背景描述
this.bgDesc = "这里是精灵的故乡,五彩斑斓的花朵遍地开放,溪水叮咚作响,空气中充满纯净的魔法能量。";
}

@Override
protected void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage) {
// Lia信任度满值触发特殊对话
if (lia.getTrustLevel() >= 80) {
System.out.println("\\n💖 Lia对你完全信任了!");
System.out.println("🗣️ Lia:谢谢你一直陪伴我,艾伦!这里是我的故乡,我愿与你分享精灵的祝福~");
allen.addCompletedMainQuest("提升Lia信任度至80");
// 永久提升Allen属性
allen.addMaxHp(10);
allen.addAttackPower(3);
System.out.println("🏆 奖励:最大HP+10,攻击力+3!");
}
}

@Override
protected void exploreRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n✨ 你在精灵山谷探索…");

System.out.println("📌 操作选择:");
System.out.println("1. 与Lia一起采摘精灵浆果(提升信任度)");
System.out.println("2. 学习精灵魔法(解锁新技能)");
System.out.println("3. 净化山谷中的黑暗能量(获得大量经验)");

int choice = getValidChoice(1, 3);
switch (choice) {
case 1:
System.out.println("🍓 你与Lia一起采摘精灵浆果,她非常开心!");
lia.addTrustLevel(10);
System.out.println("💖 Lia信任度+10(当前:" + lia.getTrustLevel() + "/100)");
break;
case 2:
System.out.println("🧙 你向精灵长老学习了基础魔法,解锁新技能!");
allen.unlockSkill("精灵祝福");
System.out.println("🔓 解锁技能:精灵祝福(战斗中恢复HP)");
break;
case 3:
System.out.println("✨ 你净化了山谷中的黑暗能量,魔法森林的能量变得更纯净了!");
allen.addExperience(20);
System.out.println("📈 经验+20");
break;
}
}
}

/**
* 场景5:永恒之泉(最终场景)
*/

class EternalSpringRegion extends Region {
public EternalSpringRegion(RegionType type) {
super(type);
}

@Override
protected void initRegionConfig() {
// 绑定最终主线任务
this.bindMainQuests.add("净化永恒之泉");
// 自定义背景描述
this.bgDesc = "泉水泛着金色的光芒,这是魔法森林的生命之源,也是最终决战的场地——树灵就盘踞在这里。";
}

@Override
protected void triggerRegionLogic(Allen allen, Lia lia, OldSage oldSage) {
// 最终BOSS战触发(需完成所有前置主线)
List<String> requiredQuests = Arrays.asList("收集第一朵魔法花", "挑战洞穴中的哥布林", "提升Lia信任度至80");
boolean allCompleted = true;
for (String quest : requiredQuests) {
if (!allen.hasCompletedMainQuest(quest)) {
allCompleted = false;
break;
}
}

if (allCompleted) {
System.out.println("\\n🌊 你来到了永恒之泉,树灵出现了!");
System.out.println("🗣️ 老贤者:这是最后的考验!净化树灵,拯救魔法森林!");
System.out.println("🗣️ Lia:艾伦,我会全力帮助你!");
// 触发最终BOSS战
BattleSystem finalBattle = new BattleSystem();
boolean win = finalBattle.fightFinalBoss(allen, lia, new TreeSpirit());
if (win) {
allen.addCompletedMainQuest("净化永恒之泉");
System.out.println("🎉 恭喜!你净化了永恒之泉,拯救了魔法森林!");
}
} else {
System.out.println("\\n❌ 无法触发最终决战!请先完成所有前置主线任务");
}
}

@Override
protected void exploreRegion(Allen allen, Lia lia, OldSage oldSage) {
System.out.println("\\n💧 你在永恒之泉探索…");

if (allen.hasCompletedMainQuest("净化永恒之泉")) {
System.out.println("✨ 永恒之泉恢复了纯净,魔法森林重新焕发生机!");
System.out.println("🎁 你获得了「森林守护者」称号!");
allen.addTitle("森林守护者");
} else {
System.out.println("⚠️ 永恒之泉被黑暗能量污染,树灵的力量正在增强!");
System.out.println("💡 提示:完成所有前置主线任务后可挑战树灵,净化泉水!");
}
}
}

2.2 场景联动核心规则💡

场景名称解锁等级核心绑定任务关键NPC/交互场景特色
入口林地 1 收集第一朵魔法花 Lia首次触发、新手引导 新手场景,基础操作教学
迷雾沼泽 2 治疗受伤的小鹿(支线) Lia辅助治疗、动物交互 支线场景,信任度提升
黑暗洞穴 3 挑战哥布林首领(主线)老贤者的交易(支线) 老贤者触发、BOSS战 战斗场景,解谜+交易
精灵山谷 4 提升Lia信任度至80 Lia深度交互、魔法学习 角色养成场景
永恒之泉 5 净化永恒之泉(最终主线) 最终BOSS战、结局触发 结局场景,最终决战

👉 新手重点:5大场景形成「新手引导→支线探索→战斗解谜→角色养成→最终决战」的完整叙事链,每个场景都有明确的核心目标,且场景间通过等级/任务进度联动,保证游戏节奏的连贯性。

🧪 三、场景系统完整测试代码

// ========== 依赖类补充(保证代码可运行) ==========
/**
* Allen类(简化版,包含核心属性)
*/

class Allen {
private int level = 1;
private int experience = 0;
private int gold = 0;
private int maxHp = 100;
private int attackPower = 10;
private List<String> completedMainQuests = new ArrayList<>();
private List<String> completedSideQuests = new ArrayList<>();
private List<Item> backpack = new ArrayList<>();
private List<String> unlockedSkills = new ArrayList<>();
private List<String> titles = new ArrayList<>();

// 核心方法
public void addExperience(int exp) {
this.experience += exp;
if (this.experience >= 10) { // 简化升级逻辑
this.level++;
this.experience = 0;
System.out.println("🎉 升级到" + level + "级!");
}
}

public void addGold(int amount) { this.gold += amount; }
public void addItem(Item item) { this.backpack.add(item); }
public void addCompletedMainQuest(String quest) { this.completedMainQuests.add(quest); }
public void addCompletedSideQuest(String quest) { this.completedSideQuests.add(quest); }
public void unlockSkill(String skill) { this.unlockedSkills.add(skill); }
public void addTitle(String title) { this.titles.add(title); }
public void addMaxHp(int amount) { this.maxHp += amount; }
public void addAttackPower(int amount) { this.attackPower += amount; }

// Getter
public int getLevel() { return level; }
public boolean hasCompletedMainQuest(String quest) { return completedMainQuests.contains(quest); }
public boolean hasCompletedSideQuest(String quest) { return completedSideQuests.contains(quest); }
public boolean hasItem(String itemName) {
for (Item item : backpack) {
if (item.getName().equals(itemName)) return true;
}
return false;
}
public List<String> getTitles() { return titles; }
}

/**
* Lia类(简化版)
*/

class Lia {
private boolean isUnlocked = false;
private int trustLevel = 0;

public void addTrustLevel(int amount) { this.trustLevel = Math.min(this.trustLevel + amount, 100); }
public boolean isUnlocked() { return isUnlocked; }
public void setUnlocked(boolean unlocked) { this.isUnlocked = unlocked; }
public int getTrustLevel() { return trustLevel; }
}

/**
* 基础道具类
*/

class Item {
private String name;
public Item(String name) { this.name = name; }
public String getName() { return name; }
}

class HealPotion extends Item { public HealPotion() { super("高级治疗药水"); } }
class MagicFlower extends Item { public MagicFlower() { super("魔法花"); } }
class MagicScroll extends Item { public MagicScroll() { super("魔法卷轴"); } }

/**
* 老贤者类(简化版)
*/

class OldSage {}

/**
* 战斗系统(简化版)
*/

class BattleSystem {
public boolean fightBoss(Allen allen, Lia lia, Object boss) {
System.out.println("⚔️ 你击败了哥布林首领!");
allen.addExperience(15);
return true;
}
public boolean fightFinalBoss(Allen allen, Lia lia, Object boss) {
System.out.println("🏆 你击败了树灵!");
return true;
}
}

/**
* BOSS类(简化版)
*/

class GoblinKing {}
class TreeSpirit {}

/**
* 支线任务类(简化版)
*/

class HealAnimalQuest {
public void executeQuest(Allen allen, Lia lia) {
System.out.println("✅ 你治疗了受伤的小鹿,支线任务完成!");
allen.addCompletedSideQuest("治疗受伤的小鹿");
lia.addTrustLevel(15);
}
}

class SageTradingQuest {
public boolean checkTriggerCondition(Allen allen, Lia lia) { return true; }
public void executeQuest(Allen allen, Lia lia) {
System.out.println("✅ 你完成了与老贤者的交易,支线任务完成!");
allen.addCompletedSideQuest("老贤者的交易");
}
}

// ========== 场景系统测试主类 ==========
public class RegionSystemTest {
public static void main(String[] args) {
// 1. 初始化角色
Allen allen = new Allen();
Lia lia = new Lia();
OldSage oldSage = new OldSage();

// 2. 初始化场景链
Region entryForest = new EntryForestRegion(RegionType.ENTRY_FOREST);
Region mistMarsh = new MistMarshRegion(RegionType.MIST_MARSH);
Region darkCave = new DarkCaveRegion(RegionType.DARK_CAVE);
Region elfValley = new ElfValleyRegion(RegionType.ELF_VALLEY);
Region eternalSpring = new EternalSpringRegion(RegionType.ETERNAL_SPRING);

// 3. 设置场景关联(形成链条)
entryForest.setNextRegion(mistMarsh);
mistMarsh.setPrevRegion(entryForest);
mistMarsh.setNextRegion(darkCave);
darkCave.setPrevRegion(mistMarsh);
darkCave.setNextRegion(elfValley);
elfValley.setPrevRegion(darkCave);
elfValley.setNextRegion(eternalSpring);
eternalSpring.setPrevRegion(elfValley);

// 4. 启动游戏(从入口林地开始)
System.out.println("🎮 魔法森林冒险开始!");
entryForest.enterRegion(allen, lia, oldSage);
}
}

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

4.1 新手常见错误

错误写法正确写法问题说明
所有场景逻辑写在一个类中 抽象类+子类拆分,通用逻辑封装在抽象类 代码冗余,场景差异化难以实现
场景切换无等级/任务校验 按等级解锁场景,按任务进度触发核心逻辑 场景切换无门槛,游戏节奏混乱
NPC在所有场景都能触发 按场景绑定NPC,标记触发状态避免重复 NPC交互无逻辑,沉浸感差
场景切换无过渡效果 添加场景进入动画、加载延迟、描述文本 场景切换生硬,玩家体验差

4.2 最佳实践

  • 场景梯度解锁:按等级/任务进度梯度解锁场景,保证游戏节奏的循序渐进;
  • NPC场景绑定:每个核心NPC只在特定场景触发,且标记触发状态避免重复交互;
  • 任务场景联动:核心任务与场景强绑定,进入场景自动校验任务触发条件;
  • 沉浸感增强:添加场景描述、进入动画、音效提示(代码中可模拟),提升玩家体验;
  • 状态校验完备:场景切换、任务触发前做充分的状态校验,避免非法操作。
  • 📌 知识回顾

  • Region抽象类是场景系统的核心,封装了场景解锁、进入、切换、探索、退出等通用逻辑,子类只需实现专属配置和交互逻辑;
  • 5大场景按「入口林地→迷雾沼泽→黑暗洞穴→精灵山谷→永恒之泉」的顺序梯度解锁,形成「新手引导→支线探索→战斗解谜→角色养成→最终决战」的完整叙事链;
  • 每个场景绑定专属的主线/支线任务,关键NPC(Lia/老贤者)仅在特定场景触发,且标记触发状态避免重复交互;
  • 场景系统通过「等级解锁+任务绑定+NPC联动」实现与角色、任务的深度耦合,形成完整的游戏玩法闭环。
  • ✍️ 写在最后

    场景系统是游戏的「空间骨架」,所有角色交互、任务推进都依附于场景展开。本项目的场景设计核心在于「抽象封装通用逻辑,差异化实现专属特性,状态驱动交互行为」——既保证代码的复用性和可维护性,又通过场景梯度解锁、任务绑定、NPC联动实现了丰富的游戏体验。

    对于Java新手来说,这部分的核心学习点是:如何通过抽象类封装通用逻辑,如何设计状态驱动的交互系统,如何实现模块间(场景-角色-任务)的低耦合高内聚联动。掌握这些思路,你不仅能复刻这个游戏的场景系统,还能将其应用到其他需要「多场景+多任务+多角色」的项目中。

    下一篇我们将讲解支线任务与计分系统,带你完成游戏「可玩性拓展+结局判定」的核心模块!

    赞(0)
    未经允许不得转载:171主机测评 » 【魔法森林冒险】12/14 场景系统:5大场景的任务串联
    分享到: 更多 (0)

    评论 抢沙发

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