Godot 4中如何让玩家移动时朝向相机pivot_y的Y轴方向?
解决方案
要实现移动时玩家朝向相机水平旋转(pivot_y的Y轴方向),可以通过以下调整解决:
核心修改点
- 移动方向基于pivot_y的水平朝向计算,而非玩家自身朝向
- 移动时让玩家平滑朝向当前移动的水平方向,避免look_at导致的地面朝向问题
- 修正移动状态下的相机旋转逻辑,保持pivot_y作为相机旋转的核心节点
修改后的完整脚本
extends CharacterBody3D @onready var pivot_y = $CamOriginY @onready var pivot_x = $CamOriginY/CamOriginX @onready var springarm = $CamOriginY/CamOriginX/SpringArm3D const SPEED = 5.0 const JUMP_VELOCITY = 4.5 const ROTATION_SPEED = 8.0 # 新增:玩家转向速度 @export var is_moving = false @export var forward_angle = "" @export var facing_dir = "" @export var sens: float = 0.5 @export var zoom_speed: float = 14.0 @export var spring_length_default: float = 1.0 @export var spring_length_min: float = 0.0 @export var spring_length_max: float = 2.0 @export var spring_length_target = spring_length_default @export var spring_length_current = spring_length_default var gravity = ProjectSettings.get_setting("physics/3d/default_gravity") func _ready(): Input.mouse_mode = Input.MOUSE_MODE_CAPTURED func _input(event): if event is InputEventMouseMotion: # 相机X轴旋转(上下)始终由pivot_x处理 pivot_x.rotate_x(deg_to_rad(-event.relative.y * sens)) pivot_x.rotation.x = clamp(pivot_x.rotation.x, deg_to_rad(-30), deg_to_rad(45)) if is_moving: # 移动时:玩家跟随相机水平旋转,pivot_y保持和玩家Y轴旋转同步 rotate_y(deg_to_rad(-event.relative.x * sens)) pivot_y.rotation.y = rotation.y else: # 静止时:仅旋转pivot_y,玩家朝向不变 pivot_y.rotate_y(deg_to_rad(-event.relative.x * sens)) if event.is_action_pressed("cam_zoom_in"): if spring_length_current > spring_length_min: spring_length_target = spring_length_current - 0.4 else: print("At minimum value") elif event.is_action_pressed("cam_zoom_out"): if spring_length_current < spring_length_max: spring_length_target = spring_length_current + 0.4 else: print("At maximum value") # 方向标记若未使用可考虑移除 if event.is_action_pressed("left"): facing_dir = "left" elif event.is_action_pressed("right"): facing_dir = "right" elif event.is_action_pressed("up"): print("hello") elif event.is_action_pressed("down"): facing_dir = "down" func _physics_process(delta): is_moving = false # 重力与跳跃处理 if not is_on_floor(): velocity.y -= gravity * delta if Input.is_action_just_pressed("ui_accept") and is_on_floor(): velocity.y = JUMP_VELOCITY if Input.is_action_just_pressed("quit"): get_tree().quit() # 相机变焦处理 spring_length_current = lerp(spring_length_current, float(spring_length_target), delta * zoom_speed) springarm.set_length(spring_length_current) # 移动方向计算:基于pivot_y的水平朝向 var input_dir = Input.get_vector("left", "right", "up", "down") if input_dir.length_squared() > 0: is_moving = true # 获取pivot_y的水平前向向量(忽略Y轴) var cam_forward = pivot_y.transform.basis.z cam_forward.y = 0 cam_forward = cam_forward.normalized() # 获取pivot_y的水平右向向量 var cam_right = pivot_y.transform.basis.x cam_right.y = 0 cam_right = cam_right.normalized() # 计算最终移动方向 var direction = cam_right * input_dir.x + cam_forward * input_dir.y direction = direction.normalized() # 设置移动速度 velocity.x = direction.x * SPEED velocity.z = direction.z * SPEED # 玩家平滑朝向移动方向(仅水平旋转) if direction.length_squared() > 0: var target_rotation = atan2(direction.x, direction.z) rotation.y = lerp(rotation.y, target_rotation, delta * ROTATION_SPEED) # 同步pivot_y的Y轴旋转,保持相机和玩家朝向一致 pivot_y.rotation.y = rotation.y else: # 减速停止 velocity.x = move_toward(velocity.x, 0, SPEED) velocity.z = move_toward(velocity.z, 0, SPEED) move_and_slide()
关键逻辑说明
- 相机旋转同步:移动时玩家旋转后,立刻同步
pivot_y.rotation.y = rotation.y,确保相机水平方向和玩家朝向始终一致;静止时仅旋转pivot_y,玩家朝向不变。 - 移动方向计算:通过
pivot_y.transform.basis获取相机的水平前向/右向向量,以此计算玩家的移动方向,确保移动方向跟随相机视角。 - 平滑转向:用
lerp实现玩家朝向的平滑过渡,避免生硬旋转,ROTATION_SPEED可根据手感调整。 - 避免地面朝向:计算方向时将向量的Y轴设为0,只保留水平分量,解决look_at导致的朝向地面问题。
内容的提问来源于stack exchange,提问作者plinkmaster
相关产品推荐
相关产品推荐

