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

6.7 KiB
Raw Permalink Blame History

条件交互与消耗型交互(技术参考)

更多“条件/消耗/解锁/UI 提示/指向高亮”的统一说明见:

目的

在不改动现有 IInteractable 行为脚本(门/机关/拾取物等)的前提下,为交互调用链增加“资格校验 / 消耗 / 解锁”能力,并通过给场景物体挂载条件组件完成配置。

交互链路(当前项目实现)

  • 玩家按下交互键后,PlayerController.PerformInteract()
    • Raycast 命中交互层物体
    • 收集命中物体与其父物体上的所有 IInteractable
    • 在调用 Interact() 前,查找命中物体父级上的所有 InteractConditionBehaviour 并逐一 CanInteract(...)
      • 任意条件失败:阻止交互,并输出失败原因
      • 全部条件通过:依次调用 IInteractable.Interact()
    • 交互成功后,逐一回调 InteractConditionBehaviour.OnInteractSucceeded(...)(用于消耗、解锁等)

相关代码入口:

如何给门/机关配置条件

无条件交互(默认)

  • 不挂任何 InteractConditionBehaviour 子类组件
  • 玩家会直接调用目标上的 IInteractable.Interact()

单条件:需要某个物品(可选消耗/解锁)

挂载组件:RequireItemsInteractCondition

  • mode = RequireAll
  • requirements:只填 1 条(requiredItemId + requiredAmount
  • consumeOnSuccess:成功交互后扣除数量
  • unlockAfterSuccess:成功一次后标记已解锁,后续无需再次校验/消耗
  • unlockState:可选,绑定 InteractUnlockState 用于后续 UI/渲染读取解锁状态
  • failReason:失败提示(可不填)
  • allowIfInventoryMissing:背包系统缺失时是否仍放行(慎用)

多条件(AND):挂多个条件组件

  • 同一个门/机关根节点上挂多个 InteractConditionBehaviour 子类
  • 玩家侧按顺序逐个校验,任意失败都会阻止交互

示例:门需要钥匙 + 玩家饥饿值必须大于 10(后者可由你后续新增一个“玩家状态条件”组件实现)。

多道具条件(OR/AND):一个组件内表达

挂载组件:RequireItemsInteractCondition

  • mode
    • RequireAll:所有条目都满足才通过(等价 AND
    • RequireAny:任意一个条目满足就通过(OR
  • requirements:配置多个条目(requiredItemId + requiredAmount
  • consumeOnSuccess
    • RequireAll:依次扣除所有条目数量
    • RequireAny:扣除“触发通过的那一条”的数量
  • unlockAfterSuccess:同上
  • unlockState:可选,绑定 InteractUnlockState 作为解锁状态源

解锁状态与外观切换(锁隐藏/电池显示)

挂载组件:InteractUnlockState

  • unlocked:当前是否解锁(用于初始状态)
  • activateWhenUnlocked:解锁后需要显示/激活的物体(例如发电机上的电池模型)
  • deactivateWhenUnlocked:解锁后需要隐藏/取消激活的物体(例如门锁子物体)
  • (可选)勾选 blockInteractionWhenLocked:让该组件本身参与“互动条件校验”,未解锁时会直接阻止互动并返回 lockedFailReason
  • (可选)联动事件:可在 onUnlocked / onLocked / onValueChanged(bool) 上挂接音效、UI、剧情等

解锁门禁(未解锁时禁止互动)

挂载组件:RequireUnlockedInteractCondition

  • unlockState:绑定某个 InteractUnlockState(未绑定时默认在父级查找)
  • failReason:失败提示
  • 也可以不挂本条件组件,改为在 InteractUnlockState 上勾选 blockInteractionWhenLocked 达到同样的“未解锁不可互动”效果

交互成功后解锁其它目标(发电机解锁开关)

挂载组件:UnlockStatesOnInteractSucceeded

  • unlockSelf:是否同时解锁自身(可用于仅通过一次后永久放行)
  • targetStates:需要被解锁的其它 InteractUnlockState(例如某个开关的解锁状态)

指向高亮(外轮廓发光)

该效果用于“玩家指向可交互对象时显示外轮廓”,并按可互动/被锁定显示不同颜色。

  1. 给可交互对象挂载:InteractOutlineTarget
  • 默认会自动查找子物体 Renderer;也可手动指定 renderers
  1. 给玩家挂载:PlayerAimOutlineHighlighter
  • cameraTransform / interactRange / interactLayer 与交互射线保持一致
  • outlineMaterial:使用 Project/InteractOutline Shader 创建的材质
  • canInteractColor:可直接互动颜色(默认偏绿)
  • lockedColor:需要解锁颜色(默认偏橙)
  1. Shader 资源:
  • Assets/_Project/Shaders/InteractOutline.shaderShader 名称:Project/InteractOutline

推荐的挂载位置

  • 推荐将条件组件挂在“门/机关根节点”上(通常是 collider 的父物体或同一层级)
  • 玩家侧通过 GetComponentsInParent<InteractConditionBehaviour>() 获取,因此挂在父级更稳妥

失败原因与 UI

  • 当前失败原因会在玩家侧以日志输出(来自条件组件的 failReason 或自动生成)
  • 如果后续要接 UI 提示,建议从 PlayerController 的“条件失败分支”作为统一出口对接(而不是散落在每个交互脚本里)

注意事项

  • 条件校验与消耗均基于 ItemData.id(string),请确保 id 唯一且稳定
  • unlockAfterSuccess 的解锁状态是运行期内存状态;如果你需要跨存档持久化,建议后续接入存档系统再把“已解锁”写入存档