Files
Echo/Assets/_Project/Docs/Interaction_条件交互与消耗型交互.md
T

119 lines
6.7 KiB
Markdown
Raw Normal View History

2026-07-08 19:53:15 +08:00
# 条件交互与消耗型交互(技术参考)
更多“条件/消耗/解锁/UI 提示/指向高亮”的统一说明见:
- [InteractionSystem_Technical_Reference.md](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Docs/InteractionSystem_Technical_Reference.md)
## 目的
在不改动现有 `IInteractable` 行为脚本(门/机关/拾取物等)的前提下,为交互调用链增加“资格校验 / 消耗 / 解锁”能力,并通过给场景物体挂载条件组件完成配置。
## 交互链路(当前项目实现)
- 玩家按下交互键后,`PlayerController.PerformInteract()`
- Raycast 命中交互层物体
- 收集命中物体与其父物体上的所有 `IInteractable`
- 在调用 `Interact()` 前,查找命中物体父级上的所有 `InteractConditionBehaviour` 并逐一 `CanInteract(...)`
- 任意条件失败:阻止交互,并输出失败原因
- 全部条件通过:依次调用 `IInteractable.Interact()`
- 交互成功后,逐一回调 `InteractConditionBehaviour.OnInteractSucceeded(...)`(用于消耗、解锁等)
相关代码入口:
- 玩家交互入口:[PlayerController.PerformInteract](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Player/PlayerController.cs#L367-L459)
- 条件基类:[InteractConditionBehaviour](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/Conditions/InteractConditionBehaviour.cs)
## 如何给门/机关配置条件
### 无条件交互(默认)
- 不挂任何 `InteractConditionBehaviour` 子类组件
- 玩家会直接调用目标上的 `IInteractable.Interact()`
### 单条件:需要某个物品(可选消耗/解锁)
挂载组件:[RequireItemsInteractCondition](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/Conditions/RequireItemsInteractCondition.cs)
- `mode = RequireAll`
- `requirements`:只填 1 条(`requiredItemId` + `requiredAmount`
- `consumeOnSuccess`:成功交互后扣除数量
- `unlockAfterSuccess`:成功一次后标记已解锁,后续无需再次校验/消耗
- `unlockState`:可选,绑定 [InteractUnlockState](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/InteractUnlockState.cs) 用于后续 UI/渲染读取解锁状态
- `failReason`:失败提示(可不填)
- `allowIfInventoryMissing`:背包系统缺失时是否仍放行(慎用)
### 多条件(AND):挂多个条件组件
- 同一个门/机关根节点上挂多个 `InteractConditionBehaviour` 子类
- 玩家侧按顺序逐个校验,任意失败都会阻止交互
示例:门需要钥匙 + 玩家饥饿值必须大于 10(后者可由你后续新增一个“玩家状态条件”组件实现)。
### 多道具条件(OR/AND):一个组件内表达
挂载组件:[RequireItemsInteractCondition](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/Conditions/RequireItemsInteractCondition.cs)
- `mode`
- `RequireAll`:所有条目都满足才通过(等价 AND)
- `RequireAny`:任意一个条目满足就通过(OR
- `requirements`:配置多个条目(`requiredItemId` + `requiredAmount`
- `consumeOnSuccess`
- `RequireAll`:依次扣除所有条目数量
- `RequireAny`:扣除“触发通过的那一条”的数量
- `unlockAfterSuccess`:同上
- `unlockState`:可选,绑定 `InteractUnlockState` 作为解锁状态源
### 解锁状态与外观切换(锁隐藏/电池显示)
挂载组件:[InteractUnlockState](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/InteractUnlockState.cs)
- `unlocked`:当前是否解锁(用于初始状态)
- `activateWhenUnlocked`:解锁后需要显示/激活的物体(例如发电机上的电池模型)
- `deactivateWhenUnlocked`:解锁后需要隐藏/取消激活的物体(例如门锁子物体)
- (可选)勾选 `blockInteractionWhenLocked`:让该组件本身参与“互动条件校验”,未解锁时会直接阻止互动并返回 `lockedFailReason`
- (可选)联动事件:可在 `onUnlocked / onLocked / onValueChanged(bool)` 上挂接音效、UI、剧情等
### 解锁门禁(未解锁时禁止互动)
挂载组件:[RequireUnlockedInteractCondition](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/Conditions/RequireUnlockedInteractCondition.cs)
- `unlockState`:绑定某个 `InteractUnlockState`(未绑定时默认在父级查找)
- `failReason`:失败提示
- 也可以不挂本条件组件,改为在 `InteractUnlockState` 上勾选 `blockInteractionWhenLocked` 达到同样的“未解锁不可互动”效果
### 交互成功后解锁其它目标(发电机解锁开关)
挂载组件:[UnlockStatesOnInteractSucceeded](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/Conditions/UnlockStatesOnInteractSucceeded.cs)
- `unlockSelf`:是否同时解锁自身(可用于仅通过一次后永久放行)
- `targetStates`:需要被解锁的其它 `InteractUnlockState`(例如某个开关的解锁状态)
### 指向高亮(外轮廓发光)
该效果用于“玩家指向可交互对象时显示外轮廓”,并按可互动/被锁定显示不同颜色。
1) 给可交互对象挂载:[InteractOutlineTarget](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Interaction/InteractOutlineTarget.cs)
- 默认会自动查找子物体 Renderer;也可手动指定 `renderers`
2) 给玩家挂载:[PlayerAimOutlineHighlighter](file:///e:/Unity/Unity%20Program/Test_2022/Assets/_Project/Scripts/Player/PlayerAimOutlineHighlighter.cs)
- `cameraTransform / interactRange / interactLayer` 与交互射线保持一致
- `outlineMaterial`:使用 `Project/InteractOutline` Shader 创建的材质
- `canInteractColor`:可直接互动颜色(默认偏绿)
- `lockedColor`:需要解锁颜色(默认偏橙)
3) Shader 资源:
- `Assets/_Project/Shaders/InteractOutline.shader`Shader 名称:`Project/InteractOutline`
## 推荐的挂载位置
- 推荐将条件组件挂在“门/机关根节点”上(通常是 collider 的父物体或同一层级)
- 玩家侧通过 `GetComponentsInParent<InteractConditionBehaviour>()` 获取,因此挂在父级更稳妥
## 失败原因与 UI
- 当前失败原因会在玩家侧以日志输出(来自条件组件的 `failReason` 或自动生成)
- 如果后续要接 UI 提示,建议从 `PlayerController` 的“条件失败分支”作为统一出口对接(而不是散落在每个交互脚本里)
## 注意事项
- 条件校验与消耗均基于 `ItemData.id`(string),请确保 id 唯一且稳定
- `unlockAfterSuccess` 的解锁状态是运行期内存状态;如果你需要跨存档持久化,建议后续接入存档系统再把“已解锁”写入存档