with one click
godot-interactive-system
Godot 4 可交互组件设计,包含InteractiveComponent代理组件、NPC对话、区域触发。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Godot 4 可交互组件设计,包含InteractiveComponent代理组件、NPC对话、区域触发。
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Godot 4.x .tscn 场景文件纯文本格式规范与 AI 操作指南 — 文件结构、资源引用、 Transform 变换、属性值格式、信号连接,以及 AI 直接读写 .tscn 文件的操作方法。
Godot 4.x .tscn 场景文件纯文本格式规范与 AI 操作指南 — 文件结构、资源引用、 Transform 变换、属性值格式、信号连接,以及 AI 直接读写 .tscn 文件的操作方法。
Godot 4 Autoload单例模式最佳实践,包含全局管理、事件总线、信号通信。
Godot 4 Buff系统完整实现,支持状态效果管理、持续时间、循环效果、层叠机制等。使用Resource+Component架构。
Godot 4 建造系统实现,包含GridMap方块管理、第一人称视角、射线交互。
Godot 4 ECS实体组件系统模式,包含组件化设计、数据与逻辑分离、组件通信。
| name | godot-interactive-system |
| description | Godot 4 可交互组件设计,包含InteractiveComponent代理组件、NPC对话、区域触发。 |
可交互组件系统用于实现玩家与游戏世界中各种对象的交互,如 NPC 对话、场景切换、商店等。系统采用代理模式,通过 InteractiveComponent 统一管理交互检测和事件分发。
玩家角色 (CharacterBase)
│
├── Talk Area2D (collision_mask = 256) ← 交互检测区域
│ │
│ └── Area Entered/Exited Signals
│
└── try_interact() ← 按 "talk" 键触发
│
├── talk_target.player_interact() [NPC对话]
│
└── interactable_area.interact() [关卡出口/商店]
| 类型 | 实现方式 | 触发方式 |
|---|---|---|
| NPC 对话 | npc_base.gd | 按键触发 |
| 关卡出口 | interactable_level_exit.gd | 按键触发 |
| 商店 | 自定义 player_interact | 按键触发 |
| 门 | 自动检测 | 区域进入自动触发 |
@onready var talk: Area2D = $Body/talk
var talk_target = null
var interactable_area = null
Talk Area 配置:
collision_layer = 0 # 不作为碰撞层
collision_mask = 256 # 检测位于256层的交互对象
monitorable = false # 不被其他 Area 检测
func _on_talk_area_entered(area: Area2D) -> void:
if not area is InteractiveComponent:
return
if talk_target:
talk_target.exit_interact(self)
talk_target = null
if area.has_method("enter_interact"):
talk_target = area
talk_target.enter_interact(self)
func _on_talk_area_exited(area: Area2D) -> void:
if talk_target == area:
talk_target.exit_interact(self)
talk_target = null
func try_interact():
if (not talk.has_overlapping_areas() or not talk_target) and not interactable_area:
return
if talk_target and talk_target.has_method("player_interact"):
talk_target.player_interact(self)
return
if interactable_area:
interactable_area.interact(self)
return
class_name InteractiveComponent
extends Area2D
@export var agent: Node2D = null
func player_interact(player: CharacterBase):
if not agent:
return
agent.player_interact(player)
func enter_interact(player: CharacterBase):
if not agent:
return
agent.enter_interact(player)
func exit_interact(player: CharacterBase):
if not agent:
return
agent.exit_interact(player)
场景配置:
collision_layer = 256
collision_mask = 0
monitoring = false
玩家交互请求
↓
InteractiveComponent.player_interact()
↓
agent.player_interact()
InteractiveComponent 可复用于不同对象agent 中,便于维护agent 改变交互行为class_name NPCBase
extends CharacterBody2D
@export var interactable: bool = true
signal dialogue_started
func _physics_process(delta: float) -> void:
if interactable:
if can_talk_to_npc():
if Input.is_action_just_pressed("talk"):
if !interact_lock:
dialogue_in_progress = true
dialogue_started.emit()
普通出口 - 进入即触发:
class_name LevelExit
extends Area2D
func _on_body_entered(body: Node2D):
if body is CharacterBase:
body.position = Vector2(-10000, -10000)
body.hide()
LevelManager.call_deferred("change_scene",
LevelManager.ChangeSceneParam.new(target_scene_path, target_scene_entry_tag))
可交互出口 - 需按键触发:
class_name InteractableLevelExit
extends LevelExit
func interact(body):
body.position = Vector2(-10000, -10000)
body.hide()
LevelManager.call_deferred("change_scene",
LevelManager.ChangeSceneParam.new(target_scene_path, target_scene_entry_tag))
func player_interact(player: CharacterBase):
var game_operation = handle_game_operation.bind(player)
GameDirector.wait_game.connect(game_operation)
GameDirector.load_chapter("res://chapters/store_test.json")
await GameDirector.finished
GameDirector.wait_game.disconnect(game_operation)
func enter_interact(player: CharacterBase):
var interact_material := ShaderMaterial.new()
interact_material.shader = load("res://resource/shaders/border.gdshader")
interact_material.set_shader_parameter("outline_color", Color(1, 1, 1, 1))
sprite_2d.material = interact_material
func exit_interact(_player: CharacterBase):
sprite_2d.material = null
enum DoorState { CLOSED, OPEN_LEFT, OPEN_RIGHT }
func _on_left_in_body_entered(body: Node2D) -> void:
if door_state == DoorState.CLOSED:
door_state = DoorState.OPEN_RIGHT
animated_sprite_2d.play("open_right")
可交互对象
│
├── InteractiveComponent (collision_layer = 256)
│ │
│ └── agent: Node2D ← 实际处理逻辑的节点
│
├── NPC (npc_base.gd)
│
├── InteractableLevelExit (interactable_level_exit.gd)
│
└── Store (自定义 player_interact)
| 模式 | 应用场景 |
|---|---|
| 代理模式 | InteractiveComponent 转发交互请求给 agent |
| 观察者模式 | talk_target 跟踪当前交互目标 |
| 状态机 | NPC 行为状态管理 |
| 导演模式 | GameDirector 统一管理游戏流程 |