HOME / 第 5 部分 · 3D 游戏开发 / 第 56 课
MODULE 5 · 3D 游戏开发
第 56 课 · 3D 拾取与交互
🎯 本课学习目标
- 实现准星指向的物体高亮
- 用射线做点击交互
- 实现开门、捡物等交互
「按 E 开门」「点击拾取」——本课用射线 + 输入实现通用 3D 交互。
📖 详细教学步骤
交互思路概念
通用交互三步:
- 每帧从准星发射射线,记录「当前指向的对象」
- 指向可交互物时显示提示(高亮/文字提示)
- 按交互键(E)调用对象的 interact() 函数
每帧检测指向对象代码
在玩家脚本里:
GDSCRIPTextends CharacterBody3D
var focused: Node3D = null # 当前指向的可交互对象
@onready var cam: Camera3D = $CameraRig/Camera3D
func _process(delta):
var center = get_viewport().get_visible_rect().size / 2
var from = cam.project_ray_origin(center)
var to = from + cam.project_ray_normal(center) * 3.0
var query = PhysicsRayQueryParameters3D.create(from, to)
var hit = get_world_3d().direct_space_state.intersect_ray(query)
# 更新焦点
var new_focus: Node3D = null
if hit and hit.collider.has_method("interact"):
new_focus = hit.collider
if new_focus != focused:
if focused and focused.has_method("set_focus"):
focused.set_focus(false) # 取消上一个高亮
focused = new_focus
if focused and focused.has_method("set_focus"):
focused.set_focus(true) # 高亮当前对象
交互执行代码
按 E 触发:
GDSCRIPTfunc _unhandled_input(event):
if event.is_action_pressed("interact") and focused:
focused.interact()
门的交互脚本代码
可交互物体统一实现 interact():
GDSCRIPTextends StaticBody3D
var opened: bool = false
func interact():
print("开门!")
opened = not opened
# 开门动画:绕 Y 轴转 90°
var tween = create_tween()
tween.tween_property(self, "rotation:y",
deg_to_rad(90) if opened else 0.0, 0.8)
高亮效果(set_focus)代码
指向时高亮物体:
GDSCRIPTfunc set_focus(focused: bool):
var mat: StandardMaterial3D = $MeshInstance3D.material_override
if focused:
mat.emission_enabled = true
mat.emission = Color(0.5, 0.8, 1.0)
mat.emission_energy_multiplier = 0.8
else:
mat.emission_enabled = false
提示文字(HUD)代码
指向可交互物时显示「按 E 开门」:
GDSCRIPTfunc _process(delta):
...
# 更新 HUD 提示
if focused:
hud.prompt.text = "[E] " + focused.prompt_text
hud.prompt.visible = true
else:
hud.prompt.visible = false
⚠️
交互没触发?
检查:①物体有碰撞形状;②has_method("interact") 存在;③射线长度够(3 米内才可交互)。
⚠️
高亮不消失?
切换焦点时记得调用旧对象的 set_focus(false)。
🧪 动手试一试
🏋️ 课后练习
做一个「开门 + 捡宝物」房间:门按 E 打开,宝物按 E 拾取并消失、HUD 提示文字切换。
门和宝物都实现 interact() 与 set_focus();玩家统一射线驱动。
💡
所有可交互物实现统一接口(interact/set_focus/prompt_text),交互系统可无限扩展。
💡
射线长度=交互距离,3 米是常见手感。
🎓 本课小结
通用 3D 交互:每帧射线找焦点 → 高亮 + HUD 提示 → 按 E 调用 interact();对象统一实现 interact/set_focus 接口。