IAccumulator
Two custom jobs which can simplify creating behaviors use implementations of IAccumulator. Types implementing this interface must be included as generic parameters for implementations of INeighborBehaviorJob<C1, C2, A, R> and IRaycastBehaviorJob<C, A1, A2, R>.
Overview
Their purpose is to accumulate sub-results per entity which can be turned into a VelocityResult afterwards. For example in the case of INeighborBehaviorJob<C1, C2, A, R>, it's Execute method is called once per each entity neighbor pair. Accumulators keep track of some state between the call per entity. The following is pseudo code of how accumulators are used internally.
foreach entity in entities:
accumulator = new().Init()
foreach neighbor in entity.neighbors:
job.Execute(entity, neighbor, accumulator)
job.Finalize(entity, accumulator)
Example
For example, to create a cohesion behavior, a centroid (average position) of all neighbors is calculated first. This could be implemented with the following implementation of IAccumulator and INeighborBehaviorJob<C1, C2, SimpleAccumulator, VelocityResult>.
The implementation in the defaults library actually uses weighted average of positions. For the sake of simplicity, average of positions (centroid) is used in the following example.
public struct CentroidAccumulator : IAccumulator
{
public float3 SumPosition;
public int NumNeighbors;
public void Add(float3 position)
{
SumPosition += position;
NumNeighbors++;
}
public void Init()
{
SumPosition = new float3();
NumNeighbors = 0;
}
public float3 CalculateCentroid()
{
return SumPosition / NumNeighbors;
}
}
struct CohesionJob : INeighborBehaviorJob<C1, C2, SimpleAccumulator, VelocityResult>
{
public void Execute(in NeighborBehaviorData<C1, C2> pair, ref CentroidAccumulator accumulator)
{
// pass in position of the neighbor
accumulator.Add(pair.OtherEntity.Position);
}
public VelocityResult Finalize(in EntityInformation<C1> entity, in CentroidAccumulator accumulator)
{
float3 centroid = accumulator.CalculateCentroid();
float3 toCentroid = centroid - entity.Position
... // rest of the behavior
}
}