Files
sijcdusmode/scripts/laser.gd
T
sijcdu 0d2bccc3a9 Monsters are now unkillable and fire a fixed bullet pattern; add periodic lasers
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.
2026-10-07 22:12:14 +08:00

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