Skip to content

Instantly share code, notes, and snippets.

@juanibiapina
Last active November 1, 2024 16:11
Show Gist options
  • Save juanibiapina/34795ec63a0b2a869c4d7a45c3709dcc to your computer and use it in GitHub Desktop.
Save juanibiapina/34795ec63a0b2a869c4d7a45c3709dcc to your computer and use it in GitHub Desktop.
Platformer Controller
extends CharacterBody2D
const floor_move_speed_max: float = 400.0
const floor_move_acceleration: float = 2000
const floor_friction: float = 2000
const jump_min_height: float = 50
const jump_max_height: float = 200
const jump_time_to_apex: float = 0.5
const air_move_speed_max: float = 400.0
const air_move_acceleration: float = 2000
const air_friction: float = 800
const fall_max_speed: float = 3000
# Derived variables
var jump_speed_max: float
var jump_speed_min: float
var gravity: float
# State variables
var state: Callable = fall_state
var remaining_air_jumps = 1
func _ready():
jump_speed_max = 2 * jump_max_height / jump_time_to_apex
jump_speed_min = lerpf(0, jump_speed_max, jump_min_height / jump_max_height)
gravity = (2 * jump_max_height) / (jump_time_to_apex * jump_time_to_apex)
func _physics_process(delta: float) -> void:
state.call(delta)
move_and_slide()
# States
func floor_state(delta: float):
if is_on_floor():
try_jump()
floor_control(delta)
else:
change_to_fall_state()
func jump_state(delta: float):
if is_jump_over():
change_to_fall_state()
else:
if Input.is_action_just_released("jump"):
jump_cutoff()
apply_gravity(delta)
air_control(delta)
try_air_jump()
func fall_state(delta: float):
if is_on_floor():
change_to_floor_state()
else:
apply_gravity(delta)
air_control(delta)
try_air_jump()
# Helpers
func try_jump():
if Input.is_action_just_pressed("jump"):
change_to_jump_state()
func change_to_jump_state():
state = jump_state
velocity.y = -jump_speed_max
func jump_cutoff():
if velocity.y < -jump_speed_min:
velocity.y = -jump_speed_min
func try_air_jump():
if Input.is_action_just_pressed("jump") and can_air_jump():
air_jump()
func can_air_jump():
return remaining_air_jumps > 0
func air_jump():
change_to_jump_state()
remaining_air_jumps -= 1
func change_to_floor_state():
state = floor_state
remaining_air_jumps = 1
func change_to_fall_state():
state = fall_state
func apply_gravity(delta):
velocity.y = move_toward(
velocity.y,
fall_max_speed,
gravity * delta
)
func floor_control(delta: float):
var direction := Input.get_axis("move_left", "move_right")
if direction:
velocity.x = move_toward(velocity.x, floor_move_speed_max * sign(direction), floor_move_acceleration * delta)
else:
velocity.x = move_toward(velocity.x, 0, floor_friction * delta)
func air_control(delta):
var direction := Input.get_axis("move_left", "move_right")
if direction:
velocity.x = move_toward(velocity.x, air_move_speed_max * sign(direction), air_move_acceleration * delta)
else:
velocity.x = move_toward(velocity.x, 0, air_friction * delta)
func is_jump_over():
return velocity.y >= 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment