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

View File

@ -48,6 +48,14 @@ shape = SubResource( 2 )
[node name="PlayerStateMachine" type="Node" parent="."]
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="."]
margin_left = -25.3386
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="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}
# newtonmeters is the unit
var acceleration_force := {
"walk": Vector2(2584, 2000),
"idle": Vector2(2584, 2000),
"run": Vector2(2584, 2000),
"walljump": Vector2(2548, 2000)
"walk": Vector2(2584, 2200),
"idle": Vector2(2584, 2200),
"run": Vector2(2584, 2200),
"walljump": Vector2(2548, 2200)
}
var _gravity := 1667.0
# Kilograms

View File

@ -1,5 +1,9 @@
extends StateMachine
onready var coyoteTimer = $CoyoteTimer
export var coyote_hanging = false
onready var jumpBufferTimer = $JumpBufferTimer
# Adds the intial states
func _ready():
@ -18,11 +22,11 @@ func _state_logic(delta):
# RayCasts for visual debugging
# TODO Global context switch for debug/build mode
# \ is for new line in multiline statements
parent.get_node("CollisionShape2D/RayCaster")._raycast(
Vector2.DOWN,
parent.get_node("CollisionShape2D").get_shape(),
parent.collision_mask
)
# parent.get_node("CollisionShape2D/RayCaster")._raycast(
# Vector2.DOWN,
# parent.get_node("CollisionShape2D").get_shape(),
# parent.collision_mask
# )
var handle_input_ref
@ -94,25 +98,42 @@ func _get_transition(delta):
if ! parent.is_on_floor():
if parent._velocity.y < 0:
new_state = states.jump
if parent._velocity.y >= 0:
# if self.state == states.run:
# parent._velocity.y = 0
new_state = states.fall
if (
parent.is_touching_wall_completely()
&& parent._velocity.y <= parent.wallslide_threshold
):
# TODO Wallslide might be too long
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:
if Input.is_action_pressed("boost_move"):
new_state = states.run
else:
new_state = states.walk
coyote_hanging = false
else:
# TODO How does this apply to enviornment induced movement?
new_state = states.idle
coyote_hanging = false
if new_state != self.state:
return new_state
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 )]
position = Vector2( 131, 560 )
gravity = 4000.0
[node name="Camera2D" parent="Blobby" index="2"]
limit_right = 85000