273 lines
7.5 KiB
GDScript
273 lines
7.5 KiB
GDScript
extends Player
|
|
|
|
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
|
|
onready var init_boost = player_state_machine.init_boost
|
|
onready var init_boost_type = player_state_machine.init_boost_type
|
|
onready var camera_tween = $Camera2D/ShiftTween
|
|
onready var camera = $Camera2D
|
|
|
|
|
|
func _on_EnemyDetector_area_entered(area: Area2D) -> void:
|
|
_velocity = calculate_stomp_velocity(_velocity, stomp_feedback)
|
|
|
|
|
|
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)
|
|
|
|
|
|
func handle_jump_movement(delta: float, direction: Vector2) -> Vector2:
|
|
return calculate_jump_velocity(_velocity, delta, direction)
|
|
|
|
|
|
func handle_fall_movement(delta: float, direction: Vector2) -> Vector2:
|
|
return calculate_fall_velocity(_velocity, delta, direction)
|
|
|
|
|
|
func handle_wallslide_movement(delta: float, direction: Vector2) -> Vector2:
|
|
return calculate_wallslide_velocity(_velocity, delta, direction)
|
|
|
|
|
|
func calculate_grounded_velocity(
|
|
linear_velocity: Vector2, delta: float, direction: Vector2
|
|
) -> Vector2:
|
|
var state = player_state_machine.state
|
|
var out_vel := linear_velocity
|
|
var velocity_direction = 1.0
|
|
if _velocity.x < 0:
|
|
velocity_direction = -1.0
|
|
|
|
# Stopping movement
|
|
if direction.x == 0.0:
|
|
var deceleration_force = calculate_deceleration_force(
|
|
_gravity, mass, delta
|
|
)
|
|
# Translates velocity back to force and subtracts deceleration force
|
|
var result_force = (
|
|
abs(convert_velocity_to_force(_velocity.x, mass, delta))
|
|
- deceleration_force
|
|
)
|
|
if result_force <= 0:
|
|
out_vel.x = 0
|
|
else:
|
|
out_vel.x = (
|
|
convert_force_to_velocity(result_force, mass, delta)
|
|
* velocity_direction
|
|
)
|
|
else:
|
|
# Reversing movement
|
|
# When turning the opposite direction, friction is added to the opposite acceleration movement
|
|
var reverse_move = is_reversing_horizontal_movement(direction)
|
|
if reverse_move:
|
|
out_vel.x -= (
|
|
convert_force_to_velocity(
|
|
calculate_deceleration_force(_gravity, mass, delta),
|
|
mass,
|
|
delta
|
|
)
|
|
* velocity_direction
|
|
)
|
|
# Normal movement
|
|
if abs(_velocity.x) < max_velocity[state]:
|
|
out_vel.x += (
|
|
delta
|
|
* (
|
|
(
|
|
(
|
|
acceleration_force[state].x
|
|
+ (
|
|
init_acceleration_force[init_boost_type]
|
|
* int(init_boost)
|
|
)
|
|
)
|
|
/ mass
|
|
)
|
|
* direction.x
|
|
)
|
|
)
|
|
elif ! reverse_move:
|
|
out_vel.x = max_velocity[state] * direction.x
|
|
# 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
|
|
|
|
|
|
func is_reversing_horizontal_movement(direction: Vector2) -> bool:
|
|
return (
|
|
(direction.x > 0 && _velocity.x < 0)
|
|
|| (direction.x < 0 && _velocity.x >= 0)
|
|
)
|
|
|
|
|
|
# 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 Walljumping is a bit to radical behaving
|
|
func is_touching_wall_completely() -> bool:
|
|
for left_raycast in left_wall_raycasts.get_children():
|
|
wall_touch_direction = -1
|
|
if ! left_raycast.is_colliding():
|
|
for right_raycast in right_wall_raycasts.get_children():
|
|
wall_touch_direction = 1
|
|
if ! right_raycast.is_colliding():
|
|
wall_touch_direction = 0
|
|
return false
|
|
return true
|
|
|
|
|
|
# TODO Player gets stuck to a wall easily
|
|
func is_correct_walljump_input(direction: Vector2) -> bool:
|
|
return (
|
|
is_touching_wall_completely()
|
|
&& Input.is_action_just_pressed("jump")
|
|
&& abs(direction.x + wall_touch_direction) < 1
|
|
&& abs(direction.x + wall_touch_direction) >= 0
|
|
)
|
|
|
|
|
|
func is_correct_airstrafe_input() -> bool:
|
|
return (
|
|
air_strafe_charges > 0
|
|
&& (
|
|
Input.is_action_just_pressed("move_left")
|
|
|| Input.is_action_just_pressed("move_right")
|
|
)
|
|
)
|
|
|
|
|
|
func convert_velocity_to_force(velocity, mass, delta) -> float:
|
|
return (velocity * mass) / delta
|
|
|
|
|
|
func convert_force_to_velocity(force, mass, delta) -> float:
|
|
return (force / mass) * delta
|
|
|
|
|
|
# TODO Comments for parameters
|
|
func calculate_deceleration_force(_gravity: float, mass: float, delta: float) -> float:
|
|
return normal_floor_friction * _gravity * mass * delta
|
|
|
|
|
|
func calculate_jump_velocity(
|
|
linear_velocity: Vector2, delta: float, direction: Vector2
|
|
) -> Vector2:
|
|
var state = self.get_node("PlayerStateMachine").state
|
|
var walljumping = is_correct_walljump_input(direction)
|
|
|
|
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)
|
|
* mass
|
|
)
|
|
linear_velocity.y = (
|
|
((acceleration_force[state].y + additive_jump_force) / mass)
|
|
* -1
|
|
)
|
|
|
|
# TODO Das eskaliert ab und an komplett
|
|
if walljumping && ! 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 += acceleration_force["walljump"].x * direction.x
|
|
|
|
if ! Input.is_action_pressed("jump"):
|
|
# TODO This is so good not gonna lie
|
|
if _velocity.y > _gravity * delta * 10:
|
|
linear_velocity.y += _gravity * delta * 10
|
|
else:
|
|
linear_velocity.y += (
|
|
max(abs(linear_velocity.y), _gravity * delta)
|
|
/ 2
|
|
)
|
|
|
|
else:
|
|
linear_velocity.y += _gravity * delta
|
|
|
|
# TODO Dis shizzle buggy
|
|
if _velocity.x == 0:
|
|
linear_velocity.x += inair_velocity * direction.x
|
|
|
|
if is_correct_airstrafe_input() && ! walljumping:
|
|
linear_velocity.x += (direction.x * acceleration_force["air_strafe"].x)
|
|
air_strafe_charges -= 1
|
|
|
|
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:
|
|
if _velocity.y < max_velocity["fall"]:
|
|
linear_velocity.y += _gravity * delta
|
|
else:
|
|
linear_velocity.y = max_velocity["fall"]
|
|
if _velocity.x == 0:
|
|
# TODO this is weird
|
|
linear_velocity.x += inair_velocity * direction.x
|
|
if Input.is_action_just_pressed("jump"):
|
|
jump_buffer_filled = true
|
|
if is_correct_airstrafe_input():
|
|
linear_velocity.x += (direction.x * acceleration_force["air_strafe"].x)
|
|
air_strafe_charges -= 1
|
|
return linear_velocity
|
|
|
|
|
|
func calculate_wallslide_velocity(
|
|
linear_velocity: Vector2, delta: float, direction: Vector2
|
|
) -> Vector2:
|
|
# Walljump mechanics
|
|
if is_correct_walljump_input(direction):
|
|
# TODO This +0.01 indicates a larger problem with division through possible 0 values!!
|
|
var multiplicator = max(min(1, 1000 / (_velocity.y + 0.01)), 0.9)
|
|
linear_velocity.y += (
|
|
(acceleration_force["walljump"].y / mass)
|
|
* -1
|
|
* multiplicator
|
|
)
|
|
linear_velocity.x += acceleration_force["walljump"].x * direction.x
|
|
else:
|
|
linear_velocity.y += _gravity * delta * 0.4
|
|
# linear_velocity.x += inair_velocity * direction.x
|
|
return linear_velocity
|
|
|
|
|
|
func calculate_stomp_velocity(linear_velocity: Vector2, impulse: float) -> Vector2:
|
|
var out := linear_velocity
|
|
out.y = -impulse
|
|
return out
|
|
|
|
|
|
func execute_movement(direction) -> void:
|
|
_velocity = move_and_slide(_velocity, FLOOR_NORMAL)
|
|
# TODO Replace .get_nodes with $ and put them to file beginning if possible
|
|
|
|
|
|
func die() -> void:
|
|
queue_free()
|
|
PlayerData.deaths += 1
|