root/src/BRAINSFramework/Locomotion/LocomtionSteering.cs
| 13 | 23 | ||
|---|---|---|---|
4 | using System.Text; | 4 | using System.Text; |
5 | using Microsoft.Xna.Framework; | 5 | using Microsoft.Xna.Framework; |
6 | using Brains.Framework.Utility; | 6 | using Brains.Framework.Utility; |
7 | using Brains.Grouping; | ||
7 | 8 | ||
8 | namespace Brains.Framework.Locomotion | 9 | namespace Brains.Framework.Locomotion |
9 | { | 10 | { |
... | ... | ||
16 | private static Random rand = new Random(); | 17 | private static Random rand = new Random(); |
17 | private Vector2 _wanderTarget; | 18 | private Vector2 _wanderTarget; |
18 | 19 | ||
19 | public const float WanderRadius = 1.2f; | 20 | public const float WanderRadius = 20; |
20 | public const float WanderDistance = 2.0f; | 21 | public const float WanderDistance = 30; |
21 | public const float WanderJitter = 80; | 22 | public const float WanderJitter = 80; |
22 | 23 | ||
23 | public enum Deceleration | 24 | public enum Deceleration |
... | ... | ||
35 | Flee= 0x00004, | 36 | Flee= 0x00004, |
36 | Arrive= 0x00008, | 37 | Arrive= 0x00008, |
37 | Wander = 0x00010, | 38 | Wander = 0x00010, |
38 | //Cohesion= 0x00020, | 39 | Cohesion= 0x00020, |
39 | //Seperation= 0x00040, | 40 | Seperation= 0x00040, |
40 | //Alignment = 0x00080, | 41 | Alignment = 0x00080, |
41 | //ObstacleAvoidance= 0x00100, | 42 | //ObstacleAvoidance= 0x00100, |
42 | //WallAvoidance = 0x00200, | 43 | //WallAvoidance = 0x00200, |
43 | //FollowPath = 0x00400, | 44 | //FollowPath = 0x00400, |
... | ... | ||
85 | { | 86 | { |
86 | TurnOff(BehaviorType.Wander); | 87 | TurnOff(BehaviorType.Wander); |
87 | } | 88 | } |
88 | | 89 | |
90 | public void TurnOnSeperation() | ||
91 | { | ||
92 | TurnOn(BehaviorType.Seperation); | ||
93 | } | ||
94 | public void TurnOffSeperation() | ||
95 | { | ||
96 | TurnOff(BehaviorType.Seperation); | ||
97 | } | ||
98 | public void TurnOnCohesion() | ||
99 | { | ||
100 | TurnOn(BehaviorType.Cohesion); | ||
101 | } | ||
102 | public void TurnOffCohesion() | ||
103 | { | ||
104 | TurnOff(BehaviorType.Cohesion); | ||
105 | } | ||
106 | public void TurnOnAlignment() | ||
107 | { | ||
108 | TurnOn(BehaviorType.Alignment); | ||
109 | } | ||
110 | public void TurnOffAlignment() | ||
111 | { | ||
112 | TurnOff(BehaviorType.Alignment); | ||
113 | } | ||
114 | |||
89 | public void TurnOnOffsetPursuit(Vector2 seek) | 115 | public void TurnOnOffsetPursuit(Vector2 seek) |
90 | { | 116 | { |
91 | 117 | ||
... | ... | ||
120 | private float ObstacleAvoidanceWeight=10; | 146 | private float ObstacleAvoidanceWeight=10; |
121 | private Vector2 SteeringForce = Vector2.Zero; | 147 | private Vector2 SteeringForce = Vector2.Zero; |
122 | private Vector2 Heading; | 148 | private Vector2 Heading; |
123 | private float MaxForce = 4; | 149 | private float MaxForce = 2; |
124 | private Vector2 Velocity; | 150 | private Vector2 Velocity; |
125 | private BehaviorType _behaviorFlags; | 151 | private BehaviorType _behaviorFlags; |
126 | 152 | ||
... | ... | ||
128 | public float SeekWeight = 1; | 154 | public float SeekWeight = 1; |
129 | public float ArriveWeight= 1; | 155 | public float ArriveWeight= 1; |
130 | public float WanderWeight= 1; | 156 | public float WanderWeight= 1; |
157 | public float SeperationWeight= 2; | ||
158 | public float AlignmentWeight= 1; | ||
159 | public float CohesionWeight = 1; | ||
131 | 160 | ||
132 | public Vector2 SeekPos { get; set; } | 161 | public Vector2 SeekPos { get; set; } |
133 | public Deceleration DecelerationSpeed { get; set; } | 162 | public Deceleration DecelerationSpeed { get; set; } |
... | ... | ||
139 | public override void Update(Microsoft.Xna.Framework.GameTime gameTime) | 168 | public override void Update(Microsoft.Xna.Framework.GameTime gameTime) |
140 | { | 169 | { |
141 | timeElapsed = gameTime.GetElapsed(); | 170 | timeElapsed = gameTime.GetElapsed(); |
171 | |||
142 | SteeringUpdate(gameTime.GetElapsed()); | 172 | SteeringUpdate(gameTime.GetElapsed()); |
143 | } | 173 | } |
144 | 174 | ||
145 | | ||
146 | |||
147 | private void SteeringUpdate(float elapsed) | 175 | private void SteeringUpdate(float elapsed) |
148 | { | 176 | { |
149 | Vector2 OldPos = Owner.Position; | 177 | Vector2 OldPos = Owner.Position; |
... | ... | ||
159 | SetHeading(Vector2.Normalize(Velocity)); | 187 | SetHeading(Vector2.Normalize(Velocity)); |
160 | } | 188 | } |
161 | Owner.Position += Velocity * elapsed; | 189 | Owner.Position += Velocity * elapsed; |
162 | Owner.Orientation = Heading;// (float)Math.Atan2(Heading.Y, Heading.X); | 190 | if(Heading!=Vector2.Zero) |
191 | Owner.Orientation = Heading;// (float)Math.Atan2(Heading.Y, Heading.X); | ||
163 | } | 192 | } |
164 | 193 | ||
165 | private void SetHeading(Vector2 new_heading) | 194 | private void SetHeading(Vector2 new_heading) |
... | ... | ||
207 | 236 | ||
208 | private Vector2 CalculatePrioritized() | 237 | private Vector2 CalculatePrioritized() |
209 | { | 238 | { |
210 | 239 | | |
211 | Vector2 force = Vector2.Zero; | 240 | Vector2 force = Vector2.Zero; |
212 | 241 | ||
242 | if (On(BehaviorType.Seperation)) | ||
243 | { | ||
244 | force = Separation() * SeperationWeight; | ||
245 | |||
246 | if (!AccumulateForce(ref _steeringForce, force)) return _steeringForce; | ||
247 | } | ||
248 | if (On(BehaviorType.Alignment)) | ||
249 | { | ||
250 | force = Alignment() * AlignmentWeight; | ||
251 | |||
252 | if (!AccumulateForce(ref _steeringForce, force)) return _steeringForce; | ||
253 | } | ||
254 | if (On(BehaviorType.Cohesion)) | ||
255 | { | ||
256 | force = Cohesion() * CohesionWeight; | ||
257 | |||
258 | if (!AccumulateForce(ref _steeringForce, force)) return _steeringForce; | ||
259 | } | ||
260 | |||
213 | if (On(BehaviorType.Seek)) | 261 | if (On(BehaviorType.Seek)) |
214 | { | 262 | { |
215 | force = Seek(SeekPos); | 263 | force = Seek(SeekPos); |
... | ... | ||
237 | return _steeringForce; | 285 | return _steeringForce; |
238 | } | 286 | } |
239 | 287 | ||
288 | private Vector2 Cohesion() | ||
289 | { | ||
290 | if (Owner.GetLabel(AIConsts.ISGROUPMEMBER) == 0) | ||
291 | return Vector2.Zero; | ||
292 | Group g = Owner.ParentWorld.GetGroup(Owner.GetLabel(AIConsts.GROUPID)); | ||
293 | |||
294 | //first find the center of mass of all the agents | ||
295 | Vector2 CenterOfMass=Vector2.Zero; | ||
296 | Vector2 SteeringForce=Vector2.Zero; | ||
297 | |||
298 | int NeighborCount = 0; | ||
299 | |||
300 | //iterate through the neighbors and sum up all the position vectors | ||
301 | for (int a = 0; a < g.Agents.Count; ++a) | ||
302 | { | ||
303 | //make sure *this* agent isn't included in the calculations and that | ||
304 | //the agent being examined is a neighbor | ||
305 | if ((g.Agents[a] != Owner))// && neighbors[a]->IsTagged()) | ||
306 | { | ||
307 | CenterOfMass += g.Agents[a].Position; | ||
308 | |||
309 | ++NeighborCount; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | if (NeighborCount > 0) | ||
314 | { | ||
315 | //the center of mass is the average of the sum of positions | ||
316 | CenterOfMass /= (float)NeighborCount; | ||
317 | |||
318 | //now seek toward that position | ||
319 | SteeringForce = Seek(CenterOfMass); | ||
320 | } | ||
321 | |||
322 | return SteeringForce; | ||
323 | |||
324 | } | ||
325 | |||
326 | private Vector2 Alignment() | ||
327 | { | ||
328 | if (Owner.GetLabel(AIConsts.ISGROUPMEMBER) == 0) | ||
329 | return Vector2.Zero; | ||
330 | Group g = Owner.ParentWorld.GetGroup(Owner.GetLabel(AIConsts.GROUPID)); | ||
331 | |||
332 | |||
333 | //used to record the average heading of the neighbors | ||
334 | Vector2 AverageHeading = Vector2.Zero; | ||
335 | |||
336 | //used to count the number of vehicles in the neighborhood | ||
337 | int NeighborCount = 0; | ||
338 | |||
339 | //iterate through all the tagged vehicles and sum their heading vectors | ||
340 | for (int a = 0; a < g.Agents.Count; ++a) | ||
341 | { | ||
342 | //make sure *this* agent isn't included in the calculations and that | ||
343 | //the agent being examined is close enough | ||
344 | if ((g.Agents[a] != Owner))// && g.Agents[a]->IsTagged) | ||
345 | { | ||
346 | AverageHeading += g.Agents[a].Orientation; | ||
347 | |||
348 | ++NeighborCount; | ||
349 | } | ||
350 | } | ||
351 | |||
352 | //if the neighborhood contained one or more vehicles, average their | ||
353 | //heading vectors. | ||
354 | if (NeighborCount > 0) | ||
355 | { | ||
356 | AverageHeading /= (float)NeighborCount; | ||
357 | AverageHeading -= Owner.Orientation; | ||
358 | } | ||
359 | |||
360 | return AverageHeading; | ||
361 | |||
362 | } | ||
363 | |||
364 | private Vector2 Separation() | ||
365 | { | ||
366 | if (Owner.GetLabel(AIConsts.ISGROUPMEMBER) == 0) | ||
367 | return Vector2.Zero; | ||
368 | Group g = Owner.ParentWorld.GetGroup(Owner.GetLabel(AIConsts.GROUPID)); | ||
369 | |||
370 | Vector2 SteeringForce = Vector2.Zero; | ||
371 | |||
372 | for (int a = 0; a < g.Agents.Count; ++a) | ||
373 | { | ||
374 | //make sure this agent isn't included in the calculations and that | ||
375 | //the agent being examined is close enough. | ||
376 | if ((g.Agents[a] != Owner)) // && g.Agents[a]->IsTagged()) | ||
377 | { | ||
378 | Vector2 ToAgent = Owner.Position - g.Agents[a].Position; | ||
379 | if (ToAgent == Vector2.Zero) | ||
380 | continue; | ||
381 | //scale the force inversely proportional to the agent's distance | ||
382 | //from its neighbor. | ||
383 | SteeringForce +=Vector2.Normalize(ToAgent) / ToAgent.Length(); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | return SteeringForce; | ||
388 | |||
389 | } | ||
390 | |||
240 | 391 | ||
241 | 392 | ||
242 | private bool AccumulateForce(ref Vector2 sf, Vector2 ForceToAdd) | 393 | private bool AccumulateForce(ref Vector2 sf, Vector2 ForceToAdd) |
... | ... | ||
313 | 464 | ||
314 | public Vector2 Wander() | 465 | public Vector2 Wander() |
315 | { | 466 | { |
316 | double JitterThisTimeSlice = WanderJitter * timeElapsed; | 467 | float JitterThisTimeSlice = WanderJitter * timeElapsed; |
317 | 468 | ||
318 | //first, add a small random vector to the target's position (RandomClamped | 469 | //first, add a small random vector to the target's position (RandomClamped |
319 | //returns a value between -1 and 1) | 470 | //returns a value between -1 and 1) |
320 | _wanderTarget+= new Vector2(RandomClamped() * WanderJitter, | 471 | _wanderTarget += new Vector2(RandomClamped() * JitterThisTimeSlice, |
321 | RandomClamped() * WanderJitter); | 472 | RandomClamped() * JitterThisTimeSlice); |
322 | 473 | ||
323 | if (_wanderTarget != Vector2.Zero) //reproject this new vector back on to a unit circle | 474 | if (_wanderTarget != Vector2.Zero) //reproject this new vector back on to a unit circle |
324 | _wanderTarget.Normalize(); | 475 | _wanderTarget.Normalize(); |
... | ... | ||
382 | float RandomClamped() | 533 | float RandomClamped() |
383 | { | 534 | { |
384 | return rand.Next() - rand.Next(); | 535 | return rand.Next() - rand.Next(); |
385 | } | 536 | } |
537 | |||
386 | } | 538 | } |
387 | } | 539 | } |
Download diff