diff --git a/src/Actor/Blobby.gd b/src/Actor/Blobby.gd index aa91b4c..672de82 100644 --- a/src/Actor/Blobby.gd +++ b/src/Actor/Blobby.gd @@ -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 diff --git a/src/Actor/Blobby.tscn b/src/Actor/Blobby.tscn index b2f1fd3..9a4be63 100644 --- a/src/Actor/Blobby.tscn +++ b/src/Actor/Blobby.tscn @@ -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"] diff --git a/src/Actor/Player.gd b/src/Actor/Player.gd index ef27cf5..a0794f0 100644 --- a/src/Actor/Player.gd +++ b/src/Actor/Player.gd @@ -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 diff --git a/src/Actor/PlayerStateMachine.gd b/src/Actor/PlayerStateMachine.gd index e945c3d..1e756dc 100644 --- a/src/Actor/PlayerStateMachine.gd +++ b/src/Actor/PlayerStateMachine.gd @@ -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 diff --git a/src/Levels/Level02.tscn b/src/Levels/Level02.tscn index f6b1bb7..7268466 100644 --- a/src/Levels/Level02.tscn +++ b/src/Levels/Level02.tscn @@ -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