210 lines
5.6 KiB
GDScript
210 lines
5.6 KiB
GDScript
class_name Player
|
|
extends CharacterBody2D
|
|
|
|
|
|
@export_group("Ground Movement")
|
|
@export var run_acceleration: float
|
|
@export var max_run_speed: float
|
|
@export var turn_acceleration: float
|
|
@export var stopping_force: float
|
|
|
|
@export_group("Bonk")
|
|
@export var bonk_speed_threshold: float
|
|
@export var bonk_power: float
|
|
@export var bonk_effect_count: int
|
|
@export var bonk_effect_scene: PackedScene
|
|
|
|
@export_group("Air Movement")
|
|
@export var gravity: float
|
|
@export var fast_gravity: float
|
|
@export var jump_power: float
|
|
@export var jump_horizontal_boost: float
|
|
@export var splat_launch_power: float
|
|
@export var splat_offset: float
|
|
@export var chomp_vault_impulse: Vector2
|
|
|
|
@export_group("Internal References")
|
|
@export var state_chart: StateChart
|
|
@export var graphics: Node2D
|
|
@export var run_animation: SpritesheetAnimation
|
|
|
|
@export var wall_cast: ShapeCast2D
|
|
@export var corner_cast: RayCast2D
|
|
@export var corner_height_cast: RayCast2D
|
|
@export var corner_snap_point: Node2D
|
|
@export var vault_off_point: Node2D
|
|
|
|
@export var bonk_effect_point: Node2D
|
|
|
|
|
|
@onready var start_position: Vector2 = global_position
|
|
|
|
|
|
var input_dir: Vector2 = Vector2.ZERO:
|
|
set(value):
|
|
input_dir = value.sign()
|
|
state_chart.set_expression_property(&"input_dir", input_dir)
|
|
|
|
var _last_velocity: Vector2 = Vector2.ZERO
|
|
var _splat_normal: Vector2 = Vector2.ZERO
|
|
var _bonk_cancel_velocity: Vector2 = Vector2.ZERO
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
_last_velocity = velocity
|
|
move_and_slide()
|
|
state_chart.set_expression_property(&"velocity", velocity)
|
|
if velocity.x != 0.0:
|
|
graphics.scale.x = signf(velocity.x)
|
|
|
|
state_chart.set_expression_property(&"on_floor", is_on_floor())
|
|
|
|
input_dir = Input.get_vector(&"move_left", &"move_right", &"move_up", &"move_down")
|
|
|
|
state_chart.send_event(&"tick")
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if event.is_action_pressed(&"jump"):
|
|
state_chart.send_event(&"jump_pressed")
|
|
if event.is_action_pressed(&"grab"):
|
|
state_chart.send_event(&"grab_pressed")
|
|
if event.is_action_released(&"grab"):
|
|
state_chart.send_event(&"grab_released")
|
|
|
|
|
|
func kill() -> void:
|
|
state_chart.send_event(&"killed")
|
|
|
|
|
|
func launch(impulse: Vector2) -> void:
|
|
velocity = impulse
|
|
state_chart.send_event(&"launched")
|
|
|
|
|
|
#region Idle
|
|
func _slow_to_stop(delta: float) -> void:
|
|
velocity.x = move_toward(velocity.x, 0.0, stopping_force * delta)
|
|
#endregion
|
|
|
|
#region Running
|
|
func _apply_run_acceleration(delta: float) -> void:
|
|
if absf(velocity.x) < max_run_speed:
|
|
velocity.x += input_dir.x * run_acceleration * delta
|
|
|
|
func _scale_run_animation(delta:float) -> void:
|
|
run_animation.speed_scale = inverse_lerp(0.0, max_run_speed, absf(velocity.x))
|
|
#endregion
|
|
|
|
|
|
#region Turning
|
|
func _apply_turn_acceleration(delta: float) -> void:
|
|
velocity.x += input_dir.x * turn_acceleration * delta
|
|
#endregion
|
|
|
|
|
|
#region Bonk
|
|
func _check_for_bonk(_delta: float) -> void:
|
|
if absf(velocity.x) >= bonk_speed_threshold:
|
|
wall_cast.force_shapecast_update()
|
|
if wall_cast.is_colliding():
|
|
state_chart.send_event(&"bonked")
|
|
|
|
func _enter_bonk() -> void:
|
|
_bonk_cancel_velocity = velocity * Vector2(-1.0, 1.0) # horizontally inverted velocity
|
|
velocity = Vector2.ZERO
|
|
|
|
func _cancel_bonk() -> void:
|
|
velocity = _bonk_cancel_velocity
|
|
|
|
func _apply_bonk() -> void:
|
|
velocity.x = signf(_bonk_cancel_velocity.x) * bonk_power
|
|
for _i in bonk_effect_count:
|
|
var effect_instance = bonk_effect_scene.instantiate()
|
|
effect_instance.global_position = global_position
|
|
get_parent().add_child(effect_instance)
|
|
#endregion
|
|
|
|
|
|
#region Falling
|
|
func _apply_gravity(delta: float) -> void:
|
|
if input_dir.y > 0.0:
|
|
velocity.y += fast_gravity * delta
|
|
else:
|
|
velocity.y += gravity * delta
|
|
#endregion
|
|
|
|
|
|
#region Jumping
|
|
func _start_jump() -> void:
|
|
velocity.y = -jump_power
|
|
velocity.x += input_dir.x * jump_horizontal_boost
|
|
#endregion
|
|
|
|
|
|
#region ChompVault
|
|
func _check_for_corner(_delta: float) -> void:
|
|
if signf(input_dir.x) == signf(graphics.scale.x):
|
|
corner_cast.force_raycast_update()
|
|
if not corner_cast.is_colliding():
|
|
wall_cast.force_shapecast_update()
|
|
if wall_cast.is_colliding():
|
|
state_chart.send_event(&"corner_detected")
|
|
|
|
func _start_chomp_vault() -> void:
|
|
corner_height_cast.force_raycast_update()
|
|
global_position.x = wall_cast.get_collision_point(0).x
|
|
global_position.y = corner_height_cast.get_collision_point().y
|
|
global_position -= to_local(corner_snap_point.global_position)
|
|
velocity = Vector2.ZERO
|
|
|
|
func _end_chomp_vault() -> void:
|
|
global_position += to_local(corner_snap_point.global_position)
|
|
global_position -= to_local(vault_off_point.global_position)
|
|
velocity = chomp_vault_impulse
|
|
velocity.x *= signf(graphics.scale.x)
|
|
#endregion
|
|
|
|
|
|
#region Missile
|
|
func _restore_graphics_rotation() -> void:
|
|
graphics.rotation = 0.0
|
|
|
|
|
|
func _face_towards_velocity(_delta: float) -> void:
|
|
graphics.rotation = Vector2(graphics.scale.x, 0.0).angle_to(velocity)
|
|
|
|
func _check_for_splat(delta: float) -> void:
|
|
var col = move_and_collide(_last_velocity * delta, true)
|
|
if col:
|
|
_splat_normal = col.get_normal()
|
|
if _splat_normal.dot(Vector2.UP) > 0.5:
|
|
return
|
|
velocity = Vector2.ZERO
|
|
global_position += col.get_travel()
|
|
var angle = col.get_normal().angle()
|
|
if graphics.scale.x > 0.0:
|
|
angle += PI
|
|
graphics.set_deferred(&"rotation", angle)
|
|
state_chart.send_event(&"splatted")
|
|
#endregion
|
|
|
|
|
|
#region Splatting
|
|
func _do_splat_launch() -> void:
|
|
var dir = input_dir.project(_splat_normal.orthogonal()).normalized()
|
|
if dir == Vector2.ZERO:
|
|
dir = _splat_normal
|
|
dir = dir.rotated(dir.angle_to(_splat_normal) * 0.5)
|
|
|
|
launch(dir * splat_launch_power)
|
|
#endregion
|
|
|
|
|
|
#region Death
|
|
func _reset_position() -> void:
|
|
global_position = start_position
|
|
velocity = Vector2.ZERO
|
|
graphics.scale.x = 1.0
|
|
graphics.rotation = 0.0
|
|
#endregion
|