优化,增加设计文档

This commit is contained in:
2026-06-29 02:48:13 +08:00
parent fb2dbfca99
commit 32484e8cb8
5 changed files with 2868 additions and 24 deletions
@@ -0,0 +1,377 @@
# Enemy双重寻敌机制实现计划
## 需求总结
1. **规则一:视觉检测与追击**
- 怪物通过射线检测看到玩家(360°全向视野)
- 看到玩家后追击
- 玩家脱离视线3秒后停止追击
2. **规则二:铃铛响应**
- 玩家摇铃铛时,铃铛声波范围内的怪物获取铃铛位置
- 怪物追击到铃铛位置
- 追击过程中如果看到玩家,切换为追击玩家(执行规则一)
- 到达铃铛位置后,如果没有看到玩家,在周围巡逻一段时间
## 状态机设计
```
Idle(待机)
├─ 射线检测到玩家 → ChasingPlayer
└─ 收到铃铛信号 → ChasingBell
ChasingPlayer(追击玩家)
├─ 持续看到玩家 → 继续追击
├─ 玩家脱离视线 → 开始计时(3秒)
│ └─ 3秒内重新看到 → 继续追击
│ └─ 3秒后仍未看到 → Idle
└─ 收到铃铛信号 → ChasingBell(打断当前状态)
ChasingBell(追击铃铛)
├─ 追击过程中射线检测到玩家 → ChasingPlayer
├─ 到达铃铛位置 → PatrollingBell
└─ 超时(10秒未到达)→ Idle
PatrollingBell(铃铛位置巡逻)
├─ 巡逻过程中射线检测到玩家 → ChasingPlayer
└─ 巡逻时间结束(5秒)→ Idle
```
## 实现步骤
### 步骤1:修改EnemyAI.cs - 添加新状态和参数
**文件**: `Assets/enemy/EnemyAI.cs`
**新增状态**:
```csharp
private enum State
{
Idle,
ChasingPlayer, // 追击玩家
ChasingBell, // 追击铃铛
PatrollingBell // 铃铛位置巡逻
}
```
**新增参数**:
```csharp
[Header("视觉检测")]
[Tooltip("射线检测层(哪些物体会阻挡视线)")]
[SerializeField] private LayerMask obstacleLayers;
[Tooltip("射线起点偏移(避免从地面发射)")]
[SerializeField] private float rayOffsetY = 0.5f;
[Header("脱离计时")]
[Tooltip("玩家脱离视线后,继续追击的时间(秒)")]
[SerializeField] private float loseSightTime = 3f;
[Header("铃铛追击")]
[Tooltip("到达铃铛位置后的容差距离")]
[SerializeField] private float bellArriveDistance = 1f;
[Tooltip("追击铃铛的最大时间(超时则放弃)")]
[SerializeField] private float bellChaseTimeout = 10f;
[Header("铃铛巡逻")]
[Tooltip("到达铃铛位置后的巡逻时间")]
[SerializeField] private float bellPatrolTime = 5f;
[Tooltip("巡逻半径")]
[SerializeField] private float bellPatrolRadius = 3f;
```
**新增变量**:
```csharp
private float _loseSightTimer; // 脱离视线计时器
private Vector3 _bellTargetPosition; // 铃铛目标位置
private float _bellChaseTimer; // 铃铛追击计时器
private Vector3 _patrolCenter; // 巡逻中心点
private float _patrolTimer; // 巡逻计时器
private Vector3 _patrolTarget; // 当前巡逻目标点
```
### 步骤2:实现射线检测视线
**新增方法**:
```csharp
/// <summary>
/// 检测是否能看到玩家(射线检测)
/// </summary>
private bool CanSeePlayer()
{
if (playerTarget == null) return false;
// 射线起点(稍微抬高,避免从地面发射)
Vector3 rayStart = transform.position + Vector3.up * rayOffsetY;
Vector3 rayEnd = playerTarget.position + Vector3.up * rayOffsetY;
Vector3 dir = rayEnd - rayStart;
float dist = dir.magnitude;
// 发射射线,只检测障碍物层
if (Physics.Raycast(rayStart, dir.normalized, out RaycastHit hit, dist, obstacleLayers))
{
// 如果击中的是玩家,说明可以看到
return hit.transform == playerTarget;
}
return false;
}
```
### 步骤3:修改状态机逻辑
**Idle状态**:
```csharp
private void UpdateIdle()
{
// 检测是否看到玩家
if (CanSeePlayer())
{
_state = State.ChasingPlayer;
_loseSightTimer = 0f;
return;
}
}
```
**ChasingPlayer状态**:
```csharp
private void UpdateChasingPlayer()
{
// 检测是否看到玩家
if (CanSeePlayer())
{
_loseSightTimer = 0f; // 重置计时器
// 追击玩家
float dist = XZDistance(transform.position, playerTarget.position);
if (dist > stopDistance)
{
MoveToward(playerTarget.position, chaseSpeed);
}
}
else
{
// 玩家脱离视线,开始计时
_loseSightTimer += Time.deltaTime;
// 继续朝玩家最后已知位置移动
if (playerTarget != null)
{
float dist = XZDistance(transform.position, playerTarget.position);
if (dist > stopDistance)
{
MoveToward(playerTarget.position, chaseSpeed);
}
}
// 超过3秒,停止追击
if (_loseSightTimer >= loseSightTime)
{
_state = State.Idle;
}
}
}
```
**ChasingBell状态**:
```csharp
private void UpdateChasingBell()
{
// 追击过程中检测是否看到玩家
if (CanSeePlayer())
{
_state = State.ChasingPlayer;
_loseSightTimer = 0f;
return;
}
// 追击计时
_bellChaseTimer += Time.deltaTime;
if (_bellChaseTimer >= bellChaseTimeout)
{
_state = State.Idle;
return;
}
// 检测是否到达铃铛位置
float dist = XZDistance(transform.position, _bellTargetPosition);
if (dist <= bellArriveDistance)
{
// 到达铃铛位置,开始巡逻
_state = State.PatrollingBell;
_patrolCenter = _bellTargetPosition;
_patrolTimer = 0f;
PickNewPatrolPoint();
return;
}
// 朝铃铛位置移动
MoveToward(_bellTargetPosition, chaseSpeed);
}
```
**PatrollingBell状态**:
```csharp
private void UpdatePatrollingBell()
{
// 巡逻过程中检测是否看到玩家
if (CanSeePlayer())
{
_state = State.ChasingPlayer;
_loseSightTimer = 0f;
return;
}
// 巡逻计时
_patrolTimer += Time.deltaTime;
if (_patrolTimer >= bellPatrolTime)
{
_state = State.Idle;
return;
}
// 朝巡逻点移动
float dist = XZDistance(transform.position, _patrolTarget);
if (dist <= 0.5f)
{
// 到达巡逻点,选择新的巡逻点
PickNewPatrolPoint();
}
else
{
MoveToward(_patrolTarget, chaseSpeed * 0.7f); // 巡逻时速度稍慢
}
}
/// <summary>
/// 选择新的巡逻点
/// </summary>
private void PickNewPatrolPoint()
{
// 在巡逻中心周围随机选择一个点
Vector2 randomDir = Random.insideUnitCircle * bellPatrolRadius;
_patrolTarget = _patrolCenter + new Vector3(randomDir.x, 0f, randomDir.y);
}
```
### 步骤4:修改铃铛响应逻辑
**OnBell方法**:
```csharp
private void OnBell(Vector3 bellPos)
{
if (playerTarget == null) return;
// 只有在聆听范围内才响应
if (XZDistance(transform.position, bellPos) > listenRange) return;
// 设置铃铛目标位置
_bellTargetPosition = bellPos;
_bellChaseTimer = 0f;
// 切换到追击铃铛状态(可以打断任何状态)
_state = State.ChasingBell;
}
```
### 步骤5:更新状态机调用
**Update方法**:
```csharp
private void Update()
{
switch (_state)
{
case State.Idle: UpdateIdle(); break;
case State.ChasingPlayer: UpdateChasingPlayer(); break;
case State.ChasingBell: UpdateChasingBell(); break;
case State.PatrollingBell: UpdatePatrollingBell(); break;
}
}
```
### 步骤6:更新编辑器可视化
**OnDrawGizmos方法**:
```csharp
private void OnDrawGizmosSelected()
{
// 根据状态显示不同颜色
Color stateColor = Color.white;
switch (_state)
{
case State.Idle: stateColor = Color.gray; break;
case State.ChasingPlayer: stateColor = Color.red; break;
case State.ChasingBell: stateColor = Color.yellow; break;
case State.PatrollingBell: stateColor = Color.cyan; break;
}
// 绘制当前状态指示
Gizmos.color = stateColor;
Gizmos.DrawWireSphere(transform.position, 0.5f);
// 绘制铃铛目标(如果在追击铃铛)
if (_state == State.ChasingBell || _state == State.PatrollingBell)
{
Gizmos.color = Color.yellow;
Gizmos.DrawWireSphere(_bellTargetPosition, bellArriveDistance);
// 绘制到铃铛的连线
Gizmos.DrawLine(transform.position, _bellTargetPosition);
}
// 绘制巡逻范围(如果在巡逻)
if (_state == State.PatrollingBell)
{
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere(_patrolCenter, bellPatrolRadius);
// 绘制当前巡逻目标
Gizmos.color = Color.green;
Gizmos.DrawWireSphere(_patrolTarget, 0.3f);
}
}
```
## 配置参数建议
| 参数 | 建议值 | 说明 |
|-----|--------|------|
| `obstacleLayers` | Obstacle | 阻挡视线的物体层 |
| `rayOffsetY` | 0.5 | 射线起点高度 |
| `loseSightTime` | 3.0 | 脱离视线后继续追击时间 |
| `bellArriveDistance` | 1.0 | 到达铃铛位置的容差 |
| `bellChaseTimeout` | 10.0 | 追击铃铛最大时间 |
| `bellPatrolTime` | 5.0 | 铃铛位置巡逻时间 |
| `bellPatrolRadius` | 3.0 | 巡逻半径 |
## 测试要点
1. **视觉检测测试**
- 在Enemy和玩家之间放置障碍物,验证射线被阻挡
- 移除障碍物,验证能检测到玩家
2. **脱离视线测试**
- 玩家跑出Enemy视线,验证3秒后停止追击
- 3秒内重新出现,验证继续追击
3. **铃铛响应测试**
- 玩家摇铃铛,验证Enemy朝铃铛位置移动
- 铃铛追击过程中看到玩家,验证切换为追击玩家
4. **巡逻测试**
- 到达铃铛位置后,验证在周围巡逻
- 巡逻过程中看到玩家,验证切换为追击玩家
## 文件清单
- 修改: `Assets/enemy/EnemyAI.cs`
## 预计工作量
- 实现时间: 2-3小时
- 调试时间: 1-2小时
- 总计: 3-5小时
@@ -0,0 +1,476 @@
# 亡灵灯笼 - 游戏设计文档
## 🎮 游戏概述
**游戏名称**: 亡灵灯笼 (Soul Lantern)
**游戏类型**: 2.5D 冒险解谜 + 生存收集
**核心玩法**: 探索黑暗迷宫 → 收集亡灵 → 躲避怪物和陷阱 → 解救亡灵
**视觉风格**: 2.5D等距视角,黑暗氛围,灯笼光照效果
**目标平台**: PC (可扩展到移动端)
---
## 🎯 核心游戏循环
```
1. 探索阶段
- 玩家在黑暗迷宫中探索
- 灯笼提供有限视野
- 铃铛声会吸引怪物
2. 收集阶段
- 找到被困的亡灵
- 使用技能将亡灵收入灯笼
- 灯笼亮度和铃铛范围增加
3. 危险阶段
- 怪物被铃声吸引,开始追击
- 触发陷阱和机关
- 需要躲避或战斗
4. 逃脱阶段
- 找到出口或传送门
- 切换到下一张地图
- 保存进度
```
---
## 🕹️ 玩家系统
### 1. 灯笼系统 (Lantern System)
**核心道具**: 魔法灯笼
| 属性 | 初始值 | 升级方式 |
|-----|--------|---------|
| **照亮范围** | 5m | 收集亡灵后增加 |
| **铃铛范围** | 10m | 收集亡灵后增加 |
| **亡灵容量** | 3个 | 升级灯笼 |
| **特殊技能CD** | 10秒 | 升级技能 |
**功能**:
-**照明**: 提供周围视野(已实现LightMaskSystem
-**铃铛**: 按E释放声波(已实现EchoSystem
-**收集**: 靠近亡灵时自动收入灯笼
-**技能**: 按Q释放"灵魂冲击"(范围眩晕)
**视觉效果**:
```
灯笼亮度 = 基础亮度 + (亡灵数量 × 单个亡灵亮度)
视野半径 = 5m + (亡灵数量 × 2m)
铃铛半径 = 10m + (亡灵数量 × 3m)
```
### 2. 玩家属性
| 属性 | 说明 |
|-----|------|
| **生命值** | 3颗心(被怪物碰到扣1颗) |
| **移动速度** | 5单位/秒 |
| **闪避能力** | 空格键翻滚(短暂无敌) |
| **技能CD** | 10秒(可升级减少) |
### 3. 技能系统
#### 技能1: 灵魂冲击 (Soul Shock)
- **按键**: Q
- **CD**: 10秒
- **效果**: 以玩家为中心,释放灵魂波动
- 范围内怪物眩晕3秒
- 可以打断怪物攻击
- 可以触发陷阱(提前引爆)
- **范围**: 8m(随亡灵数量增加)
#### 技能2: 灵魂护盾 (Soul Shield) - 解锁
- **解锁条件**: 收集10个亡灵
- **按键**: 右键
- **CD**: 15秒
- **效果**: 生成护盾,抵挡1次伤害
#### 技能3: 灵魂传送 (Soul Teleport) - 解锁
- **解锁条件**: 收集20个亡灵
- **按键**: 双击空格
- **CD**: 20秒
- **效果**: 短距离传送(10m内)
---
## 👹 敌人系统
### 1. 怪物类型
基于已实现的 `EnemyAI.cs`,扩展以下怪物类型:
#### 游荡者 (Wanderer)
- **行为**: 在固定路径巡逻
- **视野**: 15m(已实现maxSightDistance
- **速度**: 3m/s
- **特点**: 被铃声吸引(已实现BellResponding
- **弱点**: 移动缓慢,容易躲避
#### 守卫者 (Guardian)
- **行为**: 站岗不动,看到玩家追击
- **视野**: 20m
- **速度**: 4m/s
- **特点**: 攻击范围广,伤害高
- **弱点**: 只能直线攻击,可以绕柱躲避
#### 猎手 (Hunter)
- **行为**: 快速追击,会预判玩家位置
- **视野**: 25m
- **速度**: 6m/s
- **特点**: 会呼叫其他怪物
- **弱点**: 血量低,可以被灵魂冲击击杀
#### Boss: 暗影领主 (Shadow Lord)
- **行为**: 多阶段战斗
- **视野**: 全图
- **特殊能力**:
- 阶段1: 召唤小怪
- 阶段2: 黑暗领域(缩小玩家视野)
- 阶段3: 灵魂锁链(减速玩家)
### 2. 怪物AI增强
基于现有 `EnemyAI.cs`,添加以下功能:
```csharp
// 新增状态
private enum State
{
Idle,
ChasingPlayer,
ChasingBell,
PatrollingBell,
Stunned, // 眩晕(灵魂冲击)
Searching, // 搜索玩家(丢失视线后)
Returning // 返回巡逻点
}
// 新增参数
[Header("搜索行为")]
[SerializeField] private float searchDuration = 5f; // 搜索时间
[SerializeField] private float returnDistance = 10f; // 返回距离
[Header("攻击行为")]
[SerializeField] private float attackRange = 1.5f; // 攻击范围
[SerializeField] private float attackCooldown = 2f; // 攻击CD
[SerializeField] private int damage = 1; // 伤害值
```
**新增行为**:
-**搜索**: 丢失玩家视线后,在附近搜索5秒
-**返回**: 搜索失败后,返回巡逻点
-**攻击**: 靠近玩家时发动攻击
-**眩晕**: 被灵魂冲击击中后眩晕3秒
---
## 🗺️ 关卡设计
### 1. 地图系统
**地图结构**: 多个迷宫地图,通过传送门切换
#### 地图1: 废弃墓穴 (新手教程)
- **大小**: 50x50m
- **特点**: 简单迷宫,少量怪物
- **亡灵数量**: 5个
- **陷阱**: 地刺(固定位置)
- **目标**: 教学基本操作
#### 地图2: 幽暗森林
- **大小**: 80x80m
- **特点**: 复杂迷宫,视野受限
- **亡灵数量**: 10个
- **陷阱**: 地刺 + 飞箭
- **新元素**: 可破坏的墙壁
#### 地图3: 地下神殿
- **大小**: 100x100m
- **特点**: 多层结构,机关谜题
- **亡灵数量**: 15个
- **陷阱**: 所有陷阱 + 移动平台
- **新元素**: 机关门(需要激活)
#### 地图4: 暗影领域 (Boss战)
- **大小**: 60x60m
- **特点**: 开阔场地,Boss战
- **亡灵数量**: 0(专注Boss
- **陷阱**: 无
- **目标**: 击败暗影领主
### 2. 陷阱系统
#### 地刺 (Ground Spikes)
```csharp
public class GroundSpikes : MonoBehaviour
{
[SerializeField] private float damage = 1f;
[SerializeField] private float triggerRange = 1f;
[SerializeField] private float cooldown = 3f;
// 触发方式: 玩家踩上
// 效果: 扣1颗心,短暂无敌
}
```
#### 飞箭 (Flying Arrow)
```csharp
public class FlyingArrow : MonoBehaviour
{
[SerializeField] private float speed = 10f;
[SerializeField] private float damage = 1f;
[SerializeField] private float lifetime = 5f;
// 触发方式: 玩家进入触发区域
// 效果: 从固定方向发射箭矢
}
```
#### 落石 (Falling Rock)
```csharp
public class FallingRock : MonoBehaviour
{
[SerializeField] private float warningTime = 1f;
[SerializeField] private float damage = 1f;
[SerializeField] private float radius = 2f;
// 触发方式: 玩家进入区域
// 效果: 警告1秒后落石,范围伤害
}
```
### 3. 亡灵系统
#### 亡灵类型
**普通亡灵**:
- **外观**: 半透明人形
- **行为**: 被困在笼子/结界中
- **收集**: 靠近后自动收入灯笼
- **效果**: 灯笼亮度+1,铃铛范围+2m
**特殊亡灵**:
- **战士亡灵**: 提供战斗技能
- **法师亡灵**: 提供魔法护盾
- **盗贼亡灵**: 提供传送技能
#### 亡灵数据结构
```csharp
[System.Serializable]
public class SoulData
{
public string soulName; // 亡灵名称
public SoulType soulType; // 类型: 普通/战士/法师/盗贼
public int level; // 等级
public float brightnessBonus; // 亮度加成
public float rangeBonus; // 范围加成
public string specialAbility; // 特殊能力
}
```
---
## 🎨 UI系统
### 1. HUD (抬头显示)
```
┌─────────────────────────────────────┐
│ ❤❤❤ 🕐 00:12:34 │
│ │
│ [游戏画面] │
│ │
│ 🔦 灯笼: ████░░ 4/6 亡灵 │
│ ⚡ 技能: 就绪 (10s CD) │
│ 🗺️ 地图: 废弃墓穴 │
└─────────────────────────────────────┘
```
### 2. 灯笼UI
- **图标**: 灯笼图标
- **进度条**: 显示当前亡灵数量/容量
- **亮度指示**: 动态光圈大小
### 3. 技能UI
- **图标**: 技能图标
- **CD指示**: 灰色覆盖层 + 倒计时数字
- **快捷键**: Q / 右键 / 双击空格
### 4. 地图UI
- **小地图**: 右上角显示已探索区域
- **任务标记**: 显示亡灵位置和出口
---
## 💾 存档系统
### 1. 存档数据
```csharp
[System.Serializable]
public class SaveData
{
public int currentMapIndex; // 当前地图索引
public Vector3 playerPosition; // 玩家位置
public int playerHealth; // 玩家生命
public List<SoulData> collectedSouls; // 收集的亡灵
public float lanternBrightness; // 灯笼亮度
public float bellRange; // 铃铛范围
public float skillCooldown; // 技能CD
public Dictionary<string, bool> mapProgress; // 地图进度
}
```
### 2. 存档点
- **存档水晶**: 在地图中分布
- **自动存档**: 到达新地图时
- **手动存档**: 在存档水晶处按F
---
## 🎵 音效系统
### 1. 环境音效
| 场景 | 音效 |
|-----|------|
| 墓穴 | 风声、滴水声、远处哀嚎 |
| 森林 | 树叶沙沙声、猫头鹰叫 |
| 神殿 | 回声、机关运转声 |
| Boss战 | 紧张BGM、Boss咆哮 |
### 2. 交互音效
| 行为 | 音效 |
|-----|------|
| 铃铛 | 清脆铃声(已实现) |
| 收集亡灵 | 灵魂吸收音 |
| 技能释放 | 灵魂爆发音 |
| 受伤 | 痛苦呻吟 |
| 陷阱触发 | 机械触发音 |
---
## 📊 游戏平衡
### 1. 难度曲线
```
地图1 (废弃墓穴):
- 怪物数量: 3
- 陷阱数量: 5
- 亡灵数量: 5
- 难度: ★☆☆☆☆
地图2 (幽暗森林):
- 怪物数量: 6
- 陷阱数量: 10
- 亡灵数量: 10
- 难度: ★★☆☆☆
地图3 (地下神殿):
- 怪物数量: 10
- 陷阱数量: 15
- 亡灵数量: 15
- 难度: ★★★☆☆
地图4 (暗影领域):
- 怪物数量: 1 (Boss)
- 陷阱数量: 0
- 亡灵数量: 0
- 难度: ★★★★★
```
### 2. 资源平衡
**灯笼容量**:
- 初始: 3个亡灵
- 地图1后: 6个亡灵
- 地图2后: 9个亡灵
- 地图3后: 12个亡灵
**技能CD**:
- 初始: 10秒
- 每收集5个亡灵: -1秒
- 最低: 5秒
---
## 🚀 开发优先级
### Phase 1: 核心玩法 (2周)
- ✅ 灯笼系统(照明+铃铛)- 已实现
- ✅ Enemy AI(视觉+铃声)- 已实现
- ⏳ 玩家移动和碰撞
- ⏳ 亡灵收集逻辑
### Phase 2: 战斗系统 (1周)
- ⏳ 灵魂冲击技能
- ⏳ 怪物攻击逻辑
- ⏳ 玩家受伤和无敌帧
### Phase 3: 关卡设计 (2周)
- ⏳ 地图1: 废弃墓穴
- ⏳ 陷阱系统(地刺、飞箭)
- ⏳ 亡灵分布
### Phase 4: UI和存档 (1周)
- ⏳ HUD系统
- ⏳ 存档功能
- ⏳ 地图切换
### Phase 5: 扩展内容 (2周)
- ⏳ 地图2-4
- ⏳ 更多怪物类型
- ⏳ Boss战
---
## 🎯 下一步行动
基于现有代码,建议按以下顺序开发:
1. **玩家控制器增强**
- 添加生命值系统
- 添加技能系统(灵魂冲击)
- 添加灯笼升级逻辑
2. **亡灵系统**
- 创建亡灵预制体
- 实现收集逻辑
- 实现灯笼亮度动态调整
3. **陷阱系统**
- 创建地刺预制体
- 创建飞箭预制体
- 实现陷阱触发逻辑
4. **地图系统**
- 创建地图1(废弃墓穴)
- 实现地图切换逻辑
- 添加传送门
5. **UI系统**
- 创建HUD
- 添加灯笼和技能UI
- 添加小地图
---
这个设计充分利用了你已经实现的功能:
- ✅ 黑暗遮罩系统 (LightMaskSystem)
- ✅ 回声系统 (EchoSystem)
- ✅ Enemy AI (EnemyAI.cs)
- ✅ Y-Sort排序
- ✅ 地面裁剪Shader
- ✅ 2.5D摄像机系统
需要我帮你实现哪个部分?
@@ -30,8 +30,8 @@ Material:
- _EchoIntensity: 0 - _EchoIntensity: 0
- _EchoRadius: 39.41617 - _EchoRadius: 39.41617
- _EchoWidth: 2.5 - _EchoWidth: 2.5
- _LightSoftness: 0.5 - _LightSoftness: 1
- _MinBrightness: 1 - _MinBrightness: 0
m_Colors: m_Colors:
- _DarknessColor: {r: 0.01, g: 0.01, b: 0.02, a: 1} - _DarknessColor: {r: 0.01, g: 0.01, b: 0.02, a: 1}
- _EchoCenter: {r: -2.4399998, g: -1.5000057, b: 0, a: 0} - _EchoCenter: {r: -2.4399998, g: -1.5000057, b: 0, a: 0}
File diff suppressed because it is too large Load Diff
+355
View File
@@ -0,0 +1,355 @@
# 唤魂灯笼 - 前置剧情
## 📖 背景故事
### 世界观设定
在一个古老的东方小镇,人们相信**生死之间只隔着一层薄雾**。
镇上有一座**百年祠堂**,祠堂深处供奉着一件神秘的器物——**唤魂灯笼**。
传说中,这盏灯笼是**阴阳两界的桥梁**,能够照亮亡者归途,但也可能唤醒不该唤醒的东西。
---
## 👤 主角设定
**姓名**: 林默(默认名,可自定义)
**年龄**: 17岁
**身份**: 祠堂守门人的孙子
**性格**: 好奇心强,不信鬼神,叛逆但善良
### 主角背景
林默从小跟着爷爷长大,爷爷是祠堂的守门人。爷爷从小就告诫他:
> "祠堂里的东西,看看就好,**绝对不能碰**。特别是那盏灯笼..."
每次提到灯笼,爷爷的眼神都会变得恐惧,仿佛想起了什么可怕的事情。
---
## 📜 剧情章节
### 第一章:禁忌的灯笼
#### 场景1:祠堂日常(开场)
**画面**:黄昏,古老的祠堂,香火缭绕
**爷爷**(慈祥但严肃):
> "小默,记住我说的话。祠堂里的东西都有灵性,特别是深处那盏灯笼..."
**林默**(不耐烦):
> "知道了知道了,不能碰嘛。都说了几百遍了。"
**爷爷**(叹气):
> "那灯笼...不是你想象的那样简单。它...它能听到**那边的声音**。"
**林默**(心里嘀咕):
> "又是这套说辞,什么那边的声音,封建迷信。"
---
#### 场景2:诡异的呼唤(夜晚)
**时间**:深夜,林默在自己的房间
**音效**:远处传来微弱的铃声,像是有人在摇铃
**林默**(惊醒):
> "什么声音?...好像是...铃声?"
**画面**:窗外,祠堂的方向,隐约看到微弱的蓝光
**林默**(内心独白):
> "这么晚了,谁会在祠堂?...那蓝光是什么?"
**铃声再次响起**,这次更清晰,仿佛在**呼唤**他
**林默**(起身):
> "不行,我得去看看..."
---
#### 场景3:禁忌的触碰
**画面**:林默偷偷进入祠堂,来到灯笼前
**灯笼特写**
- 古铜色的灯笼,散发着幽蓝微光
- 灯笼上刻着奇怪的符文
- 灯笼顶部有一个**精致的开关**,像是某种机关
**林默**(观察):
> "这就是那盏灯笼...真的有蓝光...是萤火虫吗?"
**音效**:铃声再次响起,这次就在灯笼里
**林默**(伸手):
> "只是看看...应该不会..."
**突然**,灯笼上的符文开始发光,铃声变得急促
**林默**(手颤抖):
> "怎么回事...我的手...不受控制..."
**画面**:林默的手不由自主地伸向开关
**爷爷的声音**(回忆):
> "绝对不能碰!特别是那个开关!"
**林默**(挣扎):
> "不...我不能..."
**但是**,铃声越来越响,仿佛在**哀求**,仿佛在**呼唤**
**林默**(内心):
> "是谁...在叫我?"
---
#### 场景4:开关按下
**画面**:慢动作,林默的手指触碰到开关
**音效**:清脆的"咔哒"声
**瞬间**
- 灯笼爆发出强烈的蓝光
- 整个祠堂开始震动
- 符文全部亮起,形成诡异的图案
- 林默被蓝光吞没
**林默**(惊恐):
> "不——!"
**画面**:白光闪过,祠堂空无一人,灯笼静静燃烧
---
### 第二章:亡者的世界
#### 场景5:醒来
**画面**:林默睁开眼睛,发现自己躺在一片荒芜的土地上
**环境**
- 天空是暗紫色的,没有太阳
- 四周是破败的建筑,像是废弃的小镇
- 空气中飘着淡淡的雾气
- 远处传来哀嚎声
**林默**(起身,环顾):
> "这是...哪里?我怎么会在这里?"
**低头一看**:唤魂灯笼就在身边,散发着微弱的光
**林默**(拿起灯笼):
> "灯笼...也跟着我来了?"
**突然**,灯笼里传出微弱的声音
**声音**(空灵,像是很多人叠加):
> "救...救救我们..."
**林默**(惊恐):
> "谁?!谁在说话?"
**声音**
> "我们...被困在这里...灯笼...能救我们..."
**林默**
> "你们是谁?这是哪里?"
**声音**
> "这里是**亡者的世界**...我们都是迷失的灵魂...只有灯笼能带我们出去..."
---
#### 场景6:第一个亡灵
**画面**:一个半透明的人影出现在林默面前
**亡灵**(老者,慈祥):
> "孩子...你不该来的..."
**林默**
> "老爷爷,你知道怎么出去吗?"
**亡灵**(叹气):
> "你按下了灯笼的开关,打开了**阴阳之门**。现在,你被困在**中间地带**了。"
**林默**
> "中间地带?"
**亡灵**
> "生死之间的缝隙。我们在这里徘徊了很久...无法安息,也无法回去。"
**林默**(看着灯笼):
> "那这个灯笼..."
**亡灵**
> "它是**引路之灯**。被你唤醒后,它能照亮我们的道路,也能...收集我们的灵魂。"
**林默**
> "收集灵魂?"
**亡灵**
> "把我们收入灯笼,带我们离开这里。灯笼会变得更亮,铃铛会传得更远..."
**林默**
> "但是...为什么要帮我?"
**亡灵**(微笑):
> "因为你是**被选中的人**。只有活人的手,才能拿起唤魂灯笼。"
---
#### 场景7:使命
**亡灵**(严肃):
> "孩子,听我说。这个世界很危险..."
**画面**:远处,黑影在游荡
**亡灵**
> "那些是**迷失者**,曾经也是灵魂,但已经失去了理智。它们会被铃声吸引,攻击一切活物。"
**林默**(握紧灯笼):
> "那我..."
**亡灵**
> "你有两个选择:
> 1. 找到**回去的门**,独自离开
> 2. 用灯笼**收集我们**,带我们一起走"
**林默**
> "收集你们...会怎样?"
**亡灵**
> "灯笼会更亮,你能看得更远。我们...也能安息。"
**林默**(坚定):
> "我带你们走。"
**亡灵**(感动):
> "谢谢你...但是记住,**不要滥用铃铛**。每次摇铃,都会吸引那些迷失者..."
**林默**
> "我明白了。"
**亡灵**(消散):
> "去吧...沿着灯笼的光...找到其他灵魂..."
---
#### 场景8:开始冒险
**画面**:林默提起灯笼,环顾四周
**灯笼**:发出温暖的蓝光,照亮周围5米的范围
**林默**(内心独白):
> "爷爷说得对...这灯笼真的能听到那边的声音。"
**林默**(看着灯笼):
> "既然我按下了开关...就要负责到底。"
**林默**(摇动灯笼):
> "叮铃——"
**音效**:清脆的铃声在空旷的世界中回荡
**画面**:远处,几个半透明的人影开始向林默移动
**林默**(微笑):
> "来吧...我带你们回家。"
**画面**:镜头拉远,林默提着灯笼,走向黑暗
**字幕**
> **唤魂灯笼**
>
> *每一个灵魂,都值得被照亮*
---
## 🎭 剧情要点总结
### 核心情感
1. **好奇心 vs 禁忌**:主角因为好奇心违背了爷爷的警告
2. **责任与救赎**:既然造成了后果,就要承担责任
3. **孤独与陪伴**:从独自冒险到带领一群灵魂
### 悬念设置
1. **爷爷的秘密**:爷爷为什么那么害怕灯笼?他过去经历过什么?
2. **被选中的含义**:为什么只有活人才能拿起灯笼?
3. **亡者的过去**:这些灵魂是怎么来到这里的?
### 后续伏笔
1. **爷爷的身影**:在后续地图中,可能会看到爷爷的年轻身影(回忆)
2. **灯笼的起源**:灯笼是怎么被创造的?为什么会有开关?
3. **回去的门**:真的存在回去的路吗?
---
## 🎬 过场动画建议
### 开场动画(30秒)
```
镜头1: 祠堂全景,黄昏,香火缭绕 (3秒)
镜头2: 爷爷和林默对话 (10秒)
镜头3: 夜晚,林默被铃声惊醒 (5秒)
镜头4: 林默进入祠堂,走向灯笼 (7秒)
镜头5: 特写:手触碰开关 (3秒)
镜头6: 蓝光爆发,林默消失 (2秒)
```
### 过渡动画(10秒)
```
白光闪过 → 林默睁开眼睛 → 发现自己在陌生世界 → 拿起灯笼
```
---
## 💡 Gameplay结合
### 剧情与玩法结合点
1. **第一次摇铃**:剧情后,教程提示玩家按E摇铃
2. **收集第一个亡灵**:剧情后,引导玩家走向第一个亡灵
3. **遇到第一个怪物**:教程提示躲避或使用道具
### 情感驱动
- **灯笼变亮**:每收集一个亡灵,灯笼变亮,给玩家成就感
- **亡灵对话**:收集亡灵后,可以听到他们的故事
- **爷爷的回忆**:在特定地点,触发爷爷的回忆片段
---
## 📝 开发备注
### 需要实现的剧情系统
1. **对话系统**:支持角色对话和选择
2. **过场动画**:关键剧情节点的动画演出
3. **回忆片段**:收集特定物品触发回忆
4. **亡灵档案**:记录收集到的亡灵故事
### 剧情触发点
- **场景1-4**:游戏开场自动触发
- **场景5-8**:进入亡者世界后触发
- **后续剧情**:通过收集亡灵和探索地图逐步解锁
---
*文档版本:1.0*
*最后更新:2026年*