extends Player export var init_boost := false onready var wall_touch_direction = 0 onready var left_wall_raycasts = $WallRaycasts/LeftWallRaycast onready var right_wall_raycasts = $WallRaycasts/RightWallRaycast 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 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 = self.get_node("PlayerStateMachine").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[state] * int(init_boost) ) / mass ) * direction.x ) ) elif ! reverse_move: out_vel.x = max_velocity[state] * direction.x # Jumping when grounded if Input.is_action_just_pressed("jump"): return calculate_jump_velocity(_velocity, delta, direction) 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 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(): 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 func is_correct_walljump_input(direction: Vector2) -> bool: return ( Input.is_action_just_pressed("jump") && abs(direction.x + wall_touch_direction) < 1 && abs(direction.x + wall_touch_direction) >= 0 ) 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 Save this static number somewhere else func get_ground_friction() -> float: return 22.0 # TODO Comments for parameters func calculate_deceleration_force(_gravity: float, mass: float, delta: float) -> float: return get_ground_friction() * _gravity * mass * delta func calculate_jump_velocity( linear_velocity: Vector2, delta: float, direction: Vector2 ) -> Vector2: var state = self.get_node("PlayerStateMachine").state if Input.is_action_just_pressed("jump") && 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 ) if ( is_touching_wall_completely() && is_correct_walljump_input(direction) ): # 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: linear_velocity.y += _gravity * delta * 10 else: linear_velocity.y += ( max(abs(linear_velocity.y), _gravity * delta) / 2 ) else: linear_velocity.y += _gravity * delta * 0.88 if _velocity.x == 0: linear_velocity.x += inair_velocity * direction.x return linear_velocity # Only applicable to downwards gravity 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: linear_velocity.x += inair_velocity * direction.x 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.5) linear_velocity.y += ( (acceleration_force["walljump"].y / mass) * -1 * multiplicator ) linear_velocity.x += max_velocity["walljump"] * 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() -> void: _velocity = move_and_slide(_velocity, FLOOR_NORMAL) # TODO Replace .get_nodes with $ and put them to file beginning if possible # var camera = self.get_node("Camera2D") # if _velocity.x < 0: # camera.transform.origin.x = -100 # if _velocity.x > 0: # camera.transform.origin.x = 100 func die() -> void: queue_free() PlayerData.deaths += 1