root/src/BRAINSFramework/Locomotion/LocomtionSteering.cs

1323
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
}