You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Godot4第一人称控制器滑动结束后镜头复位问题求助

问题:滑动结束后镜头自动复位到正面,希望保持当前视角状态

我跟着YouTube博主lukky的第一人称控制器系列教程,在Godot 4中制作了一款第一人称控制器。目前遇到的问题是:每次滑动动作结束后,镜头会突然复位到正面。我希望滑动结束后能保持当前的视角状态,无需重新移动鼠标即可继续操作。

以下是我的实现代码:

extends CharacterBody3D

# Player nodes

@onready var neck = $Neck
@onready var head = $Neck/Head
@onready var eyes = $Neck/Head/Eyes

@onready var standing_collision_shape = $StandingCollisionShape
@onready var crouching_collisiong_shape = $CrouchingCollisiongShape
@onready var up_ray_cast = $UpRayCast
@onready var camera_3d = $Neck/Head/Eyes/Camera3D
@onready var animation_player = $Neck/Head/Eyes/AnimationPlayer

# Speed vars

var current_speed = 5.0

const walking_speed = 5.0
const sprinting_speed = 8.0
const crouching_speed = 3.0

# States

var walking = false
var sprinting = false
var crouching = false
var free_looking = false
var sliding = false

# Slide vars

var slide_timer = 0.0
var slide_timer_max = 1.0
var slide_vector = Vector2.ZERO
var slide_speed = 13.0

# Head bobbing vars

const head_bobbing_sprinting_speed = 22.0
const head_bobbing_walking_speed = 14.0
const head_bobbing_crouching_speed = 10.0

const head_bobbing_sprinting_intensity = 0.2
const head_bobbing_walking_intensity = 0.1
const head_bobbing_crouching_intensity = 0.05

var head_bobbing_vector = Vector2.ZERO
var head_bobbing_index = 0.0
var head_bobbing_current_intensity = 0.0

# Movement vars

const jump_velocity = 5.5

var crouching_depth = -0.5

var lerp_speed = 10.0

var air_lerp_speed = 3.0

var free_look_tilt_amount = 8

var last_velocity = Vector3.ZERO

# Input vars

var direction = Vector3.ZERO
const mouse_sens = 0.1


# Get the gravity from the project settings to be synced with RigidBody nodes.
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")


func _ready():
    Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
    

func _input(event):
    # Mouse looking logic
    if event is InputEventMouseMotion:
        if free_looking:
            neck.rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
            neck.rotation.y = clamp(neck.rotation.y, deg_to_rad(-120), deg_to_rad(120))
        else:
            rotate_y(deg_to_rad(-event.relative.x * mouse_sens))
        head.rotate_x(deg_to_rad(-event.relative.y * mouse_sens))
        head.rotation.x = clamp(head.rotation.x, deg_to_rad(-89), deg_to_rad(89))
    

