Created
September 20, 2023 03:31
-
-
Save Riordan-DC/c2e174af71339a58c56f6430afdd3934 to your computer and use it in GitHub Desktop.
Precision Platformer Controller for Godot 3.x (coyote time + prejump)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class_name Actor | |
extends KinematicBody2D | |
# Input | |
var pressing_jump = false | |
var pressing_attack = false | |
var input_direction = Vector2.ZERO | |
# Movement constants | |
export var jump_height = 100 | |
export var jump_time_to_peak = 0.5 | |
export var jump_time_to_descent = 0.4 | |
onready var jump_velocity = ((2.0 * jump_height) / jump_time_to_peak) * -1.0 | |
onready var jump_gravity = ((-2.0 * jump_height) / (jump_time_to_peak * jump_time_to_peak)) * -1.0 | |
onready var fall_gravity = ((-2.0 * jump_height) / (jump_time_to_descent * jump_time_to_descent)) * -1.0 | |
var acceleration = 1.8 | |
var acceleration_air = 0.8 | |
var max_floor_angle = deg2rad(60.0) | |
var floor_drag = 20.0 | |
var air_drag = 1.0 | |
var max_landspeed = 300 | |
var max_airspeed = 600 | |
var coyote_time = 0.1 | |
var prejump_time = 0.1 | |
# Movement variables | |
var velocity = Vector2.ZERO | |
var friction = floor_drag | |
var coyote_timer = 0.0 | |
var prejump_timer = 0.0 | |
var prev_on_floor = false | |
enum MoveState { | |
IDLE, | |
RUN, | |
PIVOT, | |
AIR | |
} | |
const MoveStateNames = ["IDLE", "RUN", "PIVOT", "AIR"] | |
var move_state = MoveState.IDLE | |
func _ready(): | |
pass | |
func _process(_delta): | |
update_input() | |
func get_gravity(): | |
return jump_gravity if (velocity.y < 0.0 and Input.is_action_pressed("move_up")) else fall_gravity | |
func _physics_process(delta): | |
velocity.y += get_gravity() * delta | |
if not is_on_floor(): | |
coyote_timer -= delta | |
if prev_on_floor: # Just fallen | |
coyote_timer = coyote_time | |
if is_on_floor() or coyote_timer > 0.0: | |
if pressing_jump: | |
velocity.y = jump_velocity | |
if abs(input_direction.x) == 0: | |
if is_on_floor(): | |
friction = floor_drag | |
velocity.x = lerp(velocity.x, 0, friction * delta) | |
else: | |
if is_on_floor(): | |
velocity.x = lerp(velocity.x, max_landspeed * input_direction.x, acceleration * delta) | |
else: | |
velocity.x = lerp(velocity.x, max_landspeed * input_direction.x, acceleration_air * delta) | |
if is_on_floor(): | |
if not pressing_jump: | |
velocity.y = clamp(velocity.y, -max_landspeed, max_landspeed) | |
velocity.x = clamp(velocity.x, -max_landspeed, max_landspeed) | |
else: | |
velocity.y = clamp(velocity.y, -max_airspeed, max_airspeed) | |
velocity.x = clamp(velocity.x, -max_landspeed, max_landspeed) | |
if prejump_timer <= 0: | |
pressing_jump = false | |
else: | |
prejump_timer -= delta | |
prev_on_floor = is_on_floor() | |
velocity = move_and_slide(velocity, Vector2.UP, true, 4, max_floor_angle, false) | |
if abs(velocity.x) < 1.0: | |
velocity.x = 0 | |
velocity = velocity.snapped(Vector2(1,1)) | |
# Stop on slope | |
if is_on_floor(): | |
if get_floor_angle(Vector2(0,-1)) != 0: | |
if input_direction.x == 0: | |
velocity.x = 0 | |
update_move_state() | |
GUI.DebugUI.label(get_instance_id(), "velocity: %s" % [velocity]) | |
func _input(_event): | |
input_direction = Input.get_vector( | |
"move_left", | |
"move_right", | |
"move_down", | |
"move_up") | |
pressing_jump = Input.is_action_just_pressed("move_up") | |
if pressing_jump: | |
prejump_timer = prejump_time | |
pressing_attack = Input.is_action_pressed("attack") | |
func update_input(): | |
pass | |
func update_move_state(): | |
if velocity.length() > 0.1: | |
# Moving | |
if is_on_floor(): | |
move_state = MoveState.RUN | |
if is_zero_approx(get_floor_angle(Vector2(0,-1))): | |
if input_direction.x > 0 and velocity.x < 0: | |
move_state = MoveState.PIVOT | |
elif input_direction.x < 0 and velocity.x > 0: | |
move_state = MoveState.PIVOT | |
else: | |
move_state = MoveState.AIR | |
else: | |
move_state = MoveState.IDLE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment