feat: implement player movement controller and state machine with dash, slide, and wall-run mechanics
This commit is contained in:
@@ -7,7 +7,7 @@ var params: MovementParams:
|
||||
|
||||
|
||||
func enter(_data: Dictionary = {}) -> void:
|
||||
pass
|
||||
machine.on_ground = false
|
||||
|
||||
|
||||
func exit() -> void:
|
||||
@@ -15,56 +15,89 @@ func exit() -> void:
|
||||
|
||||
|
||||
func update(delta: float) -> void:
|
||||
var vel: Vector3 = machine.player.velocity
|
||||
var player := machine.player
|
||||
var vel: Vector3 = player.velocity
|
||||
|
||||
# Apply standard gravity
|
||||
vel.y -= params.gravity * delta
|
||||
|
||||
# Input direction
|
||||
var input_v := machine.input_dir
|
||||
var wish_dir := Vector3(input_v.x, 0.0, input_v.y)
|
||||
if wish_dir.length_squared() > 1.0:
|
||||
wish_dir = wish_dir.normalized()
|
||||
|
||||
var effective_speed := machine.get_effective_speed(params.max_air_speed)
|
||||
# ── Gravity with variable jump height ─────────────────────────────────
|
||||
var grav := params.gravity
|
||||
if vel.y < 0.0:
|
||||
# Falling: heavier gravity for snappy arcs
|
||||
grav *= params.fall_multiplier
|
||||
elif vel.y > 0.0 and not machine.input_jump_pressed:
|
||||
# Released jump early: cut the jump short
|
||||
grav *= params.low_jump_multiplier
|
||||
vel.y -= grav * delta
|
||||
|
||||
# ── Air control ───────────────────────────────────────────────────────
|
||||
var wish_dir: Vector3 = machine.wish_dir_world
|
||||
var hvel := Vector3(vel.x, 0.0, vel.z)
|
||||
var target_vel := wish_dir * effective_speed * params.air_control
|
||||
var current_speed := hvel.length()
|
||||
|
||||
hvel = hvel.lerp(target_vel, 1.0 - exp(-params.air_acceleration * delta))
|
||||
if wish_dir.length_squared() > 0.01:
|
||||
var target_speed := maxf(current_speed, params.walk_speed)
|
||||
target_speed = minf(target_speed, params.max_air_speed)
|
||||
|
||||
var target_vel := wish_dir * target_speed
|
||||
var new_hvel = hvel.lerp(target_vel, 1.0 - exp(-params.air_control * params.air_acceleration * delta))
|
||||
|
||||
# Prevent speed loss during sharp turns, but allow braking if holding backward
|
||||
if hvel.dot(target_vel) >= 0.0 and current_speed > params.walk_speed:
|
||||
if new_hvel.length_squared() > 0.01:
|
||||
new_hvel = new_hvel.normalized() * current_speed
|
||||
|
||||
hvel = new_hvel
|
||||
else:
|
||||
# No input: slight air drag (very subtle)
|
||||
hvel *= (1.0 - 0.5 * delta)
|
||||
|
||||
vel.x = hvel.x
|
||||
vel.z = hvel.z
|
||||
|
||||
# Bunny hop: if jump pressed and on ground near-peak of arc → extra boost
|
||||
if machine.input_jump_just_pressed and machine.on_ground:
|
||||
vel.y = params.jump_velocity * params.bunny_hop_impulse
|
||||
machine.player.velocity = vel
|
||||
machine.register_chain_mechanic("bunny_hop")
|
||||
machine.current_jump_count += 1
|
||||
machine.on_ground = false
|
||||
machine.switch_to("air")
|
||||
return
|
||||
player.velocity = vel
|
||||
player.move_and_slide()
|
||||
|
||||
# Double Jump
|
||||
if machine.input_jump_just_pressed and not machine.on_ground and machine.current_jump_count < params.double_jump_max_count:
|
||||
vel.y = params.double_jump_velocity
|
||||
machine.player.velocity = vel
|
||||
machine.current_jump_count += 1
|
||||
machine.register_chain_mechanic("double_jump")
|
||||
machine.switch_to("air")
|
||||
return
|
||||
|
||||
machine.player.velocity = vel
|
||||
machine.player.move_and_slide()
|
||||
|
||||
# Landing
|
||||
if machine.player.is_on_floor():
|
||||
# ── Landing ───────────────────────────────────────────────────────────
|
||||
if player.is_on_floor():
|
||||
machine.on_ground = true
|
||||
machine.current_jump_count = 0
|
||||
|
||||
# Bunny hop: if jump was buffered or pressed on landing frame
|
||||
if machine.input_jump_pressed or machine.jump_buffer_time > 0.0:
|
||||
var land_speed := Vector3(player.velocity.x, 0.0, player.velocity.z).length()
|
||||
var bhop_speed := minf(land_speed + params.bunny_hop_speed_gain, params.bunny_hop_speed_cap)
|
||||
# Maintain horizontal direction, boost speed
|
||||
var hdir := Vector3(player.velocity.x, 0.0, player.velocity.z)
|
||||
if hdir.length_squared() > 0.01:
|
||||
hdir = hdir.normalized()
|
||||
else:
|
||||
hdir = machine.wish_dir_world
|
||||
player.velocity.x = hdir.x * bhop_speed
|
||||
player.velocity.z = hdir.z * bhop_speed
|
||||
player.velocity.y = params.jump_velocity * params.bunny_hop_impulse
|
||||
machine.current_jump_count = 1
|
||||
machine.on_ground = false
|
||||
machine.jump_buffer_time = 0.0
|
||||
machine.register_chain_mechanic("bunny_hop")
|
||||
# Stay in air state
|
||||
return
|
||||
|
||||
machine.switch_to("ground")
|
||||
return
|
||||
|
||||
# Wall run transition
|
||||
if not machine.wall_normal.is_zero_approx():
|
||||
# ── Double Jump ───────────────────────────────────────────────────────
|
||||
if machine.input_jump_just_pressed and machine.current_jump_count < params.double_jump_max_count:
|
||||
player.velocity.y = params.double_jump_velocity
|
||||
machine.current_jump_count += 1
|
||||
machine.register_chain_mechanic("double_jump")
|
||||
return
|
||||
|
||||
# ── Wall run transition ───────────────────────────────────────────────
|
||||
var wall_n := machine.detect_wall_horizontal()
|
||||
if wall_n != Vector3.ZERO and machine.input_dir.length() > 0.1 and machine.wall_cooldown_timer <= 0.0:
|
||||
machine.switch_to("wall_run")
|
||||
return
|
||||
|
||||
# ── Dash ──────────────────────────────────────────────────────────────
|
||||
if machine.input_dash:
|
||||
machine.switch_to("dash")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user