380088c694
One-screen 640x360 arena (walls, grid floor, fixed view), mech with positioning-only movement (WASD/arrows, accel/decel, no aim), auto-fire KINETIC hardpoint (nearest-target, visible range ring) firing slugs that damage + knock back, untagged grunt trickle spawner with contact damage, hull bar HUD, scene-reload on hull zero. Headless smoke gate: tests/smoke.tscn asserts boot, piloting movement, spawning, input-free auto-fire, grunt lethality, knockback displacement. 3/3 passes on nh3-dev headless 4.7.1.
59 lines
1.5 KiB
GDScript
59 lines
1.5 KiB
GDScript
extends CharacterBody2D
|
|
## Untagged grunt — the Act-1 learning-language enemy. Walks at the
|
|
## mech, deals contact damage on a tick. Untagged = neutral hue, no
|
|
## tag behavior. Knockback state lives here so KINETIC (and later
|
|
## chemistry) has something to shove.
|
|
|
|
signal died
|
|
|
|
@export var speed := 70.0
|
|
@export var hp := 3.0
|
|
@export var contact_damage := 5.0
|
|
@export var contact_interval := 0.5
|
|
@export var knockback_decay := 5.0
|
|
|
|
var _knockback := Vector2.ZERO
|
|
var _contact_cd := 0.0
|
|
var _flash := 0.0
|
|
var _mech: Node2D
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group("enemies")
|
|
_mech = get_tree().get_first_node_in_group("mech")
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
_contact_cd -= delta
|
|
var seek := Vector2.ZERO
|
|
if is_instance_valid(_mech):
|
|
seek = (_mech.global_position - global_position).normalized() * speed
|
|
_knockback = _knockback.lerp(Vector2.ZERO, 1.0 - exp(-knockback_decay * delta))
|
|
velocity = seek + _knockback
|
|
move_and_slide()
|
|
|
|
for i in get_slide_collision_count():
|
|
var collider := get_slide_collision(i).get_collider()
|
|
if collider == _mech and _contact_cd <= 0.0:
|
|
_mech.take_damage(contact_damage)
|
|
_contact_cd = contact_interval
|
|
|
|
if _flash > 0.0:
|
|
_flash -= delta
|
|
queue_redraw()
|
|
|
|
|
|
func hit(damage: float, kb: Vector2) -> void:
|
|
hp -= damage
|
|
_knockback += kb
|
|
_flash = 0.12
|
|
queue_redraw()
|
|
if hp <= 0.0:
|
|
died.emit()
|
|
queue_free()
|
|
|
|
|
|
func _draw() -> void:
|
|
var body := Color(0.95, 0.95, 0.95) if _flash > 0.0 else Color(0.45, 0.47, 0.4)
|
|
draw_circle(Vector2.ZERO, 8.0, body)
|