初次提交

This commit is contained in:
2026-07-20 10:56:52 +08:00
commit 7bcc0026e0
462 changed files with 50191 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
## ZoneManager — 地面效果区域管理(Autoload: ZoneManager
## 权威来源:architecture_design.md §8 ADR-R5-N1P6-N71 tick 用 while + -=
## SoA PackedFloat32Array stride=8;基于 SpatialGrid 空间索引(禁用 Area2D
## [0]=cx [1]=cy [2]=radius [3]=status_id [4]=duration [5]=tick_interval [6]=tick_accum [7]=owner_id
##
## 注:本 GDScript 外壳承载 tick 热循环为 S5 功能验收路径(P-S5-04);
## C# 子节点 ZoneManagerCs 驱动的压力路径(P-S5-ZM-0164 区×1000 敌 <1ms)留作后续优化,
## 与项目既有 C# 回退策略(R-08)一致。
extends Node
const ZONE_STRIDE: int = 8
const MAX_ZONES: int = 64
var _zone_data: PackedFloat32Array = PackedFloat32Array()
var _active_zones: int = 0
func _ready() -> void:
_zone_data.resize(MAX_ZONES * ZONE_STRIDE)
## 生成一个地面效果区域;满员时顶掉最旧(index 0 前移)
func spawn_zone(cx: float, cy: float, radius: float, status_id: int,
duration: float, tick_interval: float, owner_id: int) -> void:
if _active_zones >= MAX_ZONES:
# 顶掉最旧 Zoneindex 0),整体前移(O(N)N≤64)
for j in range(ZONE_STRIDE, _active_zones * ZONE_STRIDE):
_zone_data[j - ZONE_STRIDE] = _zone_data[j]
_active_zones -= 1
var base: int = _active_zones * ZONE_STRIDE
_zone_data[base + 0] = cx
_zone_data[base + 1] = cy
_zone_data[base + 2] = radius
_zone_data[base + 3] = float(status_id)
_zone_data[base + 4] = duration
_zone_data[base + 5] = maxf(0.01, tick_interval)
_zone_data[base + 6] = 0.0 # tick_accum
_zone_data[base + 7] = float(owner_id)
_active_zones += 1
func _physics_process(delta: float) -> void:
if _active_zones == 0:
return
var i: int = 0
while i < _active_zones:
var base: int = i * ZONE_STRIDE
_zone_data[base + 4] -= delta # duration 倒计时
_zone_data[base + 6] += delta # tick_accum 累积
# 速率限制:外层 if 守卫 + 内层 while + -= tick_intervalP6-N71,保留余量精度)
# SpatialGrid.query_circle 仅在 if 守卫内查询一次,不在 while 内重复查询
if _zone_data[base + 6] >= _zone_data[base + 5]:
var cx: float = _zone_data[base + 0]
var cy: float = _zone_data[base + 1]
var rad: float = _zone_data[base + 2]
var sid: int = int(_zone_data[base + 3])
var oid: int = int(_zone_data[base + 7])
var targets: PackedInt32Array = SpatialGrid.query_circle(Vector2(cx, cy), rad)
while _zone_data[base + 6] >= _zone_data[base + 5]:
_zone_data[base + 6] -= _zone_data[base + 5] # -= tick_interval 保留余量
for t_id in targets:
StatusManager.apply(t_id, sid, 1, -1.0, oid) # stacks=1, duration=默认, owner
if _zone_data[base + 4] <= 0.0: # duration 耗尽 → swap-and-pop 移除 + VFX 淡出
VFXManager.play("zone_expire", Vector2(_zone_data[base + 0], _zone_data[base + 1]))
if i < _active_zones - 1:
var last: int = (_active_zones - 1) * ZONE_STRIDE
for k in ZONE_STRIDE:
_zone_data[base + k] = _zone_data[last + k]
_active_zones -= 1
else:
i += 1
func get_active_count() -> int:
return _active_zones
func reset() -> void:
_active_zones = 0 # 惰性清理:SoA 数据不清零,_active_zones 控制有效范围