using Unity.Mathematics; using UnityEngine; using UnityEngine.Pool; using Random = UnityEngine.Random; namespace DanieleMarotta.RiversongCodeShowcase { [GameSystemGroup(typeof(EarlyAgentsSystemGroup))] public class CritterSpawnSystem : GameSystem, IUpdatable { [InjectService] private World _world; [InjectService] private IEntityCollection _entityCollection; [InjectService] private IAgentFactory _agentFactory; [InjectService] private ITileSpace _tileSpace; public CritterSpawnSystem(IServiceLocator serviceLocator) : base(serviceLocator) { } public void Update() { foreach (CritterHerd herd in _entityCollection.GetInternalEntityList(typeof(CritterHerd))) { ref var agentSourceState = ref herd.GetAgentSourceStateRW(); if (agentSourceState.AgentCount[(int)AgentJob.None] >= herd.MaxCritterCount) { herd.SpawnTimer = float.MinValue; continue; } var critterDefinition = herd.CritterDefinition; if (herd.SpawnTimer < 0) herd.SpawnTimer = Random.Range(critterDefinition.MinSpawningInterval, critterDefinition.MaxSpawningInterval); herd.SpawnTimer -= Time.deltaTime; if (herd.SpawnTimer <= 0) { herd.SpawnTimer = float.MinValue; var wanderingRadius = critterDefinition.AgentDefinition.WanderingRadius; if (!TryFindRandomFreeTile(herd.Center - wanderingRadius, herd.Center + wanderingRadius, out var tile)) continue; var position = _tileSpace.TileToWorld(tile); var critter = _agentFactory.CreateCritter(critterDefinition, herd, position); critter.WanderingCenter = tile; ref var intentQueue = ref critter.GetIntentQueueRW(); intentQueue.EnqueueIntent(AgentIntent.MakeLive()); IntentQueue.LoopWandering(ref intentQueue, 0); } } } private bool TryFindRandomFreeTile(int2 min, int2 max, out int2 tile) { using var candidatesScope = ListPool.Get(out var candidates); foreach (var candidate in TileRange.From(min, max)) if (!_world.BlockMap.IsBlocked(candidate, BlockReason.BlocksAgents)) candidates.Add(candidate); if (candidates.Count == 0) { tile = int2.zero; return false; } tile = candidates[Random.Range(0, candidates.Count)]; return true; } } }