Files
agame/character/player/player_motor.gd
T
2026-10-09 15:10:44 +08:00

84 lines
3.0 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
class_name PlayerMotor
extends Node
## 移动组件:重力、跳跃缓冲、水平加减速。
##
## 只算速度写回 body.velocity,**不调 move_and_slide()** —— 推进由 Player 统一做。
## 这样「算速度 → 推进 → 播动画」的顺序永远固定,不受节点树顺序影响。
## 跳跃输入缓冲(秒):按下跳跃后这段时间内若落地,自动补上一次起跳
const JUMP_BUFFER_TIME: float = 0.1
@export_group("移动")
## 常规移动速度(米/秒)
@export var walk_speed: float = 5.0
## 疾跑速度(米/秒)
@export var sprint_speed: float = 8.5
## 地面加速度(米/秒²)
@export var acceleration: float = 45.0
## 空中加速度(米/秒²)
@export var air_acceleration: float = 12.0
## 起跳初速度(米/秒)
@export var jump_velocity: float = 5.0
## 本帧是否在疾跑 / 是否按住蹲键。Player 读这两个值转交给 PlayerAnimator。
var sprinting: bool = false
var crouching: bool = false
var _body: CharacterBody3D
var _look_rig: Node3D
var _gravity: float = 9.8
var _jump_buffer: float = 0.0
## 由 Player 在 _ready() 注入依赖。look_rig 用来把输入转成「相对视线」的方向。
func setup(body: CharacterBody3D, look_rig: Node3D) -> void:
_body = body
_look_rig = look_rig
_gravity = float(ProjectSettings.get_setting("physics/3d/default_gravity", 9.8))
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed("jump"):
_jump_buffer = JUMP_BUFFER_TIME
## 每物理帧由 Player 调用一次,必须排在 move_and_slide() 之前。
## 只写 _body.velocity,不做位移推进。
func step(delta: float) -> void:
if _body == null or _look_rig == null:
return
# --- 重力 ---
if _body.is_on_floor():
if _body.velocity.y < 0.0:
_body.velocity.y = 0.0
else:
_body.velocity.y -= _gravity * delta
# --- 跳跃(读取输入缓冲)---
if _jump_buffer > 0.0:
_jump_buffer -= delta
if _body.is_on_floor():
_body.velocity.y = jump_velocity
_jump_buffer = 0.0
# --- 相对视线方向的水平输入 ---
# 只用 rig 的 basis(只有 yaw),低头看地时前进方向不会跟着往下扎。
var input_dir := Input.get_vector("move_left", "move_right", "move_back", "move_forward")
var look_basis := _look_rig.global_transform.basis
var wish := look_basis.x * input_dir.x - look_basis.z * input_dir.y
wish.y = 0.0
if wish.length_squared() > 0.000001:
wish = wish.normalized()
# 只有真正按了方向键才允许疾跑(避免原地"疾跑"触发跑动动画)
sprinting = Input.is_action_pressed("sprint") and input_dir.length_squared() > 0.000001
crouching = Input.is_action_pressed("crouch")
var target_speed := sprint_speed if sprinting else walk_speed
var accel := acceleration if _body.is_on_floor() else air_acceleration
var horizontal := Vector2(_body.velocity.x, _body.velocity.z)
horizontal = horizontal.move_toward(Vector2(wish.x, wish.z) * target_speed, accel * delta)
_body.velocity.x = horizontal.x
_body.velocity.z = horizontal.y