Fix spawner zone override targeting and BoxCollider2D bounds

- Добавлено свойство spawnerNameFilter (по умолчанию 'Enemy') в EntitySpawnerZone, чтобы зоны переопределения применялись только к спавнерам врагов и не заменяли префабы в CoinSpawner (спавнерах кристаллов) или других спавнерах предметов.
- Реализована точная математическая проверка IsPointInside для BoxCollider2D, что делает ее независимой от Z-координаты и тиков физического движка Unity.
- Исправлено поведение в EntitySpawner: теперь при поиске зоны проверяется zone.MatchesSpawner.
This commit is contained in:
Данил Ярош 2026-08-13 14:12:19 +03:00
parent 28f5409187
commit ad744301dd
3 changed files with 161 additions and 2 deletions

View File

@ -470,6 +470,38 @@ SpriteRenderer:
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_SpriteSortPoint: 0
--- !u!1 &8883395
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8883396}
m_Layer: 0
m_Name: SpawnZones
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8883396
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8883395}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1818583591}
m_Father: {fileID: 144963232}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &9184405
GameObject:
m_ObjectHideFlags: 0
@ -123497,6 +123529,7 @@ Transform:
m_Children:
- {fileID: 625438257}
- {fileID: 845624047}
- {fileID: 8883396}
m_Father: {fileID: 1053302775}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &144963233
@ -503951,6 +503984,102 @@ SpriteRenderer:
m_SpriteTileMode: 0
m_WasSpriteAssigned: 1
m_SpriteSortPoint: 0
--- !u!1 &1818583590
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1818583591}
- component: {fileID: 1818583593}
- component: {fileID: 1818583592}
m_Layer: 0
m_Name: NoProjectiles
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1818583591
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1818583590}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 48, y: 6, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8883396}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1818583592
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1818583590}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b5c91a3a7ea71314e9c60d5e48b397d4, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::RR.Game2D.Behaviour.EntitySpawnerZone
prefabs:
- prefab: {fileID: 3321014767926845978, guid: acfc0078c078bda4bb708ac4d22f60df, type: 3}
weight: 0
- prefab: {fileID: 5620532696342616547, guid: 64b2e8b5daaf53048a7ae0709db68282, type: 3}
weight: 0
--- !u!61 &1818583593
BoxCollider2D:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1818583590}
m_Enabled: 1
serializedVersion: 3
m_Density: 1
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_ForceSendLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ForceReceiveLayers:
serializedVersion: 2
m_Bits: 4294967295
m_ContactCaptureLayers:
serializedVersion: 2
m_Bits: 4294967295
m_CallbackLayers:
serializedVersion: 2
m_Bits: 4294967295
m_IsTrigger: 0
m_UsedByEffector: 0
m_CompositeOperation: 0
m_CompositeOrder: 0
m_Offset: {x: 36.5, y: 1.5}
m_SpriteTilingProperty:
border: {x: 0, y: 0, z: 0, w: 0}
pivot: {x: 0, y: 0}
oldSize: {x: 0, y: 0}
newSize: {x: 0, y: 0}
adaptiveTilingThreshold: 0
drawMode: 0
adaptiveTiling: 0
m_AutoTiling: 0
m_Size: {x: 74, y: 22}
m_EdgeRadius: 0
--- !u!4 &1818698340 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 2923341736873825775, guid: e5783e81b8b0fd648974f0ec7ebde930, type: 3}

View File

@ -268,7 +268,7 @@ namespace RR.Game2D.Behaviour
for (int i = 0; i < EntitySpawnerZone.ActiveZones.Count; i++)
{
EntitySpawnerZone zone = EntitySpawnerZone.ActiveZones[i];
if (zone != null && zone.IsPointInside(spawnPosition))
if (zone != null && zone.MatchesSpawner(this) && zone.IsPointInside(spawnPosition))
{
activePrefabs = zone.Prefabs;
break;

View File

@ -12,6 +12,10 @@ namespace RR.Game2D.Behaviour
[Tooltip("Список префабов, которые будут спавниться вместо оригинальных префабов спавнера внутри этой зоны.")]
[SerializeField] private EntitySpawner.SpawnPrefabEntry[] prefabs;
[Header("Targeting")]
[Tooltip("Фильтр по имени GameObject спавнера. Если не пусто, зона будет переопределять только те спавнеры, чье имя содержит этот текст (без учета регистра).")]
[SerializeField] private string spawnerNameFilter = "Enemy";
private Collider2D _collider;
// Статический список всех активных зон на сцене для быстрого поиска
@ -39,6 +43,20 @@ namespace RR.Game2D.Behaviour
ActiveZones.Remove(this);
}
/// <summary>
/// Проверяет, подходит ли данный спавнер под критерии фильтрации зоны.
/// </summary>
public bool MatchesSpawner(EntitySpawner spawner)
{
if (spawner == null)
return false;
if (string.IsNullOrEmpty(spawnerNameFilter))
return true;
return spawner.gameObject.name.IndexOf(spawnerNameFilter, StringComparison.OrdinalIgnoreCase) >= 0;
}
/// <summary>
/// Проверяет, находится ли мировая точка внутри коллайдера зоны.
/// </summary>
@ -49,7 +67,19 @@ namespace RR.Game2D.Behaviour
_collider = GetComponent<Collider2D>();
}
return _collider != null && _collider.OverlapPoint(point);
if (_collider == null)
return false;
// Если это BoxCollider2D, выполняем точную математическую проверку в локальных координатах.
// Это работает надежно в любой момент (даже до первого физического обновления) и не зависит от Z-координаты.
if (_collider is BoxCollider2D box)
{
Vector3 localPoint = transform.InverseTransformPoint(point);
return Mathf.Abs(localPoint.x - box.offset.x) <= box.size.x * 0.5f &&
Mathf.Abs(localPoint.y - box.offset.y) <= box.size.y * 0.5f;
}
return _collider.OverlapPoint(point);
}
private void OnDrawGizmos()