riversong code showcase

This commit is contained in:
Daniele Marotta
2026-05-21 15:52:18 +02:00
commit 4c9eea1c02
462 changed files with 23406 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[CreateAssetMenu(fileName = "CritterDefinition", menuName = "Riversong Code Showcase/Critter Definition")]
public class CritterDefinition : GameDataAsset
{
public AgentDefinition AgentDefinition;
public int MinCritterCount = 5;
public int MaxCritterCount = 15;
public float MinSpawningInterval = 10;
public float MaxSpawningInterval = 15;
public ProductDefinition Product;
public int MinProductAmount = 3;
public int MaxProductAmount = 5;
}
}

View File

@@ -0,0 +1,24 @@
using Unity.Mathematics;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class CritterHerd : Entity, IAgentSourceEntity
{
private AgentSourceState _agentsState;
public CritterDefinition CritterDefinition { get; set; }
public int2 Center { get; set; }
public int MaxCritterCount { get; set; }
public float SpawnTimer { get; set; }
public float SpawnCooldown => 0;
public ref AgentSourceState GetAgentSourceStateRW()
{
return ref _agentsState;
}
}
}

View File

@@ -0,0 +1,37 @@
using Random = UnityEngine.Random;
namespace DanieleMarotta.RiversongCodeShowcase
{
[GameSystemGroup(typeof(DefaultAgentsSystemGroup))]
public class CritterHerdMoveCenterSystem : GameSystem, IUpdatable
{
[InjectService]
private IEntityCollection _entityCollection;
[InjectService]
private World _world;
[InjectService]
private ISignalBus _signalBus;
public CritterHerdMoveCenterSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public void Update()
{
foreach (CritterHerd herd in _entityCollection.GetInternalEntityList(typeof(CritterHerd)))
{
if (!_world.BlockMap.IsBlocked(herd.Center, BlockReason.BlocksAgents)) continue;
var oldCenter = herd.Center;
var moveDirection = ((Directions)Random.Range(0, 8)).ToVector();
var center = oldCenter + 4 * moveDirection;
if (!_world.Contains(center) || _world.BlockMap.IsBlocked(center, BlockReason.BlocksAgents)) continue;
herd.Center = center;
}
}
}
}

View File

@@ -0,0 +1,80 @@
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<int2>.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;
}
}
}

View File

@@ -0,0 +1,11 @@
namespace DanieleMarotta.RiversongCodeShowcase
{
public struct CritterState
{
public bool IsCritter;
public int CritterDefinitionId;
public int LockId;
}
}

View File

@@ -0,0 +1,48 @@
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[GameSystemGroup(typeof(DefaultAgentsSystemGroup))]
[UpdateAfter(typeof(AgentManagerSystem))]
[UpdateBefore(typeof(AgentsCleanUpSystem))]
public class SpawnProductStackAfterCritterDeathSystem : GameSystem, IUpdatable
{
[InjectService]
private IEntityCollection _entityCollection;
[InjectService]
private ITileSpace _tileSpace;
[InjectService]
private IProductStackFactory _productStackFactory;
[InjectService]
private World _world;
public SpawnProductStackAfterCritterDeathSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public void Update()
{
foreach (CritterHerd herd in _entityCollection.GetInternalEntityList(typeof(CritterHerd)))
{
ref var agentSourceState = ref herd.GetAgentSourceStateRW();
foreach (var critterId in agentSourceState.AgentIds)
{
var critter = _entityCollection.Get<Agent>(critterId);
if (critter.LifecycleState != AgentLifecycleState.DeSpawning) continue;
var tile = _tileSpace.WorldToTile(critter.Position);
if (_world.BlockMap.IsBlocked(tile, BlockReason.BlocksAgents)) continue;
var product = herd.CritterDefinition.Product;
var amount = Random.Range(herd.CritterDefinition.MinProductAmount, herd.CritterDefinition.MaxProductAmount + 1);
_productStackFactory.CreateOrMerge(tile, product, amount);
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[GameSystemGroup(typeof(DefaultAgentsSystemGroup))]
public class UnlockCrittersSystem : GameSystem, IUpdatable
{
[InjectService]
private IEntityCache _entityCache;
[InjectService]
private IEntityCollection _entityCollection;
[InjectService]
private IIntentLogicExecutor _intentLogicExecutor;
public UnlockCrittersSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public void Update()
{
foreach (var critter in _entityCache.GetCritterAgents())
{
ref var critterState = ref critter.GetCritterStateRW();
if (critterState.LockId == Entity.InvalidId || _entityCollection.Exists(critterState.LockId)) continue;
Debug.LogError($"Invalid lock id {critterState.LockId} on critter {critter.Id}");
critterState.LockId = Entity.InvalidId;
ref var intentQueue = ref _intentLogicExecutor.CancelRemainingIntents(critter);
IntentQueue.LoopWandering(ref intentQueue, 0);
}
}
}
}

View File

@@ -0,0 +1,10 @@
using System.Collections.Generic;
using Unity.Mathematics;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class WorldCritterHerdsState
{
public List<int2> EligibleCenters { get; } = new();
}
}