0d2bccc3a9
Removed the stomp-kill from walker.gd: landing on an enemy now just costs a heart like any other contact, so the only way past is to weave through the pattern or use the key throw + W warp. Enemies fire a fan of bullets every fire_interval whose directions are computed only from the facing and the exported spread, never from the player, so every volley traces the identical path and can be memorised. Bullets are code-generated circles (no art needed), die on hitting terrain via a probe raycast, and are freed after their lifetime. New laser prefab cycles wait -> blinking warmup -> firing, and only damages during the firing phase.
75 lines
2.1 KiB
GDScript
75 lines
2.1 KiB
GDScript
extends Area2D
|
|
|
|
## 固定激光:每隔一段时间循环「蓄力闪烁 -> 发射 -> 熄灭」。
|
|
## 蓄力阶段只闪不伤人(给玩家反应时间),发射阶段碰到就扣血。
|
|
## 光束从自己的原点沿 +X 方向伸出,想改朝向就转节点本身。
|
|
|
|
enum State { WAIT, WARMUP, FIRING }
|
|
|
|
@export var length: float = 90.0
|
|
@export var thickness: float = 6.0
|
|
@export var damage: int = 1
|
|
## 蓄力(闪烁警告)时长
|
|
@export var warmup: float = 0.8
|
|
## 发射持续时长
|
|
@export var fire_time: float = 0.35
|
|
## 两次发射之间的间隔
|
|
@export var cooldown: float = 1.8
|
|
## 开场后第一次发射前的延迟
|
|
@export var start_delay: float = 1.0
|
|
@export var laser_color: Color = Color(1.0, 0.25, 0.25)
|
|
@export var warn_color: Color = Color(1.0, 0.8, 0.4)
|
|
|
|
var _state: int = State.WAIT
|
|
var _timer: float = 0.0
|
|
var _first: bool = true
|
|
var _beam: Polygon2D = null
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group("hazard")
|
|
_beam = get_node_or_null("Beam") as Polygon2D
|
|
var half := thickness * 0.5
|
|
if _beam != null:
|
|
_beam.polygon = PackedVector2Array([
|
|
Vector2(0.0, -half), Vector2(length, -half),
|
|
Vector2(length, half), Vector2(0.0, half)])
|
|
_beam.color = laser_color
|
|
_beam.visible = false
|
|
var hit := get_node_or_null("HitBox") as CollisionShape2D
|
|
if hit != null:
|
|
var rect := RectangleShape2D.new()
|
|
rect.size = Vector2(length, thickness)
|
|
hit.shape = rect
|
|
hit.position = Vector2(length * 0.5, 0.0)
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
_timer += delta
|
|
match _state:
|
|
State.WAIT:
|
|
var wait: float = start_delay if _first else cooldown
|
|
if _timer >= wait:
|
|
_first = false
|
|
_state = State.WARMUP
|
|
_timer = 0.0
|
|
State.WARMUP:
|
|
if _beam != null:
|
|
_beam.color = warn_color
|
|
_beam.visible = fmod(_timer, 0.16) < 0.08
|
|
if _timer >= warmup:
|
|
_state = State.FIRING
|
|
_timer = 0.0
|
|
if _beam != null:
|
|
_beam.color = laser_color
|
|
_beam.visible = true
|
|
State.FIRING:
|
|
for body in get_overlapping_bodies():
|
|
if body.has_method("hurt"):
|
|
body.hurt(damage)
|
|
if _timer >= fire_time:
|
|
_state = State.WAIT
|
|
_timer = 0.0
|
|
if _beam != null:
|
|
_beam.visible = false
|