riversong code showcase
This commit is contained in:
179
Source/Riversong/Game/World/Agents/AgentCommonLogicSystem.cs
Normal file
179
Source/Riversong/Game/World/Agents/AgentCommonLogicSystem.cs
Normal file
@@ -0,0 +1,179 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace DanieleMarotta.RiversongCodeShowcase
|
||||
{
|
||||
[BurstCompile]
|
||||
[Service(typeof(IAgentCommonLogic))]
|
||||
[GameSystemGroup(typeof(AgentsSystemGroup))]
|
||||
public class AgentCommonLogicSystem : GameSystem, IAgentCommonLogic
|
||||
{
|
||||
private const float RotationSpeed = 270 * math.TORADIANS;
|
||||
|
||||
[InjectService]
|
||||
private GameConfig _config;
|
||||
|
||||
[InjectService]
|
||||
private ITileSpace _tileSpace;
|
||||
|
||||
[InjectService]
|
||||
private IBuildingSpatialQuery _buildingSpatialQuery;
|
||||
|
||||
[InjectService]
|
||||
private IAgentFactory _agentFactory;
|
||||
|
||||
public AgentCommonLogicSystem(IServiceLocator serviceLocator) : base(serviceLocator)
|
||||
{
|
||||
}
|
||||
|
||||
public bool MoveAgent(Agent agent, float3 targetPosition, float dt)
|
||||
{
|
||||
var position = agent.Position;
|
||||
var heading = agent.Heading;
|
||||
|
||||
var oldPosition = position;
|
||||
var targetReached = MoveAgent(targetPosition, dt, _config.Agents.MoveSpeed, ref position, ref heading);
|
||||
|
||||
agent.Position = position;
|
||||
agent.Heading = heading;
|
||||
agent.Velocity = dt > 0 ? (position - oldPosition) / dt : 0;
|
||||
|
||||
return targetReached;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private static bool MoveAgent(in float3 targetPosition, float dt, float speed, ref float3 position, ref float3 heading)
|
||||
{
|
||||
var positionDelta = targetPosition - position;
|
||||
var targetHeading = math.normalizesafe(positionDelta, heading);
|
||||
var movementLength = speed * dt;
|
||||
|
||||
const float targetOvershoot = 1.1f;
|
||||
var targetReachedThreshold = movementLength * targetOvershoot;
|
||||
var snapPosition = math.lengthsq(positionDelta) < targetReachedThreshold * targetReachedThreshold;
|
||||
position = math.select(position + targetHeading * movementLength, targetPosition, snapPosition);
|
||||
|
||||
var snapHeading = UpdateHeading(ref heading, targetHeading, RotationSpeed * dt);
|
||||
heading = math.select(heading, targetHeading, snapHeading);
|
||||
|
||||
return snapPosition && snapHeading;
|
||||
}
|
||||
|
||||
public bool UpdateHeading(Agent agent, in float3 targetHeading, float dt)
|
||||
{
|
||||
var heading = agent.Heading;
|
||||
var headingReached = UpdateHeading(ref heading, targetHeading, RotationSpeed * dt);
|
||||
agent.Heading = heading;
|
||||
return headingReached;
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private static bool UpdateHeading(ref float3 heading, in float3 targetHeading, float maxRadiansDelta)
|
||||
{
|
||||
var q0 = quaternion.LookRotationSafe(heading, math.up());
|
||||
var q1 = quaternion.LookRotationSafe(targetHeading, math.up());
|
||||
|
||||
var angle = math.angle(q0, q1);
|
||||
if (angle < maxRadiansDelta)
|
||||
{
|
||||
heading = targetHeading;
|
||||
return true;
|
||||
}
|
||||
|
||||
var t = math.min(1, maxRadiansDelta / angle);
|
||||
var q = math.slerp(q0, q1, t);
|
||||
|
||||
heading = math.rotate(q, math.forward());
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryFetchProductFromStorage(AgentDefinition agentDefinition,
|
||||
Building source,
|
||||
int productHandle,
|
||||
int neededAmount,
|
||||
int maxAgentCount = int.MaxValue,
|
||||
AgentJob job = AgentJob.None)
|
||||
{
|
||||
ref var sourceStorage = ref source.GetStorageRW();
|
||||
return sourceStorage.CountIncludingReservations(productHandle) < neededAmount &&
|
||||
TryFindFetchStorage(source, productHandle, out var fetchBuilding) &&
|
||||
TryFetchProduct(agentDefinition, source, fetchBuilding, productHandle, 1, maxAgentCount, job);
|
||||
}
|
||||
|
||||
public bool TryFetchProductFromProvider(AgentDefinition agentDefinition,
|
||||
Building source,
|
||||
int productHandle,
|
||||
int neededAmount,
|
||||
int maxAgentCount = int.MaxValue,
|
||||
AgentJob job = AgentJob.None)
|
||||
{
|
||||
ref var sourceStorage = ref source.GetStorageRW();
|
||||
return sourceStorage.CountIncludingReservations(productHandle) < neededAmount &&
|
||||
_buildingSpatialQuery.FindProviderForFetch(source.Id, source.Rect, productHandle, out var fetchBuilding) &&
|
||||
TryFetchProduct(agentDefinition, source, fetchBuilding, productHandle, 1, maxAgentCount, job);
|
||||
}
|
||||
|
||||
public bool TryFetchProduct(AgentDefinition agentDefinition,
|
||||
Building source,
|
||||
Building fetchBuilding,
|
||||
int productHandle,
|
||||
int amount,
|
||||
int maxAgentCount = int.MaxValue,
|
||||
AgentJob job = AgentJob.None)
|
||||
{
|
||||
if (!_agentFactory.CanSpawnAgent(source, maxAgentCount, job)) return false;
|
||||
|
||||
ref var sourceStorage = ref source.GetStorageRW();
|
||||
if (sourceStorage.FreeSpace() < amount) return false;
|
||||
|
||||
ref var fetchStorage = ref fetchBuilding.GetStorageRW();
|
||||
if (fetchStorage.AvailableNow(productHandle) < amount) return false;
|
||||
|
||||
sourceStorage.ReservePutting(productHandle, amount);
|
||||
fetchStorage.ReserveTaking(productHandle, amount);
|
||||
|
||||
var position = _tileSpace.TileToWorld(source.Rect.Center);
|
||||
var agent = _agentFactory.CreateVillager(agentDefinition, source, position, job);
|
||||
IntentQueue.Fetch(ref agent.GetIntentQueueRW(), source.Rect, source.Id, fetchBuilding.Rect, fetchBuilding.Id, productHandle, amount, PathTraversalRules.TransportAgent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryDeliverProduct(AgentDefinition agentDefinition, Building source, int productHandle, int maxAgentCount = int.MaxValue, AgentJob job = AgentJob.None)
|
||||
{
|
||||
if (!_agentFactory.CanSpawnAgent(source, maxAgentCount, job)) return false;
|
||||
|
||||
ref var sourceStorage = ref source.GetStorageRW();
|
||||
if (sourceStorage.AvailableNow(productHandle) <= 0) return false;
|
||||
|
||||
if (!_buildingSpatialQuery.FindStorageForDelivery(source.Id, source.Rect, productHandle, out var deliveryStorage)) return false;
|
||||
|
||||
sourceStorage.ReserveTaking(productHandle, 1);
|
||||
|
||||
ref var destinationStorage = ref deliveryStorage.GetStorageRW();
|
||||
destinationStorage.ReservePutting(productHandle, 1);
|
||||
|
||||
var position = _tileSpace.TileToWorld(source.Rect.Center);
|
||||
var deliveryAgent = _agentFactory.CreateVillager(agentDefinition, source, position, job);
|
||||
IntentQueue.Deliver(
|
||||
ref deliveryAgent.GetIntentQueueRW(),
|
||||
source.Rect,
|
||||
source.Id,
|
||||
deliveryStorage.Rect,
|
||||
deliveryStorage.Id,
|
||||
productHandle,
|
||||
1,
|
||||
PathTraversalRules.TransportAgent);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryFindFetchStorage(Building source, int productHandle, out Building fetchBuilding)
|
||||
{
|
||||
if (source.Definition.ProvidedProducts.Count > 0)
|
||||
return _buildingSpatialQuery.FindStorageForFetch(source.Id, source.Rect, source.Definition.Range, productHandle, out fetchBuilding);
|
||||
|
||||
return _buildingSpatialQuery.FindStorageForFetch(source.Id, source.Rect, productHandle, out fetchBuilding);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user