feat(val-blog): add 2026-04-30 dream journey post

This commit is contained in:
Chen Gu
2026-08-13 17:00:22 +08:00
committed by Chen Gu
parent 691f96e8a6
commit 81978704fc
941 changed files with 195468 additions and 755 deletions
+229
View File
@@ -0,0 +1,229 @@
extends CharacterBody2D
class_name Val
# 移动速度
@export var speed: float = 100.0
# 节点引用
@onready var body_placeholder: ColorRect = $BodyPlaceholder
@onready var head_placeholder: ColorRect = $HeadPlaceholder
@onready var thought_bubble: Label = $ThoughtBubble
@onready var state_indicator: Label = $StateIndicator
@onready var nav_agent: NavigationAgent2D = $NavigationAgent2D
@onready var interaction_timer: Timer = $InteractionTimer
@onready var think_timer: Timer = $ThinkTimer
# 状态
enum State { IDLE, WALK, INTERACT, THINK }
var current_state: State = State.IDLE
var current_room: String = "客厅"
var agent_state: Dictionary = {
"location": "客厅",
"energy": 80,
"mood": "开心",
"activity": "idle"
}
# 目标
var target_position: Vector2 = Vector2.ZERO
var target_furniture: Node = null
var bridge: Node = null
# 动画颜色
var normal_color = Color(0.36, 0.61, 0.84, 1) # 蓝色
var interact_color = Color(0.5, 0.8, 0.36, 1) # 绿色
var think_color = Color(0.8, 0.5, 0.36, 1) # 橙色
signal state_changed(new_state: String)
signal action_completed(action: String)
func _ready():
# 初始化
thought_bubble.hide()
update_state_display()
# 连接导航完成信号
nav_agent.navigation_finished.connect(_on_navigation_finished)
# 查找 BridgeClient
_find_bridge()
print("Val ready at position: ", global_position)
func _find_bridge():
# 尝试多种路径
bridge = get_node_or_null("../../BridgeClient")
if not bridge:
bridge = get_node_or_null("/root/Main/BridgeClient")
if not bridge:
await get_tree().process_frame
bridge = get_node_or_null("../../BridgeClient")
if bridge:
print("Val: BridgeClient found")
if bridge.has_signal("action_received"):
bridge.action_received.connect(_on_bridge_action)
if bridge.has_signal("state_synced"):
bridge.state_synced.connect(_on_state_synced)
else:
print("Val: BridgeClient not found - running in standalone mode")
func _physics_process(delta):
match current_state:
State.WALK:
_handle_walk(delta)
State.INTERACT:
_handle_interact()
State.THINK:
_handle_think()
_:
_handle_idle()
func _handle_walk(delta):
if nav_agent.is_navigation_finished():
current_state = State.IDLE
update_state_display()
emit_signal("action_completed", "walk")
return
var next_pos = nav_agent.get_next_path_position()
var direction = (next_pos - global_position).normalized()
velocity = direction * speed
# 翻转精灵
if direction.x < 0:
body_placeholder.scale.x = -1
head_placeholder.scale.x = -1
elif direction.x > 0:
body_placeholder.scale.x = 1
head_placeholder.scale.x = 1
# 行走时颜色闪烁
body_placeholder.color = normal_color.lerp(Color.WHITE, sin(Time.get_ticks_msec() * 0.01) * 0.1)
move_and_slide()
func _handle_idle():
velocity = Vector2.ZERO
body_placeholder.color = normal_color
head_placeholder.color = normal_color
state_indicator.text = "idle"
func _handle_interact():
velocity = Vector2.ZERO
body_placeholder.color = interact_color
head_placeholder.color = interact_color
state_indicator.text = "interact"
func _handle_think():
velocity = Vector2.ZERO
body_placeholder.color = think_color
head_placeholder.color = think_color
state_indicator.text = "think"
# 移动到指定位置
func move_to(pos: Vector2):
target_position = pos
nav_agent.target_position = pos
current_state = State.WALK
update_state_display()
emit_signal("state_changed", "walk")
print("Val moving to: ", pos)
# 移动到家具并交互
func interact_with(furniture: Node):
target_furniture = furniture
var interact_pos = furniture.global_position + Vector2(0, 60)
print("Val will interact with: ", furniture.get_meta("furniture_name", "未知"), " at ", interact_pos)
move_to(interact_pos)
# 等待移动完成后再交互
await action_completed
_start_interaction(furniture)
func _start_interaction(furniture: Node):
current_state = State.INTERACT
update_state_display()
var furniture_name = furniture.get_meta("furniture_name", "物品")
var interaction = furniture.get_meta("interaction", "使用")
show_thought("正在" + interaction + furniture_name + "...")
# 发送交互事件到Bridge
_send_to_bridge({
"type": "furniture_interacted",
"furniture": furniture_name,
"interaction": interaction,
"position": [global_position.x, global_position.y]
})
# 交互持续2秒
interaction_timer.start(2.0)
await interaction_timer.timeout
current_state = State.IDLE
thought_bubble.hide()
update_state_display()
emit_signal("action_completed", "interact")
print("Val finished interacting with: ", furniture_name)
# 显示思考气泡
func show_thought(text: String, duration: float = 3.0):
thought_bubble.text = text
thought_bubble.show()
if duration > 0:
think_timer.start(duration)
await think_timer.timeout
thought_bubble.hide()
# 处理Bridge发来的动作
func _on_bridge_action(action: Dictionary):
match action.get("cmd", ""):
"walk_to":
move_to(Vector2(action.pos[0], action.pos[1]))
"show_thought":
show_thought(action.get("text", ""), action.get("duration", 3.0))
"interact":
var furniture_path = action.get("furniture_path", "")
if furniture_path:
var furniture = get_node_or_null(furniture_path)
if furniture:
interact_with(furniture)
"update_state":
_update_internal_state(action.get("key", ""), action.get("value"))
# 同步OpenClaw状态
func _on_state_synced(state: Dictionary):
agent_state = state
current_room = state.get("location", current_room)
update_state_display()
func _update_internal_state(key: String, value):
agent_state[key] = value
update_state_display()
func update_state_display():
state_indicator.text = State.keys()[current_state].to_lower()
func _on_navigation_finished():
current_state = State.IDLE
update_state_display()
print("Val navigation finished")
func _send_to_bridge(data: Dictionary):
if bridge and "send_command" in bridge:
bridge.send_command(data)
# 公共API:接收用户指令
func receive_command(command: String):
show_thought("思考中...", 0)
current_state = State.THINK
update_state_display()
_send_to_bridge({
"type": "user_command",
"command": command,
"current_state": agent_state
})