Files
sijcdusmode/scripts/laser.gd
T
sijcdu 1b3d61793d Enemies no longer attack; add a fixed bullet-ring emitter and make lasers permanent obstacles
walker.gd lost its firing code entirely: monsters now only patrol and hurt on contact, so the only way past is footwork or the key throw + W warp. New bullet_ring prefab fires a set number of bullets evenly spread over a fixed arc on a timer, with directions derived only from its own exports, so every volley is identical and the pattern can be memorised; the level places one at cell (12,12) aimed upward with the 12 bullets spread over 180 degrees. laser.gd gained always_on, defaulting to true, so the five copied lasers are now static hazards that are always lit and damage anything overlapping them rather than blinking on and off. Bullets now stop when they spawn inside terrain.
2026-10-07 22:23:18 +08:00

91 lines
2.7 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
extends Area2D
## 激光。两种模式:
## - always_on = true(默认):**固定障碍** —— 一直亮着,碰到就扣血,只能绕开或用钥匙传送穿过去
## - always_on = false:循环「蓄力闪烁 -> 发射 -> 熄灭」,需要卡时间通过
## 光束从自己的原点沿 +X 方向伸出,想改朝向就转节点本身。
enum State { WAIT, WARMUP, FIRING }
## 固定障碍模式(一直亮着)
@export var always_on: bool = true
@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 = always_on
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:
if always_on:
if _beam != null:
_beam.visible = true
_beam.color = laser_color
_hurt_overlaps()
return
_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:
_hurt_overlaps()
if _timer >= fire_time:
_state = State.WAIT
_timer = 0.0
if _beam != null:
_beam.visible = false
## 每帧检查压在光柱里的东西(不能只靠 body_entered,
## 因为玩家可能本来就在光柱里,那样不会触发 entered)
func _hurt_overlaps() -> void:
for body in get_overlapping_bodies():
if body.has_method("hurt"):
body.hurt(damage)