Files
Echo/Assets/_Project/Docs/Interaction_条件交互与消耗型交互.md
2026-07-08 20:42:51 +08:00

119 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 条件交互与消耗型交互(技术参考)
更多“条件/消耗/解锁/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` 的解锁状态是运行期内存状态;如果你需要跨存档持久化,建议后续接入存档系统再把“已解锁”写入存档