GodotGameWorkshop/Scripts/skeleton.gd
doctorbatmanwho-creator 53fd05c165 Add player health, lives, death, and cutscene system
Added player damage, invulnerability frames, knockback, and death handling. Enemies stop attacking after player death and player controls are disabled. Added a persistent three-life system with ambulance cutscenes after the first two deaths and a final Game Over cutscene after the third death.
2026-08-27 21:31:58 -04:00

180 lines
3.8 KiB
GDScript

extends CharacterBody2D
@export var speed := 75.0
@export var gravity := 980.0
@export var max_health := 3
@export var attack_range := 40.0
@export var memory_piece_scene: PackedScene
@export var memory_texture: Texture2D
@export var memory_return_spawn: Marker2D
@export var memory_wardrobe: Node2D
@onready var sprite: AnimatedSprite2D = $AnimatedSprite2D
@onready var detection_area: Area2D = $DetectionArea
@onready var attack_hitbox = $AttackHitbox
var health := 3
var player: Player = null
var is_dead := false
var is_hurt := false
var is_attacking := false
var attack_cooldown := false
var knockback_velocity := Vector2.ZERO
func _ready() -> void:
health = max_health
attack_hitbox.monitoring = false
sprite.play("idle")
detection_area.body_entered.connect(_on_detection_body_entered)
detection_area.body_exited.connect(_on_detection_body_exited)
sprite.animation_finished.connect(_on_animation_finished)
func _physics_process(delta: float) -> void:
if is_dead:
return
if player and player.is_dead:
player = null
is_attacking = false
attack_hitbox.monitoring = false
velocity.x = 0
sprite.play("idle")
move_and_slide()
return
if not is_on_floor():
velocity.y += gravity * delta
if is_hurt:
velocity = knockback_velocity
knockback_velocity = knockback_velocity.move_toward(
Vector2.ZERO,
800 * delta
)
move_and_slide()
return
if is_attacking:
velocity.x = 0
move_and_slide()
return
if player:
var direction := player.global_position.x - global_position.x
if abs(direction) > attack_range:
velocity.x = sign(direction) * speed
sprite.play("walk")
if velocity.x < 0:
sprite.flip_h = true
elif velocity.x > 0:
sprite.flip_h = false
else:
velocity.x = 0
attack()
else:
velocity.x = move_toward(velocity.x, 0, speed)
sprite.play("idle")
move_and_slide()
func attack() -> void:
if is_attacking:
return
if attack_cooldown:
return
is_attacking = true
attack_cooldown = true
velocity.x = 0
sprite.play("attack")
await get_tree().create_timer(0.2).timeout
do_attack_damage()
func do_attack_damage() -> void:
print("Checking attack hit")
attack_hitbox.monitoring = true
await get_tree().physics_frame
await get_tree().physics_frame
var bodies = attack_hitbox.get_overlapping_bodies()
print("Bodies found: ", bodies.size())
for body in bodies:
if body is Player and not body.is_dead:
print("SKELETON HIT PLAYER")
body.receive_damage(1, global_position)
attack_hitbox.monitoring = false
func take_damage(amount: int = 1) -> void:
if is_dead:
return
health -= amount
print("Skeleton health:", health)
if health <= 0:
die()
else:
is_hurt = true
if player:
var knockback_direction = sign(global_position.x - player.global_position.x)
knockback_velocity = Vector2(knockback_direction * 125, 0)
sprite.play("hurt")
await get_tree().create_timer(0.3).timeout
is_hurt = false
knockback_velocity = Vector2.ZERO
func die() -> void:
if is_dead:
return
is_dead = true
velocity.x = 0
sprite.play("death")
print("Skeleton died")
func _on_detection_body_entered(body: Node) -> void:
if body is Player:
player = body
print("Skeleton detected player")
func _on_detection_body_exited(body: Node) -> void:
if body == player:
player = null
print("Skeleton lost player")
func _on_animation_finished() -> void:
if sprite.animation == "hurt":
is_hurt = false
knockback_velocity = Vector2.ZERO
if sprite.animation == "attack":
is_attacking = false
await get_tree().create_timer(1.0).timeout
attack_cooldown = false
if sprite.animation == "death":
if memory_piece_scene:
var piece = memory_piece_scene.instantiate()
get_parent().add_child(piece)
piece.global_position = global_position
piece.memory_texture = memory_texture
piece.return_spawn = memory_return_spawn
piece.wardrobe = memory_wardrobe
queue_free()