Coyote time and jump buffer, walljump fix

This commit is contained in:
Jakob Feldmann 2021-05-11 20:07:43 +02:00
parent 36595e81ec
commit 7fd2c58218
5 changed files with 67 additions and 18 deletions

View File

@ -1,9 +1,11 @@
extends Player extends Player
export var init_boost := false export var init_boost := false
export var jump_buffer_filled := false
onready var wall_touch_direction = 0 onready var wall_touch_direction = 0
onready var left_wall_raycasts = $WallRaycasts/LeftWallRaycast onready var left_wall_raycasts = $WallRaycasts/LeftWallRaycast
onready var right_wall_raycasts = $WallRaycasts/RightWallRaycast onready var right_wall_raycasts = $WallRaycasts/RightWallRaycast
onready var player_state_machine = $PlayerStateMachine
func _on_EnemyDetector_area_entered(area: Area2D) -> void: func _on_EnemyDetector_area_entered(area: Area2D) -> void:
@ -14,6 +16,10 @@ func _on_EnemyDetector_body_entered(body: Node) -> void:
die() die()
func _on_JumpBufferTimer_timeout() -> void:
jump_buffer_filled = false
func handle_grounded_movement(delta: float, direction: Vector2) -> Vector2: func handle_grounded_movement(delta: float, direction: Vector2) -> Vector2:
return calculate_grounded_velocity(_velocity, delta, direction) return calculate_grounded_velocity(_velocity, delta, direction)
@ -33,7 +39,7 @@ func handle_wallslide_movement(delta: float, direction: Vector2) -> Vector2:
func calculate_grounded_velocity( func calculate_grounded_velocity(
linear_velocity: Vector2, delta: float, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2: ) -> Vector2:
var state = self.get_node("PlayerStateMachine").state var state = player_state_machine.state
var out_vel := linear_velocity var out_vel := linear_velocity
var velocity_direction = 1.0 var velocity_direction = 1.0
if _velocity.x < 0: if _velocity.x < 0:
@ -86,12 +92,16 @@ func calculate_grounded_velocity(
) )
elif ! reverse_move: elif ! reverse_move:
out_vel.x = max_velocity[state] * direction.x out_vel.x = max_velocity[state] * direction.x
# Jumping when grounded # Jumping when grounded or jump is buffered
if Input.is_action_just_pressed("jump"): if Input.is_action_just_pressed("jump") || jump_buffer_filled:
return calculate_jump_velocity(_velocity, delta, direction) return calculate_jump_velocity(_velocity, delta, direction)
elif player_state_machine.coyote_hanging:
out_vel.y = 0
else: else:
out_vel.y = _gravity * delta out_vel.y = _gravity * delta
return out_vel return out_vel
@ -105,7 +115,6 @@ func is_reversing_horizontal_movement(direction: Vector2) -> bool:
# Returns if the character is touching a wall with its whole body # Returns if the character is touching a wall with its whole body
# Being able to touch a vertical surface over this length also makes it a qualified "wall" # Being able to touch a vertical surface over this length also makes it a qualified "wall"
# Also sets wall_touch_direction # Also sets wall_touch_direction
# TODO Ugly side effect
# TODO Walljumping is a bit to radical behaving # TODO Walljumping is a bit to radical behaving
func is_touching_wall_completely() -> bool: func is_touching_wall_completely() -> bool:
for left_raycast in left_wall_raycasts.get_children(): for left_raycast in left_wall_raycasts.get_children():
@ -150,7 +159,10 @@ func calculate_jump_velocity(
) -> Vector2: ) -> Vector2:
var state = self.get_node("PlayerStateMachine").state var state = self.get_node("PlayerStateMachine").state
if Input.is_action_just_pressed("jump") && state != "jump": if (
Input.is_action_just_pressed("jump") && state != "jump"
|| jump_buffer_filled && state != "jump"
):
var additive_jump_force = ( var additive_jump_force = (
velocity_jump_boost_ratio velocity_jump_boost_ratio
* abs(_velocity.x) * abs(_velocity.x)
@ -163,10 +175,12 @@ func calculate_jump_velocity(
if ( if (
is_touching_wall_completely() is_touching_wall_completely()
&& is_correct_walljump_input(direction) && is_correct_walljump_input(direction)
&& ! is_on_floor()
): ):
# The faster you are moving up the farther the walljump goes # The faster you are moving up the farther the walljump goes
linear_velocity.y = (acceleration_force["walljump"].y / mass) * -1 linear_velocity.y = (acceleration_force["walljump"].y / mass) * -1
linear_velocity.x += max_velocity["walljump"] * direction.x linear_velocity.x += max_velocity["walljump"] * direction.x
if ! Input.is_action_pressed("jump"): if ! Input.is_action_pressed("jump"):
# TODO This is so good not gonna lie # TODO This is so good not gonna lie
if _velocity.y > _gravity * delta * 10: if _velocity.y > _gravity * delta * 10:
@ -176,14 +190,18 @@ func calculate_jump_velocity(
max(abs(linear_velocity.y), _gravity * delta) max(abs(linear_velocity.y), _gravity * delta)
/ 2 / 2
) )
else: else:
linear_velocity.y += _gravity * delta * 0.88 linear_velocity.y += _gravity * delta
if _velocity.x == 0: if _velocity.x == 0:
linear_velocity.x += inair_velocity * direction.x linear_velocity.x += inair_velocity * direction.x
return linear_velocity return linear_velocity
# Only applicable to downwards gravity # Only applicable to downwards gravity
# Can set the jump buffer
func calculate_fall_velocity( func calculate_fall_velocity(
linear_velocity: Vector2, delta: float, direction: Vector2 linear_velocity: Vector2, delta: float, direction: Vector2
) -> Vector2: ) -> Vector2:
@ -193,6 +211,8 @@ func calculate_fall_velocity(
linear_velocity.y = max_velocity["fall"] linear_velocity.y = max_velocity["fall"]
if _velocity.x == 0: if _velocity.x == 0:
linear_velocity.x += inair_velocity * direction.x linear_velocity.x += inair_velocity * direction.x
if Input.is_action_just_pressed("jump"):
jump_buffer_filled = true
return linear_velocity return linear_velocity

View File

@ -48,6 +48,14 @@ shape = SubResource( 2 )
[node name="PlayerStateMachine" type="Node" parent="."] [node name="PlayerStateMachine" type="Node" parent="."]
script = ExtResource( 2 ) script = ExtResource( 2 )
[node name="JumpBufferTimer" type="Timer" parent="PlayerStateMachine"]
wait_time = 0.034
one_shot = true
[node name="CoyoteTimer" type="Timer" parent="PlayerStateMachine"]
wait_time = 0.034
one_shot = true
[node name="StateLabel" type="Label" parent="."] [node name="StateLabel" type="Label" parent="."]
margin_left = -25.3386 margin_left = -25.3386
margin_top = -34.2836 margin_top = -34.2836
@ -93,3 +101,4 @@ collision_mask = 9
[connection signal="area_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_area_entered"] [connection signal="area_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_area_entered"]
[connection signal="body_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_body_entered"] [connection signal="body_entered" from="EnemyDetector" to="." method="_on_EnemyDetector_body_entered"]
[connection signal="timeout" from="PlayerStateMachine/JumpBufferTimer" to="." method="_on_JumpBufferTimer_timeout"]

View File

@ -14,10 +14,10 @@ var velocity_jump_boost_ratio := 0.1967
var init_acceleration_force := {"walk": 4181, "run": 6765, "idle": 4181} var init_acceleration_force := {"walk": 4181, "run": 6765, "idle": 4181}
# newtonmeters is the unit # newtonmeters is the unit
var acceleration_force := { var acceleration_force := {
"walk": Vector2(2584, 2000), "walk": Vector2(2584, 2200),
"idle": Vector2(2584, 2000), "idle": Vector2(2584, 2200),
"run": Vector2(2584, 2000), "run": Vector2(2584, 2200),
"walljump": Vector2(2548, 2000) "walljump": Vector2(2548, 2200)
} }
var _gravity := 1667.0 var _gravity := 1667.0
# Kilograms # Kilograms

View File

@ -1,5 +1,9 @@
extends StateMachine extends StateMachine
onready var coyoteTimer = $CoyoteTimer
export var coyote_hanging = false
onready var jumpBufferTimer = $JumpBufferTimer
# Adds the intial states # Adds the intial states
func _ready(): func _ready():
@ -18,11 +22,11 @@ func _state_logic(delta):
# RayCasts for visual debugging # RayCasts for visual debugging
# TODO Global context switch for debug/build mode # TODO Global context switch for debug/build mode
# \ is for new line in multiline statements # \ is for new line in multiline statements
parent.get_node("CollisionShape2D/RayCaster")._raycast( # parent.get_node("CollisionShape2D/RayCaster")._raycast(
Vector2.DOWN, # Vector2.DOWN,
parent.get_node("CollisionShape2D").get_shape(), # parent.get_node("CollisionShape2D").get_shape(),
parent.collision_mask # parent.collision_mask
) # )
var handle_input_ref var handle_input_ref
@ -94,25 +98,42 @@ func _get_transition(delta):
if ! parent.is_on_floor(): if ! parent.is_on_floor():
if parent._velocity.y < 0: if parent._velocity.y < 0:
new_state = states.jump new_state = states.jump
if parent._velocity.y >= 0: if parent._velocity.y >= 0:
# if self.state == states.run:
# parent._velocity.y = 0
new_state = states.fall new_state = states.fall
if ( if (
parent.is_touching_wall_completely() parent.is_touching_wall_completely()
&& parent._velocity.y <= parent.wallslide_threshold && parent._velocity.y <= parent.wallslide_threshold
): ):
# TODO Wallslide might be too long
new_state = states.wallslide new_state = states.wallslide
# Begins coyote time only if walking from ledge
elif [states.walk, states.run].has(self.state) && ! coyote_hanging:
coyoteTimer.start()
coyote_hanging = true
if new_state == states.fall && jumpBufferTimer.is_stopped():
jumpBufferTimer.start()
if (
coyoteTimer.is_stopped()
|| [states.idle, states.jump].has(self.state)
):
coyote_hanging = false
if coyote_hanging:
new_state = self.state
elif parent._velocity.x != 0: elif parent._velocity.x != 0:
if Input.is_action_pressed("boost_move"): if Input.is_action_pressed("boost_move"):
new_state = states.run new_state = states.run
else: else:
new_state = states.walk new_state = states.walk
coyote_hanging = false
else: else:
# TODO How does this apply to enviornment induced movement? # TODO How does this apply to enviornment induced movement?
new_state = states.idle new_state = states.idle
coyote_hanging = false
if new_state != self.state: if new_state != self.state:
return new_state return new_state
parent.init_boost = false parent.init_boost = false

View File

@ -58,7 +58,6 @@ tile_data = PoolIntArray( 0, 0, 0, 65536, 0, 0, 131072, 0, 0, 196608, 0, 0, 2621
[node name="Blobby" parent="." instance=ExtResource( 1 )] [node name="Blobby" parent="." instance=ExtResource( 1 )]
position = Vector2( 131, 560 ) position = Vector2( 131, 560 )
gravity = 4000.0
[node name="Camera2D" parent="Blobby" index="2"] [node name="Camera2D" parent="Blobby" index="2"]
limit_right = 85000 limit_right = 85000