new spawning manager, spawner improvements - now with multiple enemies to spawn, KillTrigger
This commit is contained in:
@@ -1,171 +1,411 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Invector;
|
||||
using Invector; // Assuming this is for vDamage, if not used, can be removed
|
||||
using Invector.vCharacterController.AI;
|
||||
using PixelCrushers;
|
||||
using PixelCrushers; // For Saver and SaveSystem
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.AI; // Required for NavMesh
|
||||
|
||||
namespace Beyond
|
||||
{
|
||||
public class EnemySpawner : Saver
|
||||
{
|
||||
public GameObject m_prefab;
|
||||
public Transform m_distanceFrom;
|
||||
//public bool m_distanceFromMainCam;
|
||||
public float m_spawnCheckInterval = .5f;
|
||||
public float m_distance = 20f;
|
||||
public int m_numToSpawn = -1;
|
||||
public bool m_respawnOnPlayersDeath = true;
|
||||
public LayerMask raycastMask = 1; //default
|
||||
private SaveData m_spawnData;
|
||||
//private bool m_spawned;
|
||||
private vControlAI m_spawnedAI;
|
||||
public UnityEvent<EnemySpawner> m_OnDead;
|
||||
public UnityEvent<EnemySpawner> m_onReceivedDamage;
|
||||
class SaveData
|
||||
[Header("Spawning Configuration")]
|
||||
public GameObject m_prefab;
|
||||
public int m_enemiesPerSpawnWave = 3;
|
||||
public float m_spawnRadius = 5f;
|
||||
public int m_maxSpawnAttemptsPerEnemy = 10;
|
||||
public float m_navMeshSampleDistance = 1.0f;
|
||||
|
||||
[Header("Activation & Respawn")]
|
||||
public Transform m_distanceFrom;
|
||||
public float m_spawnCheckInterval = .5f;
|
||||
public float m_distance = 20f;
|
||||
|
||||
[Tooltip("Maximum number of times a full wave can be (re)spawned. Set to -1 for infinite respawns. This count increments each time a wave is successfully initiated.")]
|
||||
public int m_maxWaveRespawns = -1;
|
||||
|
||||
public bool m_respawnOnPlayersDeath = true;
|
||||
public LayerMask raycastMask = 1; // Default layer
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent<EnemySpawner> m_OnDead; // Invoked when an enemy spawned by THIS spawner dies
|
||||
public UnityEvent<EnemySpawner> m_onReceivedDamage; // Invoked when an enemy from THIS spawner receives damage
|
||||
|
||||
private SaveData m_spawnData;
|
||||
private List<vControlAI> m_activeEnemies = new List<vControlAI>();
|
||||
private bool _initialWaveCheckPassedThisActivation = false; // Flag to control CheckSpawn behavior per activation cycle
|
||||
|
||||
const float RAY_Y_OFFSET = 30f; // How high above candidate point to start raycast
|
||||
const float GROUND_Y_OFFSET = .1f; // How high above ground to place enemy pivot
|
||||
|
||||
// Internal class for saving spawner state
|
||||
class SaveData
|
||||
{
|
||||
public int wavesSpawnedCount;
|
||||
public bool waveActive;
|
||||
// Note: _initialWaveCheckPassedThisActivation is transient and reset based on game state, not directly saved.
|
||||
}
|
||||
|
||||
public override void Awake()
|
||||
{
|
||||
#if ENEMIES_DISABLED && UNITY_EDITOR
|
||||
enabled = false;
|
||||
return;
|
||||
#endif
|
||||
base.Awake(); // Important: Call Saver's Awake
|
||||
m_spawnData = new SaveData
|
||||
{
|
||||
wavesSpawnedCount = 0,
|
||||
waveActive = false
|
||||
};
|
||||
m_activeEnemies = new List<vControlAI>();
|
||||
_initialWaveCheckPassedThisActivation = false; // Initialize flag
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start(); // Important: Call Saver's Start
|
||||
|
||||
// Set up m_distanceFrom
|
||||
if (Player.Instance != null)
|
||||
m_distanceFrom = Player.Instance.transform;
|
||||
else if (Camera.main != null)
|
||||
m_distanceFrom = Camera.main.transform;
|
||||
else
|
||||
{
|
||||
Debug.LogError($"EnemySpawner ({name}): m_distanceFrom could not be set (Player.Instance and Camera.main are null). Disabling spawner.", this);
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Subscribe to player respawn events
|
||||
if (m_respawnOnPlayersDeath && Player.Instance != null)
|
||||
{
|
||||
var respawner = Player.Instance.GetComponent<Respawner>(); // Assuming PixelCrushers Respawner
|
||||
if (respawner != null)
|
||||
{
|
||||
respawner.m_onRespawned.AddListener(OnPlayerRespawned);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"EnemySpawner ({name}): Player.Instance does not have a Respawner component. m_respawnOnPlayersDeath will not function fully.", this);
|
||||
}
|
||||
}
|
||||
|
||||
// Start checking for spawn conditions
|
||||
InvokeRepeating("CheckSpawn", m_spawnCheckInterval + (Random.value * m_spawnCheckInterval), m_spawnCheckInterval);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
// Unsubscribe from player respawn events
|
||||
if (m_respawnOnPlayersDeath && Player.Instance != null)
|
||||
{
|
||||
var respawner = Player.Instance.GetComponent<Respawner>();
|
||||
if (respawner != null)
|
||||
{
|
||||
respawner.m_onRespawned.RemoveListener(OnPlayerRespawned);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up listeners from active enemies
|
||||
foreach (var ai in m_activeEnemies)
|
||||
{
|
||||
if (ai != null)
|
||||
{
|
||||
ai.onDead.RemoveListener(OnEnemyDead);
|
||||
ai.onReceiveDamage.RemoveListener(OnEnemyReceiveDamage);
|
||||
}
|
||||
}
|
||||
m_activeEnemies.Clear();
|
||||
|
||||
CancelInvoke("CheckSpawn"); // Ensure InvokeRepeating is stopped
|
||||
}
|
||||
|
||||
|
||||
private void OnPlayerRespawned()
|
||||
{
|
||||
if (!m_respawnOnPlayersDeath) return;
|
||||
|
||||
// If a wave was previously active and its enemies are now gone, mark the wave as inactive.
|
||||
if (m_spawnData.waveActive && m_activeEnemies.Count == 0)
|
||||
{
|
||||
m_spawnData.waveActive = false;
|
||||
}
|
||||
|
||||
// Reset the flag to allow CheckSpawn (or direct spawn here) to work for this new "life"
|
||||
_initialWaveCheckPassedThisActivation = false;
|
||||
|
||||
// Attempt to spawn a new wave if conditions are met
|
||||
if (!m_spawnData.waveActive && CanSpawnMoreWaves())
|
||||
{
|
||||
if (IsPlayerInRange())
|
||||
{
|
||||
SpawnWave();
|
||||
if (m_spawnData.waveActive) // If wave was successfully spawned by this call
|
||||
{
|
||||
_initialWaveCheckPassedThisActivation = true; // Mark as done for this cycle
|
||||
}
|
||||
}
|
||||
// else Debug.Log($"Player respawned, but spawner {name} is out of range. No wave spawned immediately by OnPlayerRespawned.");
|
||||
}
|
||||
// else if (m_spawnData.waveActive) Debug.Log($"Player respawned, but spawner {name} still has an active wave.");
|
||||
// else if (!CanSpawnMoreWaves()) Debug.Log($"Player respawned, but spawner {name} has reached its wave limit.");
|
||||
}
|
||||
|
||||
public override string RecordData()
|
||||
{
|
||||
return SaveSystem.Serialize(m_spawnData);
|
||||
}
|
||||
|
||||
public override void ApplyData(string s)
|
||||
{
|
||||
var data = SaveSystem.Deserialize<SaveData>(s);
|
||||
if (data != null)
|
||||
{
|
||||
m_spawnData = data;
|
||||
// If loaded save indicates a wave was active but no enemies are present (they weren't saved/restored),
|
||||
// mark wave as inactive.
|
||||
if (m_spawnData.waveActive && m_activeEnemies.Count == 0) // m_activeEnemies is runtime only
|
||||
{
|
||||
m_spawnData.waveActive = false;
|
||||
}
|
||||
|
||||
// Determine the state of _initialWaveCheckPassedThisActivation based on loaded data
|
||||
// If a wave was active, or any waves had been spawned, assume the "initial check" for the
|
||||
// current game session (before this load) effectively passed.
|
||||
// A Reset or PlayerRespawn will clear this flag if needed for a new cycle.
|
||||
if (m_spawnData.waveActive || m_spawnData.wavesSpawnedCount > 0) {
|
||||
_initialWaveCheckPassedThisActivation = true;
|
||||
} else {
|
||||
_initialWaveCheckPassedThisActivation = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAnyEnemyAlive()
|
||||
{
|
||||
return m_activeEnemies.Count > 0;
|
||||
}
|
||||
|
||||
public bool CanSpawnMoreWaves()
|
||||
{
|
||||
if (m_spawnData == null) return false;
|
||||
return m_maxWaveRespawns < 0 || m_spawnData.wavesSpawnedCount < m_maxWaveRespawns;
|
||||
}
|
||||
|
||||
public bool IsExhausted()
|
||||
{
|
||||
return !CanSpawnMoreWaves() && !IsAnyEnemyAlive();
|
||||
}
|
||||
public int GetWavesSpawnedCount()
|
||||
{
|
||||
public int numSpawned;
|
||||
public bool spawned;
|
||||
if (m_spawnData != null)
|
||||
{
|
||||
return m_spawnData.wavesSpawnedCount;
|
||||
}
|
||||
return 0; // Should ideally not happen if Awake ran
|
||||
}
|
||||
|
||||
public override void Awake()
|
||||
{
|
||||
#if ENEMIES_DISABLED && UNITY_EDITOR
|
||||
enabled = false;
|
||||
return;
|
||||
#endif
|
||||
base.Awake();
|
||||
//m_spawned = false;
|
||||
m_spawnData = new SaveData();
|
||||
m_spawnData.numSpawned = 0;
|
||||
m_spawnData.spawned = false;
|
||||
}
|
||||
public void SpawnWave()
|
||||
{
|
||||
if (m_prefab == null)
|
||||
{
|
||||
Debug.LogError($"EnemySpawner ({name}): m_prefab is not set!", this);
|
||||
return;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (m_respawnOnPlayersDeath && Player.Instance != null)
|
||||
{
|
||||
var respawner = Player.Instance.GetComponent<Respawner>();
|
||||
respawner.m_onRespawned.RemoveListener(OnPlayerRespawned);
|
||||
}
|
||||
|
||||
if (m_spawnedAI)
|
||||
{
|
||||
m_spawnedAI.onDead.RemoveListener(OnDead);
|
||||
}
|
||||
}
|
||||
if (!CanSpawnMoreWaves())
|
||||
{
|
||||
// This check is also in CheckSpawn/OnPlayerRespawned, but good for direct calls too
|
||||
// Debug.Log($"EnemySpawner ({name}): Max wave respawn limit reached or cannot spawn more waves.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
|
||||
base.Start();
|
||||
if (Player.Instance != null)
|
||||
m_distanceFrom = Player.Instance.transform;
|
||||
else
|
||||
{
|
||||
m_distanceFrom = Camera.main.transform;
|
||||
}
|
||||
if (m_spawnData.waveActive)
|
||||
{
|
||||
// Debug.Log($"EnemySpawner ({name}): Wave already active, not spawning another.", this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_respawnOnPlayersDeath)
|
||||
{
|
||||
var respawner = Player.Instance.GetComponent<Respawner>();
|
||||
respawner.m_onRespawned.AddListener(OnPlayerRespawned);
|
||||
}
|
||||
InvokeRepeating("CheckSpawn", m_spawnCheckInterval + (Random.value * m_spawnCheckInterval), m_spawnCheckInterval);
|
||||
}
|
||||
int enemiesSuccessfullySpawned = 0;
|
||||
for (int i = 0; i < m_enemiesPerSpawnWave; i++)
|
||||
{
|
||||
Vector3 spawnPosition = Vector3.zero;
|
||||
bool foundValidPosition = false;
|
||||
|
||||
void CheckRespawnCondition()
|
||||
{
|
||||
if ((m_numToSpawn < 0 || m_numToSpawn > m_spawnData.numSpawned) && m_spawnedAI == null )
|
||||
m_spawnData.spawned = false;
|
||||
|
||||
}
|
||||
private void OnPlayerRespawned()
|
||||
{
|
||||
CheckRespawnCondition();
|
||||
}
|
||||
for (int attempt = 0; attempt < m_maxSpawnAttemptsPerEnemy; attempt++)
|
||||
{
|
||||
Vector2 randomCircleOffset = Random.insideUnitCircle * m_spawnRadius;
|
||||
Vector3 candidateBasePosition = transform.position + new Vector3(randomCircleOffset.x, 0, randomCircleOffset.y);
|
||||
Vector3 raycastStartPos = candidateBasePosition + Vector3.up * RAY_Y_OFFSET;
|
||||
|
||||
public override string RecordData()
|
||||
{
|
||||
return SaveSystem.Serialize(m_spawnData);
|
||||
}
|
||||
RaycastHit hit;
|
||||
if (Physics.Raycast(raycastStartPos, Vector3.down, out hit, RAY_Y_OFFSET * 2, raycastMask))
|
||||
{
|
||||
Vector3 potentialSpawnPoint = hit.point + Vector3.up * GROUND_Y_OFFSET;
|
||||
NavMeshHit navHit;
|
||||
if (NavMesh.SamplePosition(potentialSpawnPoint, out navHit, m_navMeshSampleDistance, NavMesh.AllAreas))
|
||||
{
|
||||
spawnPosition = navHit.position;
|
||||
foundValidPosition = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void ApplyData(string s)
|
||||
{
|
||||
var data = SaveSystem.Deserialize<SaveData>(s);
|
||||
if (data != null)
|
||||
{
|
||||
m_spawnData = data;
|
||||
//m_spawned = true;
|
||||
CheckRespawnCondition();
|
||||
}
|
||||
}
|
||||
if (foundValidPosition)
|
||||
{
|
||||
GameObject enemyGO = Instantiate(m_prefab, spawnPosition, transform.rotation, transform);
|
||||
vControlAI spawnedAI = enemyGO.GetComponent<vControlAI>();
|
||||
if (spawnedAI != null)
|
||||
{
|
||||
m_activeEnemies.Add(spawnedAI);
|
||||
spawnedAI.onDead.AddListener(OnEnemyDead);
|
||||
spawnedAI.onReceiveDamage.AddListener(OnEnemyReceiveDamage);
|
||||
enemiesSuccessfullySpawned++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"EnemySpawner ({name}): Spawned prefab '{m_prefab.name}' does not have a vControlAI component!", enemyGO);
|
||||
Destroy(enemyGO);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"EnemySpawner ({name}): Failed to find a valid spawn position for an enemy after {m_maxSpawnAttemptsPerEnemy} attempts.", this);
|
||||
}
|
||||
}
|
||||
|
||||
public bool SpawnedAndLive()
|
||||
{
|
||||
return m_spawnedAI != null;
|
||||
}
|
||||
if (enemiesSuccessfullySpawned > 0)
|
||||
{
|
||||
m_spawnData.waveActive = true;
|
||||
m_spawnData.wavesSpawnedCount++;
|
||||
Debug.Log($"EnemySpawner ({name}): Spawned wave {m_spawnData.wavesSpawnedCount}/{(m_maxWaveRespawns < 0 ? "infinite" : m_maxWaveRespawns.ToString())} with {enemiesSuccessfullySpawned} enemies.", this);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No enemies were spawned in this attempt, so the wave isn't truly "active".
|
||||
// And we shouldn't count it towards wavesSpawnedCount if nothing came out.
|
||||
m_spawnData.waveActive = false;
|
||||
Debug.LogWarning($"EnemySpawner ({name}): Attempted to spawn a wave, but no enemies were successfully placed.", this);
|
||||
}
|
||||
}
|
||||
|
||||
public bool SpawnedAndDead()
|
||||
{
|
||||
return m_spawnData.spawned && m_spawnedAI == null;
|
||||
}
|
||||
private void OnEnemyReceiveDamage(vDamage damageData) // Assuming vDamage from Invector
|
||||
{
|
||||
m_onReceivedDamage?.Invoke(this);
|
||||
}
|
||||
|
||||
public void Spawn()
|
||||
{
|
||||
if (m_prefab == null)
|
||||
return;
|
||||
|
||||
Vector3 pos;
|
||||
const float RAY_OFFSET = 30f;
|
||||
const float Y_OFFSET = .1f;
|
||||
pos = transform.position;
|
||||
pos.y += RAY_OFFSET;
|
||||
RaycastHit hit = new RaycastHit();
|
||||
if (Physics.Raycast(pos, Vector3.down, out hit, 100f, raycastMask))
|
||||
{
|
||||
pos.y -= RAY_OFFSET;
|
||||
if (pos.y < hit.point.y + Y_OFFSET)
|
||||
{
|
||||
pos.y = hit.point.y + Y_OFFSET;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError("EnemySpawner error: raycast failed");
|
||||
return;
|
||||
}
|
||||
private void OnEnemyDead(GameObject deadEnemyObject)
|
||||
{
|
||||
vControlAI deadAI = deadEnemyObject.GetComponent<vControlAI>();
|
||||
if (deadAI != null && m_activeEnemies.Contains(deadAI))
|
||||
{
|
||||
deadAI.onDead.RemoveListener(OnEnemyDead);
|
||||
deadAI.onReceiveDamage.RemoveListener(OnEnemyReceiveDamage);
|
||||
m_activeEnemies.Remove(deadAI);
|
||||
m_OnDead?.Invoke(this);
|
||||
}
|
||||
|
||||
//m_spawned = true;
|
||||
m_spawnData.spawned = true;
|
||||
m_spawnData.numSpawned++;
|
||||
var enemy = Instantiate(m_prefab, pos, transform.rotation, transform);
|
||||
m_spawnedAI = enemy.GetComponent<vControlAI>();
|
||||
if (m_spawnedAI)
|
||||
{
|
||||
m_spawnedAI.onDead.AddListener(OnDead);
|
||||
m_spawnedAI.onReceiveDamage.AddListener(OnReceiveDamage);
|
||||
}
|
||||
if (m_activeEnemies.Count == 0 && m_spawnData.waveActive)
|
||||
{
|
||||
m_spawnData.waveActive = false; // Mark wave as inactive
|
||||
// DO NOT call CheckSpawn() here to prevent immediate respawn.
|
||||
// DO NOT reset _initialWaveCheckPassedThisActivation here. That's for new cycles (player respawn/reset).
|
||||
Debug.Log($"EnemySpawner ({name}): All enemies in wave died. Wave inactive. Waiting for player respawn or manual reset.", this);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsPlayerInRange()
|
||||
{
|
||||
if (m_distanceFrom == null) // Should be set in Start, but as a fallback
|
||||
{
|
||||
if (Player.Instance != null) m_distanceFrom = Player.Instance.transform;
|
||||
else if (Camera.main != null) m_distanceFrom = Camera.main.transform;
|
||||
else
|
||||
{
|
||||
// Debug.LogWarning($"EnemySpawner ({name}): Cannot check range, m_distanceFrom is null.", this);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return (transform.position - m_distanceFrom.position).sqrMagnitude < m_distance * m_distance;
|
||||
}
|
||||
|
||||
}
|
||||
public void CheckSpawn() // Called by InvokeRepeating
|
||||
{
|
||||
if (!enabled || !gameObject.activeInHierarchy || m_prefab == null) return;
|
||||
|
||||
private void OnReceiveDamage(vDamage arg0)
|
||||
{
|
||||
m_onReceivedDamage?.Invoke(this);
|
||||
}
|
||||
// If the "initial" spawn for this activation cycle has already happened (or attempted),
|
||||
// CheckSpawn should not try again until the cycle is reset (by player death or ResetSpawner).
|
||||
if (_initialWaveCheckPassedThisActivation)
|
||||
{
|
||||
// If a wave is active, great, CheckSpawn's job for this cycle is done.
|
||||
// If no wave is active BUT wavesSpawnedCount > 0, it means the wave spawned by this cycle died.
|
||||
// In this case, CheckSpawn also shouldn't immediately respawn.
|
||||
// It waits for OnPlayerRespawned or ResetSpawner to clear the flag.
|
||||
return;
|
||||
}
|
||||
|
||||
private void OnDead(GameObject arg0)
|
||||
{
|
||||
m_spawnedAI = null;
|
||||
m_OnDead?.Invoke(this);
|
||||
}
|
||||
// Try to spawn if: no wave active, can spawn more, player in range, AND initial check hasn't passed.
|
||||
if (!m_spawnData.waveActive && CanSpawnMoreWaves() && IsPlayerInRange())
|
||||
{
|
||||
SpawnWave();
|
||||
if (m_spawnData.waveActive) // If wave was successfully spawned
|
||||
{
|
||||
_initialWaveCheckPassedThisActivation = true; // Mark as done for this cycle
|
||||
}
|
||||
// If SpawnWave failed to actually spawn anyone (e.g. no valid spots),
|
||||
// waveActive will be false, and _initialWaveCheckPassedThisActivation will remain false,
|
||||
// allowing CheckSpawn to try again on the next interval.
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckSpawn(){
|
||||
if (!m_spawnData.spawned && gameObject.activeInHierarchy && (transform.position - m_distanceFrom.position).sqrMagnitude < m_distance * m_distance){
|
||||
Spawn();
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetSpawner()
|
||||
{
|
||||
CancelInvoke("CheckSpawn"); // Stop existing repeating call
|
||||
|
||||
// Destroy active enemies
|
||||
for (int i = m_activeEnemies.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (m_activeEnemies[i] != null)
|
||||
{
|
||||
m_activeEnemies[i].onDead.RemoveListener(OnEnemyDead);
|
||||
m_activeEnemies[i].onReceiveDamage.RemoveListener(OnEnemyReceiveDamage);
|
||||
Destroy(m_activeEnemies[i].gameObject);
|
||||
}
|
||||
}
|
||||
m_activeEnemies.Clear();
|
||||
|
||||
// Reset spawn data
|
||||
if (m_spawnData != null)
|
||||
{
|
||||
m_spawnData.wavesSpawnedCount = 0;
|
||||
m_spawnData.waveActive = false;
|
||||
}
|
||||
else // Should not happen if Awake ran
|
||||
{
|
||||
m_spawnData = new SaveData { wavesSpawnedCount = 0, waveActive = false };
|
||||
}
|
||||
|
||||
_initialWaveCheckPassedThisActivation = false; // Reset the flag for a new cycle
|
||||
|
||||
// Restart InvokeRepeating if spawner is active
|
||||
if (enabled && gameObject.activeInHierarchy)
|
||||
{
|
||||
// Re-initialize m_distanceFrom
|
||||
if (Player.Instance != null) m_distanceFrom = Player.Instance.transform;
|
||||
else if (Camera.main != null) m_distanceFrom = Camera.main.transform;
|
||||
|
||||
InvokeRepeating("CheckSpawn", m_spawnCheckInterval + (Random.value * m_spawnCheckInterval), m_spawnCheckInterval);
|
||||
Debug.Log($"Spawner ({name}) has been reset. CheckSpawn restarted. Will attempt to spawn when conditions met.", this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($"Spawner ({name}) has been reset but is currently disabled or inactive. CheckSpawn not restarted.", this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user