class_name PlayerLook extends Node ## 视角组件:把鼠标位移转成 CameraRig 的 yaw 与 Camera 的 pitch。 ## 只管转摄像机 —— 不碰速度、不碰动画。 ## ## 接法:Player 下挂一个普通 Node,脚本挂上去;由 Player._ready() 调 setup() 注入依赖。 @export_group("视角") ## 鼠标灵敏度(弧度/像素) @export var mouse_sensitivity: float = 0.0025 ## 最低俯角(向下看) @export var pitch_min_deg: float = -89.0 ## 最高仰角(向上看) @export var pitch_max_deg: float = 89.0 ## 眼睛分两层转:CameraRig 绕竖直轴转(yaw),Camera 原地抬头低头(pitch)。 ## 分开是为了让 pitch 不掺进移动方向 —— 移动只用 rig 的 basis,低头看地也不会走歪。 var _yaw: float = 0.0 var _pitch: float = 0.0 var _rig: Node3D var _camera: Camera3D var _body: Node3D ## 由 Player 在 _ready() 注入依赖。组件不自己 get_node,才能脱离具体场景复用。 func setup(rig: Node3D, camera: Camera3D, body: Node3D) -> void: _rig = rig _camera = camera _body = body _yaw = rig.rotation.y _pitch = clampf(camera.rotation.x, deg_to_rad(pitch_min_deg), deg_to_rad(pitch_max_deg)) _apply() func _unhandled_input(event: InputEvent) -> void: if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: _yaw -= event.relative.x * mouse_sensitivity _pitch = clampf( _pitch - event.relative.y * mouse_sensitivity, deg_to_rad(pitch_min_deg), deg_to_rad(pitch_max_deg) ) _apply() ## 把 _yaw / _pitch 落到节点上。鼠标一动就调一次(渲染帧),所以视角跟手、不等物理帧。 ## 身体跟着一起转 —— 第一人称里「你看哪,身体就朝哪」,别人看你也是这个朝向。 func _apply() -> void: if _rig == null: return _rig.rotation.y = _yaw _camera.rotation.x = _pitch _body.rotation.y = _yaw