191 lines
5 KiB
GDScript
191 lines
5 KiB
GDScript
class_name Player extends CharacterBody2D
|
|
# Child Nodes
|
|
@onready var camera : Camera2D = $Camera2D;
|
|
@onready var anim_sprite : AnimatedSprite2D = $AnimatedSprite2D;
|
|
@onready var earth_aligner : Node2D = $EarthAligner;
|
|
@onready var sword : Area2D = $Sword;
|
|
@onready var active_item_cooldown : Timer = $ActiveItemCooldown
|
|
|
|
@export var double_jump_animation : PackedScene
|
|
|
|
# allow taking away player control
|
|
var handle_input : bool = true
|
|
|
|
# Gravity
|
|
var earth_center = Vector2.ZERO;
|
|
var max_fall_speed = 700;
|
|
var gravity = 100;
|
|
|
|
# Movement
|
|
var facing = -1;
|
|
var hspeed = 150;
|
|
var jump_strength = 1200;
|
|
var air_jumps_max = 1;
|
|
var air_jumps_current = 1;
|
|
|
|
# HP and Iframes
|
|
signal health_changed(new_health : int)
|
|
signal max_hp_changed(new_max_hp : int)
|
|
signal player_died
|
|
|
|
var current_hp = 5:
|
|
set(new_hp):
|
|
current_hp = new_hp
|
|
health_changed.emit(current_hp)
|
|
@export var max_hp = 5:
|
|
set(new_max_hp):
|
|
max_hp = new_max_hp
|
|
max_hp_changed.emit(max_hp)
|
|
var hit_invulnerability = 0.8
|
|
var inv_time = 0;
|
|
var dead = false;
|
|
|
|
# Received Knockback
|
|
var reset_to_velocity = Vector2.ZERO
|
|
var knockback_strength = 1500
|
|
var damage_knockup = 500
|
|
|
|
# Attack Handling
|
|
var atk_cooldown = 0.5
|
|
var atk_timer = 0
|
|
var can_upslash = false
|
|
|
|
signal attack
|
|
|
|
# Active Item
|
|
signal active_item_changed(newitem : Item)
|
|
var active_item : ActiveItem = null:
|
|
set(new_active_item):
|
|
active_item = new_active_item
|
|
active_item_changed.emit(active_item)
|
|
|
|
|
|
func set_cooldown(cooldown):
|
|
active_item_cooldown.wait_time = cooldown
|
|
|
|
func activate_cooldown():
|
|
active_item_cooldown.start()
|
|
|
|
|
|
func _ready() -> void:
|
|
max_hp_changed.emit(max_hp)
|
|
health_changed.emit(current_hp)
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
manage_velocity(delta)
|
|
move_and_slide()
|
|
|
|
func _process(delta: float) -> void:
|
|
manage_iframes(delta)
|
|
manage_movement_options()
|
|
manage_active(delta)
|
|
manage_animation()
|
|
manage_attack(delta)
|
|
|
|
func manage_iframes(delta: float):
|
|
if(inv_time > 0):
|
|
inv_time = max(0, inv_time-delta)
|
|
|
|
func manage_attack(delta : float):
|
|
atk_timer = max(0, atk_timer-delta)
|
|
if handle_input:
|
|
if(Input.is_action_just_pressed("attack") and atk_timer <= 0):
|
|
if Input.is_action_pressed("up") and can_upslash:
|
|
attack.emit("up")
|
|
else:
|
|
attack.emit("horizontal")
|
|
$AnimatedSprite2D.play("attack")
|
|
$SwordSwingAudio.play()
|
|
atk_timer = atk_cooldown
|
|
|
|
func manage_active(_delta : float):
|
|
if(active_item != null and Input.is_action_just_pressed("item") and active_item_cooldown.is_stopped()):
|
|
active_item.activate()
|
|
if(Input.is_action_just_pressed("drop_item")):
|
|
active_item = null
|
|
|
|
func manage_movement_options() -> void:
|
|
if(is_on_floor()):
|
|
air_jumps_current = air_jumps_max
|
|
|
|
func manage_animation() -> void:
|
|
var walk_dir = 0
|
|
if(handle_input):
|
|
if(Input.is_action_pressed("move_right")):
|
|
walk_dir += 1
|
|
if(Input.is_action_pressed("move_left")):
|
|
walk_dir -= 1
|
|
|
|
if(walk_dir != 0):
|
|
facing = walk_dir
|
|
anim_sprite.scale.x = - abs(anim_sprite.scale.x) * facing
|
|
if(is_on_floor() and not $AnimatedSprite2D.is_playing()):
|
|
anim_sprite.play("walk")
|
|
else:
|
|
if anim_sprite.animation == "walk":
|
|
anim_sprite.stop()
|
|
|
|
|
|
func manage_velocity(delta: float) -> void:
|
|
up_direction = (position - earth_center).normalized();
|
|
var old_local_velocity = earth_aligner.local_from_global(velocity)
|
|
var local_velocity = Vector2(old_local_velocity.x/pow(1.7,60*delta), old_local_velocity.y);
|
|
local_velocity += Vector2(0, gravity)
|
|
|
|
if handle_input:
|
|
if(Input.is_action_pressed("move_right")):
|
|
local_velocity += Vector2(hspeed, 0)
|
|
if(Input.is_action_pressed("move_left")):
|
|
local_velocity += Vector2(-hspeed, 0)
|
|
|
|
if(Input.is_action_just_pressed("jump") and (is_on_floor() or air_jumps_current > 0)):
|
|
var dropped = false
|
|
if(not is_on_floor()):
|
|
air_jumps_current -= 1;
|
|
play_double_jump_animation()
|
|
elif (Input.is_action_pressed("drop")):
|
|
dropped = true
|
|
self.position += earth_aligner.global_from_local(Vector2(0,12))
|
|
if(not dropped):
|
|
local_velocity.y = -jump_strength
|
|
|
|
if(local_velocity.y > max_fall_speed):
|
|
local_velocity.y = max_fall_speed
|
|
|
|
if(reset_to_velocity != Vector2.ZERO):
|
|
local_velocity = reset_to_velocity
|
|
reset_to_velocity = Vector2.ZERO
|
|
velocity = earth_aligner.global_from_local(local_velocity)
|
|
|
|
|
|
func hurt(dmg: int, dir: Vector2 = Vector2.ZERO):
|
|
if(inv_time <= 0):
|
|
$AudioStreamPlayer2D.play()
|
|
current_hp -= dmg
|
|
if(current_hp <= 0):
|
|
die()
|
|
inv_time = hit_invulnerability
|
|
reset_to_velocity = Vector2(-sign(earth_aligner.local_from_global(dir).x)*knockback_strength, -damage_knockup)
|
|
return true
|
|
return false
|
|
|
|
func die():
|
|
if not dead:
|
|
player_died.emit()
|
|
dead = true
|
|
|
|
func _on_attack_end():
|
|
if($AnimatedSprite2D.animation != "idle"):
|
|
$AnimatedSprite2D.play("idle")
|
|
$AnimatedSprite2D.stop()
|
|
|
|
func _on_death_screen_visibility_changed() -> void:
|
|
handle_input = !handle_input
|
|
|
|
func play_double_jump_animation() -> void:
|
|
$AirJumpAudio.play()
|
|
var node = double_jump_animation.instantiate()
|
|
add_child(node)
|
|
node.position = Vector2(0, 5)
|
|
node.scale = .5 * Vector2.ONE
|
|
node.reparent(get_parent())
|