Bullet field: pierce-through and damaging, rings spaced 3 cells apart

Solid bullets were blocking the patrolling enemies, so the field now defaults to solid = false: each bullet is a plain StaticBody2D with no collision layer, plus an Area2D that only detects the player, so nothing is physically obstructed while contact still costs a heart. Ring radii changed from [5, 10, 15] to [3, 6, 9]. Damage is now applied every frame to whatever is overlapping, not only on body_entered, so standing inside a bullet keeps hurting instead of only the first touch. Also picks up the editor change that removed Walker_03.
This commit is contained in:
2026-10-07 22:38:07 +08:00
parent 35174b67ab
commit defdf202e6
4 changed files with 37 additions and 29 deletions
+30 -14
View File
@@ -1,14 +1,18 @@
extends Node2D
## 静态弹幕障碍:以自己为圆心,一圈一圈地摆上**固定不动、不会发射**的子弹。
## 默认只是纯障碍(实心,撞得到、能踩上去),把 damage 调大于 0 就变成碰到扣血。
## 落在实心地砖里的子弹会自动跳过(不然会埋在地里)。
##
## 两种形态:
## - solid = true :实心障碍,挡路、能踩上去(注意:会连小怪一起挡住)
## - solid = false:可以穿透,只做伤害判定 —— 配合 damage > 0 就是普通弹幕
##
## 落在实心地砖里、或跑出关卡范围的子弹会自动跳过。
const BULLET_SCRIPT := preload("res://scripts/bullet.gd")
@export var enabled: bool = true
## 每一圈的半径(单位:格)。默认 5 格、10 格、15 格
@export var radii_cells: Array[int] = [5, 10, 15]
## 每一圈的半径(单位:格)。默认 3 格、6 格、9 格
@export var radii_cells: Array[int] = [3, 6, 9]
## 每圈摆几颗
@export var per_ring: int = 20
## 一格多少像素(图块是 18)
@@ -18,10 +22,10 @@ const BULLET_SCRIPT := preload("res://scripts/bullet.gd")
## 子弹半径
@export var bullet_radius: int = 3
@export var bullet_color: Color = Color(1.0, 0.45, 0.85)
## 实心障碍:玩家撞得到、也能踩上去
@export var solid: bool = true
## 碰到扣几颗心。0 = 只是障碍不扣血
@export var damage: int = 0
## 实心障碍:挡路、能踩上去。关掉的话就是可以穿透的纯弹幕
@export var solid: bool = false
## 碰到扣几颗心。0 = 不扣血
@export var damage: int = 1
## 超出这个范围的子弹不生成(默认整个关卡 468x270)
@export var bounds: Rect2 = Rect2(0, 0, 468, 270)
## 最多铺几圈
@@ -33,6 +37,8 @@ var made: int = 0
var skipped_out: int = 0
var skipped_ground: int = 0
var _hurt_areas: Array = []
func _ready() -> void:
if not enabled:
@@ -47,6 +53,7 @@ func _build() -> void:
made = 0
skipped_out = 0
skipped_ground = 0
_hurt_areas.clear()
for i in mini(radii_cells.size(), max_rings):
var radius: float = float(radii_cells[i]) * cell_size
for k in per_ring:
@@ -62,6 +69,19 @@ func _build() -> void:
made += 1
## 每帧检查一次:站在子弹里也会持续扣血
## (不能只靠 body_entered —— 玩家本来就在子弹里的话不会触发)
func _physics_process(_delta: float) -> void:
if damage <= 0 or _hurt_areas.is_empty():
return
for area in _hurt_areas:
if not is_instance_valid(area):
continue
for body in area.get_overlapping_bodies():
if body.has_method("hurt"):
body.hurt(damage)
func _tile_layers() -> Array:
var root: Node = owner if owner != null else get_tree().current_scene
if root == null:
@@ -91,6 +111,7 @@ func _make(pos: Vector2, tex: Texture2D) -> void:
body.collision_layer = 1
body.collision_mask = 1
else:
# 不实心:谁都挡不住,只靠下面的伤害区域起作用
body.collision_layer = 0
body.collision_mask = 0
add_child(body)
@@ -118,9 +139,4 @@ func _make(pos: Vector2, tex: Texture2D) -> void:
hit.shape = circle2
area.add_child(hit)
body.add_child(area)
area.body_entered.connect(_on_hit)
func _on_hit(body: Node2D) -> void:
if body.has_method("hurt"):
body.hurt(damage)
_hurt_areas.append(area)