131 lines
3.4 KiB
GDScript
131 lines
3.4 KiB
GDScript
extends CharacterBody2D
|
|
|
|
@export var attack_duration: float = 0.4
|
|
@export var attack_cooldown_duration: float = 0.6
|
|
|
|
@onready var attack_area: Area2D = $AttackArea
|
|
@onready var attack_timer: Timer = $AttackTimer
|
|
@onready var attack_cooldown_timer: Timer = $AttackCooldownTimer
|
|
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
|
|
|
|
# TODO: these stats are shared across most entities; extract to resource?
|
|
@export var speed: int = 200
|
|
var damage: int = 10
|
|
var can_attack: bool = true
|
|
var desired_rotation: float = 0
|
|
|
|
# Resources / money
|
|
var resources: int = 0
|
|
|
|
# Health
|
|
var maxHealth: int = 100
|
|
var healthPoints: int = 100
|
|
var isAlive: bool = true
|
|
@onready var invulnerable_cooldown_timer: Timer = $InvulnerableCooldownTimer
|
|
var hasiframes: bool = false # only used for iframe after collision for now
|
|
var target = Vector2.ZERO # either vector2 or Node2D
|
|
|
|
func _ready() -> void:
|
|
var screen_size = get_viewport_rect().size
|
|
GameManager.init_screen_size(screen_size.x, screen_size.y)
|
|
|
|
attack_area.monitoring = false # no collision until attacking TODO: Think about being attacked
|
|
attack_timer.wait_time = attack_duration
|
|
attack_cooldown_timer.wait_time = attack_cooldown_duration
|
|
|
|
sprite.play("default")
|
|
|
|
|
|
func _input(event):
|
|
# TODO: only does clicks/taps; accept mouse drags
|
|
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
|
target = get_global_mouse_position()
|
|
|
|
func _physics_process(delta):
|
|
var pos
|
|
if typeof(target) == TYPE_VECTOR2:
|
|
pos = target
|
|
elif "position" in target:
|
|
pos = target.position
|
|
else:
|
|
return
|
|
var dir: Vector2 = position.direction_to(pos)
|
|
|
|
if position.distance_to(pos) > 2:
|
|
self.desired_rotation = atan2(dir.y, dir.x)
|
|
move_and_collide(speed * dir * delta)
|
|
position = GameManager.get_boundaried_position(position)
|
|
|
|
|
|
func _process(delta):
|
|
if isAlive:
|
|
if Input.is_action_pressed("try_attack"):
|
|
try_attack()
|
|
|
|
# smoothly rotate
|
|
if self.rotation != self.desired_rotation:
|
|
self.rotation = lerp_angle(self.rotation, self.desired_rotation, clampf(4 * delta, 0, 1))
|
|
|
|
|
|
func try_attack() -> void:
|
|
if not can_attack:
|
|
return
|
|
attack()
|
|
|
|
func attack() -> void:
|
|
can_attack = false
|
|
attack_area.monitoring = true
|
|
attack_timer.start()
|
|
sprite.play("attacking")
|
|
|
|
func _on_attack_timeout() -> void:
|
|
attack_area.monitoring = false
|
|
sprite.play("default")
|
|
attack_cooldown_timer.start()
|
|
|
|
func _on_attack_cooldown_timeout() -> void:
|
|
can_attack = true
|
|
|
|
func _on_attack_hit(body: Node2D) -> void:
|
|
var hit_hittable = false
|
|
if body.is_in_group("prey") or body.is_in_group("predator"):
|
|
if body.has_method("handle_damage"):
|
|
body.handle_damage(damage, self)
|
|
hit_hittable = true
|
|
if hit_hittable:
|
|
await get_tree().create_timer(0.2).timeout
|
|
sprite.play("default")
|
|
|
|
func _on_invulnerable_cooldown_timeout() -> void:
|
|
hasiframes = false
|
|
|
|
func handle_damage(dmg: int, src: Node) -> void:
|
|
# TODO: enhanced damage logic (src entity effects?)
|
|
if not hasiframes:
|
|
print("Player took %d damage." % dmg)
|
|
healthPoints -= dmg
|
|
hasiframes = true
|
|
invulnerable_cooldown_timer.start()
|
|
if isAlive and healthPoints <= 0:
|
|
die()
|
|
|
|
func collect_resource(damnt: int) -> void:
|
|
resources += damnt
|
|
print("Resource collected! Total: ", resources)
|
|
|
|
func die() -> void:
|
|
print("Player died.")
|
|
isAlive = false
|
|
GameManager.switch_scene("respawn")
|
|
|
|
# TODO: Is this used or should it be removed? (currently unused)
|
|
func respawm() -> void:
|
|
healthPoints = maxHealth
|
|
isAlive = true
|
|
hasiframes = true
|
|
attack_cooldown_timer.start()
|
|
|
|
|
|
|
|
|