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