1 #include "agent_simulation_internal.h"
3 #include <bz/math/math.h>
4 #include <bz/math/random.h>
5 #include <bz/memory/allocator.h>
9 BZAgentDetails details
;
14 struct BZAgentSimulation
{
20 BZAgentSimulationID
bzFXCreateAgentSimulation(BZMemoryArenaID arena
, size_t maxAgents
, const char *identifierFmt
, ...) {
21 BZAgentSimulation
*simulation
= bzMemoryAlloc(arena
, sizeof(BZAgentSimulation
));
23 simulation
->maxAgents
= maxAgents
;
24 simulation
->agents
= bzMemoryAlloc(arena
, maxAgents
* sizeof(BZAgent
));
29 static void agentSeekForce(BZVector
*out
, BZAgent
*agent
, const BZVector
*seekTarget
) {
31 bzVectorSubtract(&delta
, seekTarget
, &agent
->details
.position
);
32 if (bzVectorMagnitudeSquared(&delta
) > 10.0f
* 10.0f
) { // FIXME
33 bzVectorNormalized(out
, &delta
);
34 bzVectorScale(out
, out
, agent
->details
.maxForce
); // FIXME
36 bzVectorSet(out
, 0, 0);
40 static void agentSeparationForce(BZVector
*out
, BZAgentSimulationID simulation
, BZAgent
*agent
) {
41 bzVectorSet(out
, 0, 0);
42 for (size_t i
= 0; i
< simulation
->agentCount
; ++i
) {
44 bzVectorSubtract(&delta
, &agent
->details
.position
, &simulation
->agents
[i
].details
.position
);
45 float squareDistance
= bzVectorMagnitudeSquared(&delta
);
46 float radius
= 50.0f
; // FIXME
48 if (squareDistance
> 0 && squareDistance
< radius
* radius
) {
50 bzVectorScale(&force
, &delta
, (radius
* radius
) / squareDistance
); // Square distance helps scale up/down avoidance
51 bzVectorAdd(out
, out
, &force
);
56 static void agentAlignmentForce(BZVector
*out
, BZAgentSimulationID simulation
, BZAgent
*agent
) {
57 BZVector averageForward
= bzVectorMake(0, 0);
58 size_t neighbourCount
= 0;
59 for (size_t i
= 0; i
< simulation
->agentCount
; ++i
) {
61 bzVectorSubtract(&delta
, &agent
->details
.position
, &simulation
->agents
[i
].details
.position
);
62 float squareDistance
= bzVectorMagnitudeSquared(&delta
);
63 float radius
= 150.0f
; // FIXME
65 if (squareDistance
> 0 && squareDistance
< radius
* radius
) {
67 bzVectorMakeAngle(&forward
, simulation
->agents
[i
].details
.angle
);
68 bzVectorAdd(&averageForward
, &averageForward
, &forward
);
73 if (neighbourCount
> 0) {
74 bzVectorNormalized(out
, &averageForward
); // FIXME, need to divide by number of agents? limit??
76 bzVectorSet(out
, 0, 0);
80 static void agentCohesionForce(BZVector
*out
, BZAgentSimulationID simulation
, BZAgent
*agent
) {
81 BZVector averagePosition
= bzVectorMake(0, 0);
82 size_t neighbourCount
= 0;
83 for (size_t i
= 0; i
< simulation
->agentCount
; ++i
) {
85 bzVectorSubtract(&delta
, &agent
->details
.position
, &simulation
->agents
[i
].details
.position
);
86 float squareDistance
= bzVectorMagnitudeSquared(&delta
);
87 float radius
= 150.0f
; // FIXME
89 if (squareDistance
> 0 && squareDistance
< radius
* radius
) {
90 bzVectorAdd(&averagePosition
, &averagePosition
, &simulation
->agents
[i
].details
.position
);
95 if (neighbourCount
> 0) {
96 bzVectorScale(&averagePosition
, &averagePosition
, 1.0f
/ neighbourCount
);
97 bzVectorSubtract(&averagePosition
, &averagePosition
, &agent
->details
.position
);
98 bzVectorNormalized(out
, &averagePosition
);
100 bzVectorSet(out
, 0, 0);
104 void bzFXUpdateAgentSimulation(BZAgentSimulationID simulation
, float deltaTime
, BZCollisionSpaceID collisionSpace
, BZVector
*v
) {
105 for (size_t i
= 0; i
< simulation
->agentCount
; ++i
) {
106 BZAgent
*agent
= &simulation
->agents
[i
];
109 agentSeekForce(&seekForce
, agent
, v
);
111 BZVector separationForce
;
112 agentSeparationForce(&separationForce
, simulation
, agent
);
114 BZVector alignmentForce
;
115 agentAlignmentForce(&alignmentForce
, simulation
, agent
);
117 BZVector cohesionForce
;
118 agentCohesionForce(&cohesionForce
, simulation
, agent
);
120 bzVectorSet(&agent
->force
, 0, 0);
121 bzVectorScale(&seekForce
, &seekForce
, 40.0f
);
122 bzVectorAdd(&agent
->force
, &agent
->force
, &seekForce
);
123 bzVectorScale(&separationForce
, &separationForce
, 100.0f
);
124 bzVectorAdd(&agent
->force
, &agent
->force
, &separationForce
);
125 bzVectorScale(&alignmentForce
, &alignmentForce
, 10.0f
);
126 bzVectorAdd(&agent
->force
, &agent
->force
, &alignmentForce
);
127 bzVectorScale(&cohesionForce
, &cohesionForce
, 10.0f
);
128 bzVectorAdd(&agent
->force
, &agent
->force
, &cohesionForce
);
130 // bzVectorScale(&agent->force, &agent->force, 36.0f);
132 float forceMagnitude
= bzVectorMagnitude(&agent
->force
);
133 forceMagnitude
= bzMin(forceMagnitude
, agent
->details
.maxForce
);
134 if (forceMagnitude
> 0.0f
) {
135 bzVectorNormalized(&agent
->force
, &agent
->force
);
136 bzVectorScale(&agent
->force
, &agent
->force
, forceMagnitude
);
137 bzVectorScale(&agent
->force
, &agent
->force
, 1.0f
/ agent
->details
.mass
);
140 bzVectorScale(&force
, &agent
->force
, deltaTime
);
141 bzVectorAdd(&agent
->velocity
, &agent
->velocity
, &force
);
142 // bzVectorCopy(&agent->velocity, &agent->force);
145 float velocityMagnitude
= bzVectorMagnitude(&agent
->velocity
);
146 velocityMagnitude
= bzMin(velocityMagnitude
, agent
->details
.maxSpeed
);
147 if (velocityMagnitude
> 0.0f
) {
148 bzVectorNormalized(&agent
->velocity
, &agent
->velocity
);
149 bzVectorScale(&agent
->velocity
, &agent
->velocity
, velocityMagnitude
);
153 bzVectorScale(&velocity
, &agent
->velocity
, deltaTime
);
154 bzVectorAdd(&agent
->details
.position
, &agent
->details
.position
, &velocity
);
156 // bzCollisionResolve()
160 BZAgentID
bzFXAgentSimulationAddAgent(BZAgentSimulationID simulation
, const BZAgentDetails
*details
) {
161 bzAssertMessage(simulation
->agentCount
< simulation
->maxAgents
, "No available agents");
163 BZAgent
*agent
= &simulation
->agents
[simulation
->agentCount
++];
165 agent
->details
= *details
;
166 //bzVectorSet(&agent->force, 0, 0);
167 bzVectorSet(&agent
->velocity
, bzRandomFloatRange(-10, 10), bzRandomFloatRange(-10, 10));
172 void bzFXAgentSimulationRemoveAgent(BZAgentSimulationID simulation
, BZAgentID agent
) {
173 agent
->agentIdx
= 0; // FIXME
176 void bzFXAgentSimulationGetAgentDetails(BZAgentDetails
*detailsOut
, BZAgentSimulationID simulation
, BZAgentID agent
) {
177 *detailsOut
= agent
->details
;
182 #include <bz/gfx/gfx.h>
183 void bzFXAgentSimulationDrawDebug(BZAgentSimulationID simulation
) {
184 for (size_t i
= 0; i
< simulation
->agentCount
; ++i
) {
185 BZAgent
*agent
= &simulation
->agents
[i
];
186 bzCirc(agent
->details
.position
.x
, agent
->details
.position
.y
, 2, 9);
189 bzVectorMakeAngle(&forward
, agent
->details
.angle
);
190 //bzLine(agent->details.position.x, agent->details.position.y, agent->details.position.x + forward.x * 40, agent->details.position.y + forward.y * 40, 7);
193 agent
->details
.position
.x
, agent
->details
.position
.y
,
194 agent
->details
.position
.x
+ agent
->velocity
.x
, agent
->details
.position
.y
+ agent
->velocity
.y
,
198 agent
->details
.position
.x
, agent
->details
.position
.y
,
199 agent
->details
.position
.x
+ agent
->force
.x
, agent
->details
.position
.y
+ agent
->force
.y
,