Blobby/src/Actor/Blobby.gd

237 lines
6.6 KiB
GDScript

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