Files
notSpore/evolve-die-repeat/molecular/molecular_player.gd
2026-03-07 14:35:07 +01:00

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()