func _physics_process(delta):
    # Getting movement input
    var input_dir = Input.get_vector("left", "right", "forward", "backward")
    
    # Handle movement state
    
    # Crouching
    if Input.is_action_pressed("crouch") || sliding:
        current_speed = lerp(current_speed, crouching_speed, delta * lerp_speed)
        head.position.y = lerp(head.position.y, crouching_depth, delta * lerp_speed)
        
        crouching_collisiong_shape.disabled = false
        standing_collision_shape.disabled = true
        
        # Slide begin logic
        if sprinting && input_dir != Vector2.ZERO:
            sliding = true
            slide_timer = slide_timer_max
            slide_vector = input_dir
            free_looking = true
        
        walking = false
        sprinting = false
        crouching = true

    elif not up_ray_cast.is_colliding():
        
        # Standing 
        
        standing_collision_shape.disabled = false
        crouching_collisiong_shape.disabled = true
        head.position.y = lerp(head.position.y, 0.0, delta * lerp_speed)
        if Input.is_action_pressed("sprint"):
            # Sprinting
            current_speed = lerp(current_speed, sprinting_speed, delta * lerp_speed)
            
            walking = false
            sprinting = true
            crouching = false
        else:
            # Walking
            current_speed = lerp(current_speed, walking_speed, delta * lerp_speed)
            
            walking = true
            sprinting = false
            crouching = false
    

    # Handle free looking
    if Input.is_action_pressed("free_look") || sliding:
        free_looking = true
        
        if sliding:
            eyes.rotation.z = lerp(eyes.rotation.z, -deg_to_rad(7.0), delta * lerp_speed)
        else:
            eyes.rotation.z = -deg_to_rad(neck.rotation.y * free_look_tilt_amount)
    else:
        free_looking = false
        neck.rotation.y = lerp(neck.rotation.y, 0.0, delta * lerp_speed)
        eyes.rotation.z = lerp(eyes.rotation.z, 0.0, delta * lerp_speed)
    
    # Hanle sliding
    if sliding:
        slide_timer -= delta
        if slide_timer <= 0:
            sliding = false
            free_looking = false
    
    # Handle headbob
    if sprinting:
        head_bobbing_current_intensity = head_bobbing_sprinting_intensity
        head_bobbing_index += head_bobbing_sprinting_speed * delta
    elif walking:
        head_bobbing_current_intensity = head_bobbing_walking_intensity
        head_bobbing_index += head_bobbing_walking_speed * delta
    elif crouching:
        head_bobbing_current_intensity = head_bobbing_crouching_intensity
        head_bobbing_index += head_bobbing_crouching_speed * delta
    
    if is_on_floor() && !sliding && input_dir != Vector2.ZERO:
        head_bobbing_vector.y = sin(head_bobbing_index)
        head_bobbing_vector.x = sin(head_bobbing_index / 2) + 0.5
        
        eyes.position.y = lerp(eyes.position.y, head_bobbing_vector.y * (head_bobbing_current_intensity / 2.0), delta * lerp_speed) # can tweak 2.0
        eyes.position.x = lerp(eyes.position.x, head_bobbing_vector.x * head_bobbing_current_intensity, delta * lerp_speed)
    else:
        eyes.position.y = lerp(eyes.position.y, 0.0, delta * lerp_speed)
        eyes.position.x = lerp(eyes.position.x, 0.0, delta * lerp_speed)
    
    
    
    
    # ------------MOVEMENT CODE------------ #
    
    # Add the gravity.
    if not is_on_floor():
        velocity.y -= gravity * delta

    # Handle Jump.
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = jump_velocity
        sliding = false # MAYBE LATER MAKE "C" SLIDE CANCEL INSTEAD OF SPACE (But still keep slide jumping)
        animation_player.play("jump")
        
    # Handle landing
    if is_on_floor():
        if last_velocity.y < -10.0:
            animation_player.play("roll")
        elif last_velocity.y < -4.0:
            animation_player.play("landing")

    # Get the input direction and handle the movement/deceleration.
    # As good practice, you should replace UI actions with custom gameplay actions.
    if is_on_floor():
        direction = lerp(direction, transform.basis * Vector3(input_dir.x, 0, input_dir.y).normalized(), delta * lerp_speed)
    else:
        if input_dir != Vector2.ZERO:
            direction = lerp(direction, transform.basis * Vector3(input_dir.x, 0, input_dir.y).normalized(), delta * air_lerp_speed)
    
    if sliding:
        direction = (transform.basis * Vector3(slide_vector.x, 0, slide_vector.y)).normalized()
        current_speed = (slide_timer + 0.1) * slide_speed
    
    if direction:
        velocity.x = direction.x * current_speed
        velocity.z = direction.z * current_speed
        
    else:
        velocity.x = move_toward(velocity.x, 0, current_speed)
        velocity.z = move_toward(velocity.z, 0, current_speed)
    
    last_velocity = velocity

    # RESPAWN
    if position.y < -10.0:
        position = Vector3(0, 0, 0)
        last_velocity = Vector3.ZERO
    
    move_and_slide()

节点结构截图:
节点结构截图

内容的提问来源于stack exchange,提问作者Coding_Guy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 17:14:52