From 3eb6049b39036c5866175c7dac3ff3b9dae52532 Mon Sep 17 00:00:00 2001 From: Joywayer Date: Fri, 24 Jul 2026 15:11:16 +0800 Subject: [PATCH] =?UTF-8?q?feat(bounce):=20bullet=5Fmanager=20=E5=91=BD?= =?UTF-8?q?=E4=B8=AD=E5=BC=B9=E8=B7=B3=E5=88=86=E6=94=AF(=E4=BC=98?= =?UTF-8?q?=E5=85=88=E4=BA=8Epierce)+=E8=B7=B3=E8=BF=87=E5=B7=B2=E8=AE=BF?= =?UTF-8?q?=E9=97=AE+=5Ffind=5Fnearest=5Funvisited=20=E5=AF=BB=E7=9A=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/autoloads/bullet_manager.gd | 40 +++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/scripts/autoloads/bullet_manager.gd b/scripts/autoloads/bullet_manager.gd index c0fcd1e..fe3bf75 100644 --- a/scripts/autoloads/bullet_manager.gd +++ b/scripts/autoloads/bullet_manager.gd @@ -73,6 +73,10 @@ func _check_collision(bullet_idx: int, base: int) -> bool: var dist_sq: float = dx * dx + dy * dy if dist_sq > query_r * query_r: continue + if _bullet_contexts.has(bullet_idx): + var vt = _bullet_contexts[bullet_idx].get("visited_targets", null) + if vt != null and entity_id in vt: + continue # 弹跳已命中过此敌:跳过,避免密集群内重复命中 # 命中:通过 DamageContextPool 发出伤害 var ctx_id: int = DamageContextPool.acquire(b_dmg, b_mult, b_type, b_own, false, 0.0) EnemyManager.apply_damage_from_context(entity_id, ctx_id) @@ -99,6 +103,25 @@ func _check_collision(bullet_idx: int, base: int) -> bool: if payload_id >= 0: var parent_depth: int = int(cold.get("trigger_parent_depth", 0)) SpellEvaluator.execute_sub(payload_id, hit_pos, b_own, parent_depth + 1) + # bounce 处理(优先于 pierce):命中后弹向最近未访问敌人,伤害递减 + var bounce: int = int(cold.get("bounce_remaining", 0)) + if bounce > 0: + var visited: Array = cold.get("visited_targets", []) + visited.append(entity_id) + var next_id: int = _find_nearest_unvisited(Vector2(bx, by), float(cold.get("bounce_range", 250.0)), visited) + if next_id >= 0: + var np: Vector2 = EnemyManager.get_pos_by_id(next_id) + var spd: float = Vector2(_data[base + 2], _data[base + 3]).length() + var dir: Vector2 = (np - Vector2(bx, by)).normalized() + _data[base + 2] = dir.x * spd + _data[base + 3] = dir.y * spd + _data[base + 7] *= float(cold.get("bounce_decay", 0.9)) + cold["bounce_remaining"] = bounce - 1 + cold["visited_targets"] = visited + _bullet_contexts[bullet_idx] = cold + return false + _swap_and_pop(bullet_idx) + return true # pierce 处理 var pierce: int = int(cold.get("pierce_remaining", 0)) if pierce > 0: @@ -174,6 +197,23 @@ func sync_multimesh(mm: MultiMesh) -> void: 0.0, Vector2(r * 2.0, r * 2.0), 0.0, Vector2(_data[base + 0], _data[base + 1]))) +## 弹跳寻的:query_circle 半径内滤除已访问/哨兵,取最近 entity_id;无则 -1 +func _find_nearest_unvisited(origin: Vector2, radius: float, visited: Array) -> int: + var hits: PackedInt32Array = SpatialGrid.query_circle(origin, radius) + var best_id: int = -1 + var best_sq: float = radius * radius + for eid in hits: + if eid in visited: + continue + var p: Vector2 = EnemyManager.get_pos_by_id(eid) + if p == Vector2(-9999.0, -9999.0): + continue + var d: float = origin.distance_squared_to(p) + if d <= best_sq: + best_sq = d + best_id = eid + return best_id + func get_nearest_enemy_pos(origin: Vector2, max_dist: float = 9999.0) -> Vector2: return EnemyManager.get_nearest_pos(origin, max_dist)