➕ADD: Personajes y enemigo de testeo

This commit is contained in:
ankdev committed 2026-10-01 14:29:59 +02:00
1 parent 3d356166ca
commit 1b797a3e90
21 files changed
+696 -340

No files matched your search

+176
View File
@@ -0,0 +1,176 @@
extends CharacterBody2D
signal died
# First real enemy on purpose: no generic Enemy base class yet.
# Once a second/third enemy exists, we can extract only the behaviour they
# actually share instead of guessing an abstraction in advance.
const PLAYER_HURTBOX_MASK: int = 1 << 3
@export_category("Movement")
@export var move_speed: float = 85.0
@export var max_fall_speed: float = 1200.0
@export_category("Combat")
@export_range(1, 100, 1) var max_health: int = 3
@export_range(0, 100, 1) var contact_damage: int = 1
@export var contact_damage_interval: float = 0.45
@export_category("Debug")
## Enabled while the enemy has no final sprite/animation. The grey rectangle is
## the temporary body; red overlays are the gameplay hurtbox/contact hitbox.
@export var show_debug_hitboxes: bool = true
@onready var body_collision: CollisionShape2D = $CollisionShape2D
@onready var hurtbox_collision: CollisionShape2D = $Hurtbox/CollisionShape2D
@onready var contact_hitbox: Area2D = $ContactHitbox
@onready var contact_collision: CollisionShape2D = $ContactHitbox/CollisionShape2D
@onready var floor_probe: RayCast2D = $FloorProbe
var current_health: int
var move_direction: float = -1.0
var contact_damage_timer: float = 0.0
var is_dead: bool = false
func _ready() -> void:
current_health = max_health
contact_hitbox.collision_layer = 0
contact_hitbox.collision_mask = PLAYER_HURTBOX_MASK
contact_hitbox.monitoring = true
_update_floor_probe()
queue_redraw()
func _physics_process(delta: float) -> void:
if is_dead:
return
contact_damage_timer = max(contact_damage_timer - delta, 0.0)
_apply_gravity(delta)
_turn_before_ledge()
velocity.x = move_direction * move_speed
move_and_slide()
if is_on_wall():
_turn_around()
_damage_player_on_contact()
queue_redraw()
func _apply_gravity(delta: float) -> void:
if is_on_floor():
return
velocity += get_gravity() * delta
velocity.y = min(velocity.y, max_fall_speed)
func _turn_before_ledge() -> void:
# The ray sits just in front of the feet. If it stops finding floor while the
# enemy is grounded, turning here prevents the basic walker from suiciding
# off every platform.
if is_on_floor() and not floor_probe.is_colliding():
_turn_around()
func _turn_around() -> void:
move_direction *= -1.0
_update_floor_probe()
func _update_floor_probe() -> void:
floor_probe.position.x = abs(floor_probe.position.x) * move_direction
func _damage_player_on_contact() -> void:
if contact_damage_timer > 0.0:
return
for area in contact_hitbox.get_overlapping_areas():
var target: Node = area.get_parent()
if target != null and target.has_method("take_damage"):
target.take_damage(contact_damage, global_position)
contact_damage_timer = contact_damage_interval
return
func take_damage(amount: int, source_position: Vector2) -> void:
if amount <= 0 or is_dead:
return
current_health = max(current_health - amount, 0)
if current_health == 0:
_die()
return
# Turn away from the attacker. This gives a tiny readable reaction without
# inventing a hit-stun/knockback system before it is actually needed.
var reaction_direction: float = signf(global_position.x - source_position.x)
if reaction_direction != 0.0:
move_direction = reaction_direction
_update_floor_probe()
func _die() -> void:
is_dead = true
died.emit()
queue_free()
# ============================================================================
# TEMPORARY VISUAL + DEBUG HITBOXES
# ============================================================================
func _draw() -> void:
# The enemy has no sprite yet. This neutral block makes the actual entity
# visible independently from the red debug overlays.
_draw_rectangle_collision(
body_collision,
Color(0.18, 0.18, 0.20, 0.90),
Color(0.85, 0.85, 0.90, 1.0)
)
if not show_debug_hitboxes:
return
# Hurtbox: where punches / ground pound are allowed to damage the enemy.
_draw_rectangle_collision(
hurtbox_collision,
Color(1.0, 0.05, 0.05, 0.12),
Color(1.0, 0.05, 0.05, 0.55)
)
# Contact hitbox: slightly larger, so it is obvious exactly when touching
# the enemy can damage the player.
_draw_rectangle_collision(
contact_collision,
Color(1.0, 0.05, 0.05, 0.18),
Color(1.0, 0.05, 0.05, 0.85),
contact_hitbox.position
)
func _draw_rectangle_collision(
collision: CollisionShape2D,
fill_color: Color,
outline_color: Color,
extra_offset: Vector2 = Vector2.ZERO
) -> void:
var rectangle: RectangleShape2D = collision.shape as RectangleShape2D
if rectangle == null:
return
var center: Vector2 = collision.position + extra_offset
var rect: Rect2 = Rect2(center - rectangle.size / 2.0, rectangle.size)
draw_rect(rect, fill_color, true)
draw_rect(rect, outline_color, false, 2.0)