Author: conkerjo
(2009/07/01 23:02) Over 2 years ago
1
//****************************************************************//
2
//********************copyright Rik Dodsworth 2009****************//
3
4
//***************************free to use**************************//
5
6
//*******************please just leave this header****************//
7
//*************************for recognition************************//
8
9
10
11
using System;
12
using System.Collections.Generic;
13
using System.Linq;
...
26
using System.IO;
16
27
using System.Reflection;
17
28
using Brains.Framework.Designer;
18
19
using Brains.Framework.Map;
29
20
30
namespace Brains.Framework
21
31
{
22
32
/// <summary>
23
33
/// Class to represent an AI Agent. Add the Agent to a World
24
/// Represents an autonomous agent in the AI world.
34
/// </summary>
25
35
/// <remarks>You can implement your own Agent by inheriting from this class</remarks>
36
public class Agent
186
// - for each component calculate row and col
177
187
178
188
Vector2 vDistanceFromMapCenter = this.Position;
179
189
Grid map = ParentWorld.Map.Cluster[0];
180
Grid map = ParentWorld.Map.ClusterGrid.Grids[0];
190
float _hstep = (map.Width/ ((float)map.Cols));
181
191
float _vstep = (map.Height/ ((float)map.Rows));
182
192
float xComponent = (vDistanceFromMapCenter.X / _hstep) ;
183
224
}
215
225
public Grid GetGridAtPosition(Vector2 position)
216
226
217
227
foreach (var item in ParentWorld.Map.Cluster)
218
foreach (var item in ParentWorld.Map.ClusterGrid.Grids)
228
219
229
if (
220
230
(position.X > item.Position.X && position.X < (item.Position.X + item.Width)) &&
221
//****************************************************************//
using System;
14
using System.Text;
/// The main AI Engine.
/// Represents the main AI Engine.
/// Create an instance of this class and call update every frame to stimulate the world
public class AIEngine
15
using Brains.Framework.Behaviors.PathFinding;
using Microsoft.Xna.Framework;
namespace Brains.Framework.Behaviors
namespace Brains.Framework.Behaviors.PathFinding
using Brains.Framework.PathFinding;
40
<UseVSHostingProcess>false</UseVSHostingProcess>
41
<PlatformTarget>x86</PlatformTarget>
42
<XnaCompressContent>false</XnaCompressContent>
43
<DocumentationFile>bin\x86\Debug\Brains.Framework.xml</DocumentationFile>
</PropertyGroup>
44
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
45
<DebugType>pdbonly</DebugType>
46
87
<Compile Include="Behaviors\PathFinding\CyclicPathBehavior.cs" />
88
<Compile Include="Behaviors\PathFinding\FindPathBehavior.cs" />
89
<Compile Include="Behaviors\PathFinding\FollowPathBehavior.cs" />
90
<Compile Include="Consts.cs" />
91
<Compile Include="Utility\AIConsts.cs" />
92
<Compile Include="Map\Cluster.cs" />
<Compile Include="Designer\BehaviorNode.cs" />
93
<Compile Include="Behaviors\BehaviorBase.cs" />
94
<Compile Include="Behaviors\BehaviorList.cs" />
95
98
<Compile Include="Behaviors\IActionBehavior.cs" />
100
99
<Compile Include="Behaviors\ICompositeBehavior.cs" />
101
<Compile Include="Behaviors\SequenceBehavior.cs" />
102
<Compile Include="Behaviors\BehaviorState.cs" />
<Compile Include="Behaviors\IBehavior.cs" />
103
<Compile Include="Designer\BehaviorAttribute.cs" />
104
<Compile Include="ExtensionMethods.cs" />
105
<Compile Include="Utility\Enums.cs" />
106
<Compile Include="Utility\ExtensionMethods.cs" />
<Compile Include="Feeler.cs" />
107
<Compile Include="Grid.cs" />
108
<Compile Include="Map\Grid.cs" />
<Compile Include="GridCell.cs" />
109
<Compile Include="Map\GridCell.cs" />
<Compile Include="Agent.cs" />
110
<Compile Include="Label.cs" />
111
112
<Compile Include="Utility\License.cs" />
<Compile Include="Locomotion\LocomotionController.cs" />
113
<Compile Include="Locomotion\LocomtionSteering.cs" />
114
<Compile Include="Map.cs" />
115
<Compile Include="Map\WorldMap.cs" />
<Compile Include="PathFinding\PathFinder.cs" />
116
<Compile Include="PathFinding\PathFinderNode.cs" />
117
<Compile Include="PathFinding\NodeComparer.cs" />
118
<Compile Include="PathFinding\PathFinderState.cs" />
<Compile Include="PriorityQueue.cs" />
119
<Compile Include="Properties\AssemblyInfo.cs" />
120
<Compile Include="QuadTree\FRect.cs" />
121
<Compile Include="QuadTree\RectangleF.cs" />
<Compile Include="QuadTree\QuadTree.cs" />
122
<Compile Include="QuadTree\QuadTreeNode.cs" />
123
<Compile Include="QuadTree\QuadTreePositionItem.cs" />
124
<Compile Include="Util.cs" />
125
<Compile Include="Utility\Util.cs" />
<Compile Include="World.cs" />
126
</ItemGroup>
127
<ItemGroup>
128
175
<Target Name="AfterBuild">
176
</Target>
-->
<PropertyGroup>
<PostBuildEvent>xcopy /Y $(TargetDir)$(TargetName).* $(ProjectDir)..\..\build\Release\</PostBuildEvent>
</Project>
using Brains.Framework.Utility;
/// Stores a direction and length of the feeler.
public class Feeler
public Agent Owner;
private Agent _owner;
/// Gets the owning agent of the Feeler
public Agent Owner { get { return _owner; } }
/// Gets or Sets the direction of the Feeler in local space coordinates
public Vector2 Vector { get; set; }
/// Gets or sets the length of the Feeler
public float Length { get; set; }
public Vector2 TipWorldPosition
get
Vector2 dest = Util.VectorToWorldSpace(Vector, Owner.Orientation);
Vector2 dest = VectorUtil.VectorToWorldSpace(Vector, Owner.Orientation);
Vector2 dd =Owner.Position + (dest * Length);
37
return dd;
38
39
/// Gets the direction of the Feeler in world coordinates
public Vector2 WorldDirection
47
48
49
return dest;
50
51
52
public Feeler(Vector2 feeler,float length,Agent owner)
53
54
internal Feeler(Vector2 feeler,float length,Agent owner)
55
Length = length;
56
Vector = feeler;
57
Owner = owner;
58
_owner = owner;
59
60
61
62
63
64
namespace Brains
public struct Label
internal struct Label
public float Value;
public float Value2;
/// Gets or sets the maximum speed the agent can travel at
public float MaxSpeed { get; set; }
public float MaxSpeed
get; set;
/// Gets or sets the maximum amount an Agent can rotate per second
/// <remarks>Value is in radians</remarks>
public float MaxRotation { get; set; }
public float MaxRotation
/// Gets or sets the owning Agent
public Agent Owner { get; set; }
public Agent Owner
/// Gets the current speed of the Agent
public float Speed { get { return _speed; } }
public float Speed
get { return _speed; }
/// Gets the velocity as a Vector2 of the Agent
public Vector2 Velocity { get { return _velocity; } }
public Vector2 Velocity
get { return _velocity; }
/// Gets or sets wether the Agent can move at all
/// Gets or sets the value of wether the Agent will move
public bool Stationary { get; set; }
public bool Stationary
65
66
67
/// Initializes a new instance of LocomotionController
68
public LocomotionController()
69
70
71
namespace Brains.Framework.Locomotion
/// This class is currently W.I.P
/// <remarks></remarks>
public class LocomtionSteering:LocomotionController
private static Random rand = new Random();
private Vector2 _wanderTarget;
Vector2 _steeringForce;
public const float WanderRadius = 1.2f;
private float ObstacleAvoidanceWeight=10;
public const float WanderDistance = 2.0f;
public float SeekWeight=1;
public const float WanderJitter = 80;
public enum Deceleration
Fast,
Normal,
Slow
public Vector2 SeekPos { get; set; }
[Flags()]
public enum BehaviorType
none = 0x00000,
None = 0x00000,
seek = 0x00002,
Seek = 0x00002,
flee = 0x00004,
Flee= 0x00004,
arrive = 0x00008,
Arrive= 0x00008,
wander = 0x00010,
Wander = 0x00010,
cohesion = 0x00020,
//Cohesion= 0x00020,
separation = 0x00040,
//Seperation= 0x00040,
allignment = 0x00080,
//Alignment = 0x00080,
obstacle_avoidance = 0x00100,
//ObstacleAvoidance= 0x00100,
wall_avoidance = 0x00200,
//WallAvoidance = 0x00200,
follow_path = 0x00400,
//FollowPath = 0x00400,
pursuit = 0x00800,
Pursuit= 0x00800,
evade = 0x01000,
Evade = 0x01000,
interpose = 0x02000,
//Interpose= 0x02000,
hide = 0x04000,
//Hide= 0x04000,
flock = 0x08000,
//Flock = 0x08000,
offset_pursuit = 0x10000,
OffsetPursuit= 0x10000,
Vector2 SteeringForce = Vector2.Zero;
Vector2 Heading;
float MaxForce=4;
public void TurnAllOff()
Vector2 Velocity;
private BehaviorType _behaviorFlags;
public LocomtionSteering()
_behaviorFlags = BehaviorType.None;
public void SeekOn(Vector2 target)
public void TurnOnArrive(Vector2 targetPosition)
TurnOn(BehaviorType.Arrive);
SeekPos = targetPosition;
public void TurnOffArrive()
TurnOff(BehaviorType.Arrive);
if (!On(BehaviorType.seek))
public void TurnOnSeek(Vector2 targetPosition)
_behaviorFlags |= BehaviorType.seek;
TurnOn(BehaviorType.Seek);
72
73
74
public void TurnOffSeek()
75
76
TurnOff(BehaviorType.Seek);
77
78
79
public void TurnOnWander()
80
81
TurnOn(BehaviorType.Wander);
82
83
84
public void TurnOffWander()
85
86
TurnOff(BehaviorType.Wander);
public void TurnOnOffsetPursuit(Vector2 seek)
SeekPos= target;
public void TurnOffOffsetPursuit()
96
97
public void TurnOnPursuit(Vector2 seek)
public void TurnOffPursuit()
public void TurnOnFlee(Vector2 seek)
public void TurnOffFlee()
private Vector2 _steeringForce;
private Vector2 SteeringForce = Vector2.Zero;
private Vector2 Heading;
private float MaxForce = 4;
private Vector2 Velocity;
public float SeekWeight = 1;
129
public float ArriveWeight= 1;
130
public float WanderWeight= 1;
131
132
133
public Deceleration DecelerationSpeed { get; set; }
134
135
136
DecelerationSpeed = Deceleration.Normal;
137
138
float timeElapsed;
public override void Update(Microsoft.Xna.Framework.GameTime gameTime)
139
140
141
timeElapsed = gameTime.GetElapsed();
SteeringUpdate(gameTime.GetElapsed());
142
143
144
145
public void ObstacleAvoidanceOn()
146
_behaviorFlags |= BehaviorType.obstacle_avoidance;
private void SteeringUpdate(float elapsed)
147
148
if(!On(BehaviorType.seek))
SeekOn(Owner.DesiredPosition);
if (!On(BehaviorType.obstacle_avoidance))
ObstacleAvoidanceOn();
Vector2 OldPos = Owner.Position;
149
SeekPos = Owner.DesiredPosition;
SteeringForce = Vector2.Zero;
150
151
SteeringForce = Calculate();
152
Owner.Position += Velocity * elapsed;
161
Owner.Orientation = Heading;// (float)Math.Atan2(Heading.Y, Heading.X);
162
163
public void SetHeading(Vector2 new_heading)
164
165
private void SetHeading(Vector2 new_heading)
166
Heading= new_heading;
167
//Right = Perp(_heading);
168
169
170
public Vector2 Truncate(Vector2 vec, float max)
171
private Vector2 Truncate(Vector2 vec, float max)
172
Vector2 __v = vec;
173
if (vec.Length() > max)
174
private Vector2 Calculate()
_steeringForce = Vector2.Zero;
184
//if (isObstacleAvoidanceOn())
185
// CalculateNearbyObjects();
_steeringForce = CalculatePrioritized();
return _steeringForce;
private bool On(BehaviorType bt)
private bool On(BehaviorType type)
return (_behaviorFlags & bt) == bt;
193
return (_behaviorFlags & type) == type;
194
195
196
private void TurnOn(BehaviorType bt)
197
198
if(!On(bt))
199
_behaviorFlags |= bt;
200
201
202
private void TurnOff(BehaviorType bt)
203
204
if(On(bt))
205
_behaviorFlags ^= bt;
206
207
private Vector2 CalculatePrioritized()
208
209
210
Vector2 force = Vector2.Zero;
211
212
if (On(BehaviorType.obstacle_avoidance))
213
if (On(BehaviorType.Seek))
214
Vector2 __oa = ObstacleAvoidance();
force = Seek(SeekPos);
force = Vector2.Multiply(__oa, ObstacleAvoidanceWeight);
force = Vector2.Multiply(force, SeekWeight);
if (!AccumulateForce(ref _steeringForce, force)) return _steeringForce;
if (On(BehaviorType.seek))
222
223
if (On(BehaviorType.Arrive))
force = Arrive(SeekPos, DecelerationSpeed) * ArriveWeight;
if (On(BehaviorType.Wander))
231
232
force = Wander() * WanderWeight;
233
234
235
236
237
238
153
239
154
private Vector2 Seek(Vector2 seek)
240
155
241
156
Vector2 tpos = seek - Owner.Position;
157
Vector2 DesiredVelocity = Vector2.Zero;
158
if (tpos != Vector2.Zero)
159
DesiredVelocity = Vector2.Normalize(seek- Owner.Position) * MaxSpeed;
160
return (DesiredVelocity - Velocity);
private bool AccumulateForce(ref Vector2 sf, Vector2 ForceToAdd)
242
243
//first calculate how much steering force we have left to use
244
return true;
265
266
267
private Vector2 ObstacleAvoidance()
268
269
Vector2 _steer=Vector2.Zero;
270
foreach (var item in Owner.ParentWorld.Map.Cluster[0].Cells)
271
foreach (var item in Owner.ParentWorld.Map.ClusterGrid.Grids[0].Cells)
272
if (item.Type == 0)
273
274
//Check feeler 1
275
Ray _ra = new Ray(Owner.Position.ToVector3(), Owner.Feelers[1].WorldDirection.ToVector3());
276
Vector3 tl = (item.Position - new Vector2(Owner.ParentWorld.Map.Cluster[0].CellSize / 2)).ToVector3();
277
Vector3 tl = (item.Position - new Vector2(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize / 2)).ToVector3();
BoundingBox _box = new BoundingBox(
278
tl,
279
tl + new Vector3(Owner.ParentWorld.Map.Cluster[0].CellSize,
280
tl + new Vector3(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize,
Owner.ParentWorld.Map.Cluster[0].CellSize, 0));
281
Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize, 0));
float? inte = _ra.Intersects(_box);
282
if (inte.HasValue)
283
284
//Check feeler2
292
293
_ra = new Ray(Owner.Position.ToVector3(), Owner.Feelers[2].WorldDirection.ToVector3());
294
tl = (item.Position - new Vector2(Owner.ParentWorld.Map.Cluster[0].CellSize / 2)).ToVector3();
295
tl = (item.Position - new Vector2(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize / 2)).ToVector3();
_box = new BoundingBox(
296
297
298
299
inte = _ra.Intersects(_box);
300
301
302
310
return _steer;
311
312
313
314
public Vector2 Wander()
315
316
double JitterThisTimeSlice = WanderJitter * timeElapsed;
317
318
//first, add a small random vector to the target's position (RandomClamped
319
//returns a value between -1 and 1)
320
_wanderTarget+= new Vector2(RandomClamped() * WanderJitter,
321
RandomClamped() * WanderJitter);
322
323
if (_wanderTarget != Vector2.Zero) //reproject this new vector back on to a unit circle
324
_wanderTarget.Normalize();
325
326
//increase the length of the vector to the same as the radius
327
//of the wander circle
328
_wanderTarget *= WanderRadius;
329
330
//move the target into a position WanderDist in front of the agent
331
Vector2 _newtarget = _wanderTarget + new Vector2(WanderDistance, 0);
332
333
//project the target into world space
334
Vector2 _target = VectorUtil.PointToWorldSpace(_newtarget,
335
Owner.Orientation,
336
Owner.Position);
337
338
return _target - Owner.Position;
339
340
341
342
public Vector2 Arrive(Vector2 targetPosition,Deceleration decelspeed)
343
344
Vector2 toTarget = targetPosition - Owner.Position;
345
346
//calculate the distance to the target
347
float dist = toTarget.Length();
348
349
if (dist > 0)
350
351
//because Deceleration is enumerated as an int, this value is required
352
//to provide fine tweaking of the deceleration..
353
const float DecelerationTweaker = 0.3f;
354
355
//calculate the speed required to reach the target given the desired
356
//deceleration
357
float speed = dist / ((float)decelspeed * DecelerationTweaker);
358
359
//make sure the velocity does not exceed the max
360
speed = Math.Min(speed, MaxSpeed);
361
362
//from here proceed just like Seek except we don't need to normalize
363
//the ToTarget vector because we have already gone to the trouble
364
//of calculating its length: dist.
365
Vector2 DesiredVelocity = toTarget * speed / dist;
366
367
368
369
370
return Vector2.Zero;
371
372
373
374
375
376
377
DesiredVelocity = Vector2.Normalize(seek - Owner.Position) * MaxSpeed;
378
379
380
381
382
float RandomClamped()
383
384
return rand.Next() - rand.Next();
385
386
387
using AIFamework;
namespace Brains.Framework.PathFinding
public class PathFinder
return _foundInOpenIndex ;
public enum HeuristicType
Euclidean,
Manhattan,
Diagonal
using System.Collections;
using System.Runtime.InteropServices;
namespace AIFamework
/// Represents an item stored in a priority queue.
/// <typeparam name="TValue">The type of object in the queue.</typeparam>
/// <typeparam name="TPriority">The type of the priority field.</typeparam>
[Serializable]
[ComVisible(false)]
public struct PriorityQueueItem<TValue, TPriority>
private TValue value;
// *******************************************//
// *********Credits to Kyle Schouviller*******//
// *******for the original implementation*****//
using Microsoft.Xna.Framework.Graphics;
namespace Brains.Framework.QuadTree
public class QuadTree<T>
public static Rectangle GetRectangle(FRect rect)
public static Rectangle GetRectangle(RectangleF rect)
return new Rectangle((int)rect.Left, (int)rect.Top, (int)rect.Width, (int)rect.Height);
public void Count()
#region Properties
/// The head node of the QuadTree
/// Gets the world rectangle
public FRect WorldRect
public RectangleF WorldRect
get { return headNode.Rect; }
protected int maxItems;
#endregion
#region Initialization
/// QuadTree constructor
/// <param name="worldRect">The world rectangle for this QuadTree (a rectangle containing all items at all times)</param>
/// <param name="maxItems">Maximum number of items in any cell of the QuadTree before partitioning</param>
public QuadTree(FRect worldRect, int maxItems)
public QuadTree(RectangleF worldRect, int maxItems)
this.headNode = new QuadTreeNode<T>(worldRect, maxItems, Resize);
this.maxItems = maxItems;
/// <remarks>This constructor is for ease of use</remarks>
public QuadTree(Vector2 size, int maxItems)
: this(new FRect(Vector2.Zero, size), maxItems)
: this(new RectangleF(Vector2.Zero, size), maxItems)
// Nothing extra to initialize
#region Methods
/// Inserts an item into the QuadTree
// check if the world needs resizing
if (!headNode.ContainsRect(item.Rect))
Resize(new FRect(
Resize(new RectangleF(
Vector2.Min(headNode.Rect.TopLeft, item.Rect.TopLeft) * 2,
Vector2.Max(headNode.Rect.BottomRight, item.Rect.BottomRight) * 2));
/// <param name="newWorld">The new field</param>
/// <remarks>This is an expensive operation, so try to initialize the world to a big enough size</remarks>
public void Resize(FRect newWorld)
public void Resize(RectangleF newWorld)
// Get all of the items in the tree
List<QuadTreePositionItem<T>> Components = new List<QuadTreePositionItem<T>>();
#region Query methods
/// Gets a list of items containing a specified point
/// <param name="Rect">The rectangle</param>
/// <param name="ItemsFound">The list to add found items to (list will not be cleared first)</param>
public void GetItems(FRect Rect, ref List<QuadTreePositionItem<T>> ItemsList)
public void GetItems(RectangleF Rect, ref List<QuadTreePositionItem<T>> ItemsList)
if (ItemsList != null)
headNode.GetAllItems(ref ItemsList);
// *******************************************************************************//
// *************************Credits to Kyle Schouviller***************************//
// *************************for the original implementation***********************//
public class QuadTreeNode<T>
#region Delegates
/// World resize delegate
/// <param name="newSize">The new world size</param>
public delegate void ResizeDelegate(FRect newSize);
public delegate void ResizeDelegate(RectangleF newSize);
/// The rectangle of this node
protected FRect rect;
protected RectangleF rect;
/// Gets the rectangle of this node
public FRect Rect
public RectangleF Rect
get { return rect; }
protected set { rect = value; }
protected ResizeDelegate WorldResize;
/// QuadTreeNode constructor
/// <param name="parentNode">The parent node of this QuadTreeNode</param>
/// <param name="rect">The rectangle of the QuadTreeNode</param>
/// <param name="maxItems">Maximum number of items in the QuadTreeNode before partitioning</param>
public QuadTreeNode(QuadTreeNode<T> parentNode, FRect rect, int maxItems)
public QuadTreeNode(QuadTreeNode<T> parentNode, RectangleF rect, int maxItems)
ParentNode = parentNode;
Rect = rect;
/// <param name="worldResize">The function to return the size</param>
public QuadTreeNode(FRect rect, int maxItems, ResizeDelegate worldResize)
public QuadTreeNode(RectangleF rect, int maxItems, ResizeDelegate worldResize)
ParentNode = null;
Items = new List<QuadTreePositionItem<T>>();
#region Insertion methods
/// Insert an item in this node
// Create the nodes
Vector2 MidPoint = Vector2.Divide(Vector2.Add(Rect.TopLeft, Rect.BottomRight), 2.0f);
TopLeftNode = new QuadTreeNode<T>(this, new FRect(Rect.TopLeft, MidPoint), MaxItems);
TopLeftNode = new QuadTreeNode<T>(this, new RectangleF(Rect.TopLeft, MidPoint), MaxItems);
TopRightNode = new QuadTreeNode<T>(this, new FRect(new Vector2(MidPoint.X, Rect.Top), new Vector2(Rect.Right, MidPoint.Y)), MaxItems);
TopRightNode = new QuadTreeNode<T>(this, new RectangleF(new Vector2(MidPoint.X, Rect.Top), new Vector2(Rect.Right, MidPoint.Y)), MaxItems);
BottomLeftNode = new QuadTreeNode<T>(this, new FRect(new Vector2(Rect.Left, MidPoint.Y), new Vector2(MidPoint.X, Rect.Bottom)), MaxItems);
BottomLeftNode = new QuadTreeNode<T>(this, new RectangleF(new Vector2(Rect.Left, MidPoint.Y), new Vector2(MidPoint.X, Rect.Bottom)), MaxItems);
BottomRightNode = new QuadTreeNode<T>(this, new FRect(MidPoint, Rect.BottomRight), MaxItems);
BottomRightNode = new QuadTreeNode<T>(this, new RectangleF(MidPoint, Rect.BottomRight), MaxItems);
IsPartitioned = true;
/// <remarks>ItemsFound is assumed to be initialized, and will not be cleared</remarks>
public void GetItems(FRect Rect, ref List<QuadTreePositionItem<T>> ItemsFound)
public void GetItems(RectangleF Rect, ref List<QuadTreePositionItem<T>> ItemsFound)
// test the point against this node
else return null;
#region Destruction
/// Destroys this node
418
414
419
415
420
416
421
417
422
423
#region Observer methods
424
425
426
/// Handles item movement
444
440
445
else if (!ContainsRect(item.Rect))
441
446
442
447
WorldResize(new FRect(
443
WorldResize(new RectangleF(
448
Vector2.Min(Rect.TopLeft, item.Rect.TopLeft) * 2,
449
Vector2.Max(Rect.BottomRight, item.Rect.BottomRight) * 2));
450
468
RemoveItem(item);
464
469
465
470
466
471
467
472
473
#region Helper methods
474
475
476
/// Tests whether this node contains a rectangle
477
478
/// <param name="rect">The rectangle to test</param>
479
/// <returns>Whether or not this node contains the specified rectangle</returns>
480
public bool ContainsRect(FRect rect)
public bool ContainsRect(RectangleF rect)
481
482
return (rect.TopLeft.X >= Rect.TopLeft.X &&
483
rect.TopLeft.Y >= Rect.TopLeft.Y &&
485
rect.BottomRight.Y <= Rect.BottomRight.Y);
486
487
488
484
489
490
491
/// A position item in a quadtree
public QuadTreeNode<T> node;
internal QuadTree<T> quadTree;
#region Events and Event Handlers
/// Handles the move event
node.RemoveItem(this);
/// The center position of this item
/// The rectangle containing this item
private FRect rect;
private RectangleF rect;
/// Gets a rectangle containing this item
get { return parent; }
/// Creates a position item in a QuadTree
/// <param name="size">The size of this item</param>
public QuadTreePositionItem(T parent, Vector2 position, Vector2 size)
this.rect = new FRect(0f, 0f, 1f, 1f);
this.rect = new RectangleF(0f, 0f, 1f, 1f);
this.parent = parent;
this.position = position ;
OnMove();
/// Destroys this item and removes it from the QuadTree
OnDestroy();
//***********************(c) Rik Dodsworth 2009*******************//
using System.Globalization;
using Brains.Framework.QuadTree;
//privates
//
private Texture2D _mapTexture;
private Map _map;
private WorldMap _map;
//Public properties
public List<Agent> Actors = new List<Agent>();
public Map Map { get{return _map; } }
public WorldMap Map { get { return _map; } }
//Public Methods
/// <param name="maxclusterheight"></param>
internal void SetupMap(int width, int height, int cellsize, int maxclusterwidth,int maxclusterheight,Type gridType)
_map = new Map(width,height);
_map = new WorldMap(width,height);
int totalCols = width / cellsize;
int totalRows= height / cellsize;
int clusterRows = totalCols / maxclusterwidth;
int clusterCols = totalRows/ maxclusterheight;
_map.Rows = clusterRows;
_map.ClusterGrid.Setup(clusterRows, clusterCols);
_map.Cols = clusterCols;
Vector2 position = new Vector2();
for (int y = 0; y < clusterRows; y++)
Map.GridCellTree.GetAllItems(ref list);
//Grid grid = Map.Cluster[index];
//Annotate clearance.
for (int xx =Map.Cols * Map.Cluster[0].Cols - 1; xx >= 0; xx--)
int rows = Map.ClusterGrid.Rows;
int cols= Map.ClusterGrid.Cols;
Cluster cluster = Map.ClusterGrid;
for (int xx = cluster.TotalCols - 1; xx >= 0; xx--)
for (int yy = Map.Rows * Map.Cluster[0].Rows - 1; yy >= 0; yy--)
for (int yy = cluster.TotalRows - 1; yy >= 0; yy--)
//int x = xx / Map.Cluster[0].Cols;
//int y = yy/ Map.Cluster[0].Rows;
//int index = y * Map.Cols + x;
int totalCols = Map.Cols * Map.Cluster[0].Cols;
int index = yy * totalCols + xx;
int index = yy * cluster.TotalCols + xx;
GridCell cell = Map.AllCells[index];// grid.GetCell(xx - (x * grid.Cols), yy - (y * grid.Rows));
if (cell.Type == 0) //If the cell is not traversable, bail out.
continue;
//Get adjacent tiles
GridCell c1, c2, c3;
int y = (index - (index % totalCols)) / totalCols;
int y = (index - (index % cluster.TotalCols)) / cluster.TotalCols;
int x = index % totalCols;
int x = index % cluster.TotalCols;
int newindex = (y + 1) * totalCols + (x+1);
int newindex = (y + 1) * cluster.TotalCols + (x + 1);
c1 = null;
c2 = null;
c3 = null;
if(Map.AllCells.Count > newindex)
c1 = Map.AllCells[newindex];// grid.GetCell(cell.X + 1, cell.Y + 1);
newindex = (y) * totalCols + (x + 1);
newindex = (y) * cluster.TotalCols + (x + 1);
if (Map.AllCells.Count > newindex)
c2 = Map.AllCells[newindex]; //grid.GetCell(cell.X + 1, cell.Y);
newindex = (y + 1) * totalCols + (x);
newindex = (y + 1) * cluster.TotalCols + (x);
c3 = Map.AllCells[newindex]; //grid.GetCell(cell.X, cell.Y + 1);
if (Map.Cluster.Count > 1)
if (cluster.Grids.Count > 1)
int index = 0;
for (int y = 0; y < Map.Rows; y++)
for (int y = 0; y < rows; y++)
for (int x = 0; x < Map.Cols; x++)
for (int x = 0; x < cols; x++)
//Check right edge
if (Map.Cluster.Count > index + 1)
if (cluster.Grids.Count > index + 1)
for (int row = 0; row < Map.Cluster[index].Rows; row++)
for (int row = 0; row < cluster.Grids[index].Rows; row++)
GridCell leftcell = Map.Cluster[index].GetCell(
GridCell leftcell = cluster.Grids[index].GetCell(
Map.Cluster[index].Cols - 1,
cluster.Grids[index].Cols - 1,
row);
GridCell rightcell = Map.Cluster[index + 1].GetCell(
GridCell rightcell = cluster.Grids[index + 1].GetCell(
0,
if (index > 1)
GridCell leftcell = Map.Cluster[index - 1].GetCell(
GridCell leftcell = cluster.Grids[index - 1].GetCell(
Map.Cluster[index - 1].Cols - 1,
cluster.Grids[index - 1].Cols - 1,
GridCell rightcell = Map.Cluster[index].GetCell(
GridCell rightcell = cluster.Grids[index].GetCell(
//check bottom edge
if (index + Map.Cols < Map.Cluster.Count)
if (index + cols < cluster.Grids.Count)
245
246
for (int col = 0; col < Map.Cluster[index].Cols; col++)
for (int col = 0; col < cluster.Grids[index].Cols; col++)
247
248
GridCell topcell = Map.Cluster[index].GetCell(
GridCell topcell = cluster.Grids[index].GetCell(
249
col,
250
Map.Cluster[index].Rows - 1);
cluster.Grids[index].Rows - 1);
251
GridCell bottomcell = Map.Cluster[index + Map.Cols].GetCell(
GridCell bottomcell = cluster.Grids[index + cols].GetCell(
252
253
0);
254
261
262
263
//Check Top
255
264
if (index - Map.Cols > 0)
256
if (index - cols > 0)
257
258
259
GridCell topcell = Map.Cluster[index - Map.Cols].GetCell(
260
GridCell topcell = cluster.Grids[index - cols].GetCell(
Map.Cluster[index - Map.Cols].Rows - 1);
cluster.Grids[index - cols].Rows - 1);
GridCell bottomcell = Map.Cluster[index].GetCell(
GridCell bottomcell = cluster.Grids[index].GetCell(
Grid item = Map.Cluster[index];
Grid item = Map.ClusterGrid.Grids[index];
index++;
int count = item.Rows * item.Cols;
//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{/// Class to represent an AI Agent. Add the Agent to a World/// Represents an autonomous agent in the AI world.Grid map = ParentWorld.Map.ClusterGrid.Grids[0];{{foreach (var item in ParentWorld.Map.ClusterGrid.Grids){{//****************************************************************//using System;//********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//using System;{{/// The main AI Engine./// Represents the main AI Engine.//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//<Compile Include="Utility\AIConsts.cs" /><Compile Include="Map\Cluster.cs" /><Compile Include="Behaviors\BehaviorState.cs" /><Compile Include="ExtensionMethods.cs" /><Compile Include="Utility\Enums.cs" /><Compile Include="Utility\ExtensionMethods.cs" /><Compile Include="Map\Grid.cs" /><Compile Include="Map\GridCell.cs" /><Compile Include="Map\WorldMap.cs" /><Compile Include="PathFinding\PathFinderState.cs" /><Compile Include="QuadTree\FRect.cs" /><Compile Include="QuadTree\RectangleF.cs" /><Compile Include="Utility\Util.cs" />//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//{{{{public Agent Owner;private Agent _owner;/// <summary>/// Gets the owning agent of the Feeler/// </summary>public Agent Owner { get { return _owner; } }/// <summary>/// Gets or Sets the direction of the Feeler in local space coordinates/// </summary>public Vector2 Vector { get; set; }public Vector2 Vector { get; set; }public float Length { get; set; }public float Length { get; set; }{{{{Vector2 dest = VectorUtil.VectorToWorldSpace(Vector, Owner.Orientation);{{{{Vector2 dest = VectorUtil.VectorToWorldSpace(Vector, Owner.Orientation);public Feeler(Vector2 feeler,float length,Agent owner)internal Feeler(Vector2 feeler,float length,Agent owner){{Owner = owner;_owner = owner;namespace Brains.Framework{{public struct Labelinternal struct Label{{//****************************************************************//using System;//********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//using System;public float MaxSpeed { get; set; }{get; set;}public float MaxRotation { get; set; }{get; set;}public Agent Owner { get; set; }{get; set;}public float Speed { get { return _speed; } }{get { return _speed; }}public Vector2 Velocity { get { return _velocity; } }{get { return _velocity; }}/// Gets or sets wether the Agent can move at all/// Gets or sets the value of wether the Agent will movepublic bool Stationary { get; set; }{get; set;}/// <summary>/// Initializes a new instance of LocomotionController/// </summary>{{//****************************************************************//using System;//********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//using System;{{{{Vector2 _steeringForce;public const float WanderRadius = 1.2f;private float ObstacleAvoidanceWeight=10;public const float WanderDistance = 2.0f;public float SeekWeight=1;public const float WanderJitter = 80;public enum Deceleration{Fast,Normal,Slow}public Vector2 SeekPos { get; set; }{{none = 0x00000,None = 0x00000,seek = 0x00002,Seek = 0x00002,flee = 0x00004,Flee= 0x00004,arrive = 0x00008,Arrive= 0x00008,wander = 0x00010,Wander = 0x00010,cohesion = 0x00020,//Cohesion= 0x00020,separation = 0x00040,//Seperation= 0x00040,allignment = 0x00080,//Alignment = 0x00080,obstacle_avoidance = 0x00100,//ObstacleAvoidance= 0x00100,wall_avoidance = 0x00200,//WallAvoidance = 0x00200,follow_path = 0x00400,//FollowPath = 0x00400,pursuit = 0x00800,Pursuit= 0x00800,evade = 0x01000,Evade = 0x01000,interpose = 0x02000,//Interpose= 0x02000,hide = 0x04000,//Hide= 0x04000,flock = 0x08000,//Flock = 0x08000,offset_pursuit = 0x10000,OffsetPursuit= 0x10000,Vector2 SteeringForce = Vector2.Zero;Vector2 Heading;float MaxForce=4;public void TurnAllOff()Vector2 Velocity;private BehaviorType _behaviorFlags;public LocomtionSteering(){{_behaviorFlags = BehaviorType.None;public void SeekOn(Vector2 target)public void TurnOnArrive(Vector2 targetPosition){{{if (!On(BehaviorType.seek))public void TurnOnSeek(Vector2 targetPosition)_behaviorFlags |= BehaviorType.seek;{SeekPos = targetPosition;TurnOn(BehaviorType.Seek);}public void TurnOffSeek(){TurnOff(BehaviorType.Seek);}public void TurnOnWander(){TurnOn(BehaviorType.Wander);}public void TurnOffWander(){TurnOff(BehaviorType.Wander);}public void TurnOnOffsetPursuit(Vector2 seek){SeekPos= target;{{{{{public Vector2 SeekPos { get; set; }public Deceleration DecelerationSpeed { get; set; }{{{public void ObstacleAvoidanceOn(){_behaviorFlags |= BehaviorType.obstacle_avoidance;}{{if(!On(BehaviorType.seek))SeekOn(Owner.DesiredPosition);if (!On(BehaviorType.obstacle_avoidance))ObstacleAvoidanceOn();SeekPos = Owner.DesiredPosition;public void SetHeading(Vector2 new_heading)private void SetHeading(Vector2 new_heading){{public Vector2 Truncate(Vector2 vec, float max)private Vector2 Truncate(Vector2 vec, float max){{{{//if (isObstacleAvoidanceOn())// CalculateNearbyObjects();private bool On(BehaviorType bt)private bool On(BehaviorType type){{return (_behaviorFlags & bt) == bt;return (_behaviorFlags & type) == type;{{{{if (On(BehaviorType.obstacle_avoidance))if (On(BehaviorType.Seek)){{Vector2 __oa = ObstacleAvoidance();force = Seek(SeekPos);force = Vector2.Multiply(__oa, ObstacleAvoidanceWeight);force = Vector2.Multiply(force, SeekWeight);if (On(BehaviorType.seek))if (On(BehaviorType.Arrive)){{force = Seek(SeekPos);force = Arrive(SeekPos, DecelerationSpeed) * ArriveWeight;force = Vector2.Multiply(force, SeekWeight);{if (!AccumulateForce(ref _steeringForce, force)) return _steeringForce;}private Vector2 Seek(Vector2 seek){Vector2 tpos = seek - Owner.Position;Vector2 DesiredVelocity = Vector2.Zero;if (tpos != Vector2.Zero)DesiredVelocity = Vector2.Normalize(seek- Owner.Position) * MaxSpeed;return (DesiredVelocity - Velocity);}{{{{foreach (var item in Owner.ParentWorld.Map.ClusterGrid.Grids[0].Cells){{{{Vector3 tl = (item.Position - new Vector2(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize / 2)).ToVector3();tl + new Vector3(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize,Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize, 0));{{tl = (item.Position - new Vector2(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize / 2)).ToVector3();tl + new Vector3(Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize,Owner.ParentWorld.Map.ClusterGrid.Grids[0].CellSize, 0));{{{{{{{//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//using AIFamework;using Brains.Framework.Map;{{public enum HeuristicType{Euclidean,Manhattan,Diagonal}//****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************////****************************************************************////********************copyright Rik Dodsworth 2009****************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//namespace AIFameworknamespace Brains.Framework{{[ComVisible(false)]{{namespace Brains.Framework.QuadTree{{{{public static Rectangle GetRectangle(FRect rect)public static Rectangle GetRectangle(RectangleF rect){{public void Count(){}#region Propertiespublic FRect WorldRectpublic RectangleF WorldRect{{get { return headNode.Rect; }get { return headNode.Rect; }#endregion#region Initializationpublic QuadTree(FRect worldRect, int maxItems)public QuadTree(RectangleF worldRect, int maxItems){{: this(new FRect(Vector2.Zero, size), maxItems): this(new RectangleF(Vector2.Zero, size), maxItems){{#endregion#region Methods{{Resize(new FRect(Resize(new RectangleF({{Resize(new FRect(Resize(new RectangleF(public void Resize(FRect newWorld)public void Resize(RectangleF newWorld){{#endregion#region Query methodspublic void GetItems(FRect Rect, ref List<QuadTreePositionItem<T>> ItemsList)public void GetItems(RectangleF Rect, ref List<QuadTreePositionItem<T>> ItemsList){{{{#endregion// *******************************************************************************//// *******************************************************************************//// *********Credits to Kyle Schouviller*******//// *************************Credits to Kyle Schouviller***************************//// *******for the original implementation*****//// *************************for the original implementation***********************//// *******************************************************************************//// *******************************************************************************//// *******************************************************************************//// *******************************************************************************//// *******************************************************************************//namespace Brains.Framework.QuadTree{{{{public static Rectangle GetRectangle(FRect rect)public static Rectangle GetRectangle(RectangleF rect){{#region Delegatespublic delegate void ResizeDelegate(FRect newSize);public delegate void ResizeDelegate(RectangleF newSize);#endregion#region Propertiesprotected FRect rect;protected RectangleF rect;public FRect Rectpublic RectangleF Rect{{get { return rect; }get { return rect; }protected set { rect = value; }protected set { rect = value; }#endregion#region Initializationpublic QuadTreeNode(QuadTreeNode<T> parentNode, FRect rect, int maxItems)public QuadTreeNode(QuadTreeNode<T> parentNode, RectangleF rect, int maxItems){{public QuadTreeNode(FRect rect, int maxItems, ResizeDelegate worldResize)public QuadTreeNode(RectangleF rect, int maxItems, ResizeDelegate worldResize){{#endregion#region Insertion methodsTopLeftNode = new QuadTreeNode<T>(this, new FRect(Rect.TopLeft, MidPoint), MaxItems);TopLeftNode = new QuadTreeNode<T>(this, new RectangleF(Rect.TopLeft, MidPoint), MaxItems);TopRightNode = new QuadTreeNode<T>(this, new FRect(new Vector2(MidPoint.X, Rect.Top), new Vector2(Rect.Right, MidPoint.Y)), MaxItems);TopRightNode = new QuadTreeNode<T>(this, new RectangleF(new Vector2(MidPoint.X, Rect.Top), new Vector2(Rect.Right, MidPoint.Y)), MaxItems);BottomLeftNode = new QuadTreeNode<T>(this, new FRect(new Vector2(Rect.Left, MidPoint.Y), new Vector2(MidPoint.X, Rect.Bottom)), MaxItems);BottomLeftNode = new QuadTreeNode<T>(this, new RectangleF(new Vector2(Rect.Left, MidPoint.Y), new Vector2(MidPoint.X, Rect.Bottom)), MaxItems);BottomRightNode = new QuadTreeNode<T>(this, new FRect(MidPoint, Rect.BottomRight), MaxItems);BottomRightNode = new QuadTreeNode<T>(this, new RectangleF(MidPoint, Rect.BottomRight), MaxItems);#endregion#region Query methodspublic void GetItems(FRect Rect, ref List<QuadTreePositionItem<T>> ItemsFound)public void GetItems(RectangleF Rect, ref List<QuadTreePositionItem<T>> ItemsFound){{#endregion#region Destruction#endregion#region Observer methods{{WorldResize(new FRect(WorldResize(new RectangleF(#endregion#region Helper methodspublic bool ContainsRect(FRect rect)public bool ContainsRect(RectangleF rect){{#endregionnamespace Brains.Framework.QuadTree{{{{#region Events and Event Handlers#endregion#region Propertiesprivate FRect rect;private RectangleF rect;public FRect Rectpublic RectangleF Rect{{get { return rect; }get { return rect; }get { return parent; }get { return parent; }#endregion#region Initialization{{this.rect = new FRect(0f, 0f, 1f, 1f);this.rect = new RectangleF(0f, 0f, 1f, 1f);#endregion#region Methods#endregion//****************************************************************////***********************(c) Rik Dodsworth 2009*******************////****************************************************************////***************************free to use**************************////****************************************************************////*******************please just leave this header****************////*************************for recognition************************////****************************************************************////****************************************************************//using Brains.Framework.QuadTree;using Brains.Framework.Map;using Brains.Framework.Utility;{{private WorldMap _map;public Map Map { get{return _map; } }public WorldMap Map { get { return _map; } }{{_map = new WorldMap(width,height);_map.Rows = clusterRows;_map.ClusterGrid.Setup(clusterRows, clusterCols);_map.Cols = clusterCols;{{for (int xx =Map.Cols * Map.Cluster[0].Cols - 1; xx >= 0; xx--)int rows = Map.ClusterGrid.Rows;int cols= Map.ClusterGrid.Cols;Cluster cluster = Map.ClusterGrid;for (int xx = cluster.TotalCols - 1; xx >= 0; xx--){{for (int yy = Map.Rows * Map.Cluster[0].Rows - 1; yy >= 0; yy--)for (int yy = cluster.TotalRows - 1; yy >= 0; yy--){{int totalCols = Map.Cols * Map.Cluster[0].Cols;int index = yy * totalCols + xx;int y = (index - (index % totalCols)) / totalCols;int y = (index - (index % cluster.TotalCols)) / cluster.TotalCols;int x = index % totalCols;int x = index % cluster.TotalCols;int newindex = (y + 1) * totalCols + (x+1);int newindex = (y + 1) * cluster.TotalCols + (x + 1);newindex = (y) * totalCols + (x + 1);newindex = (y) * cluster.TotalCols + (x + 1);newindex = (y + 1) * totalCols + (x);newindex = (y + 1) * cluster.TotalCols + (x);if (Map.Cluster.Count > 1)if (cluster.Grids.Count > 1){{for (int y = 0; y < Map.Rows; y++)for (int y = 0; y < rows; y++){{for (int x = 0; x < Map.Cols; x++)for (int x = 0; x < cols; x++){{if (Map.Cluster.Count > index + 1)if (cluster.Grids.Count > index + 1){{for (int row = 0; row < Map.Cluster[index].Rows; row++)for (int row = 0; row < cluster.Grids[index].Rows; row++){{GridCell leftcell = Map.Cluster[index].GetCell(GridCell leftcell = cluster.Grids[index].GetCell(Map.Cluster[index].Cols - 1,cluster.Grids[index].Cols - 1,GridCell rightcell = Map.Cluster[index + 1].GetCell(GridCell rightcell = cluster.Grids[index + 1].GetCell({{for (int row = 0; row < Map.Cluster[index].Rows; row++)for (int row = 0; row < cluster.Grids[index].Rows; row++){{GridCell leftcell = Map.Cluster[index - 1].GetCell(GridCell leftcell = cluster.Grids[index - 1].GetCell(Map.Cluster[index - 1].Cols - 1,cluster.Grids[index - 1].Cols - 1,GridCell rightcell = Map.Cluster[index].GetCell(GridCell rightcell = cluster.Grids[index].GetCell(if (index + Map.Cols < Map.Cluster.Count)if (index + cols < cluster.Grids.Count){{for (int col = 0; col < Map.Cluster[index].Cols; col++)for (int col = 0; col < cluster.Grids[index].Cols; col++){{GridCell topcell = Map.Cluster[index].GetCell(GridCell topcell = cluster.Grids[index].GetCell(Map.Cluster[index].Rows - 1);cluster.Grids[index].Rows - 1);GridCell bottomcell = Map.Cluster[index + Map.Cols].GetCell(GridCell bottomcell = cluster.Grids[index + cols].GetCell(if (index - Map.Cols > 0)if (index - cols > 0){{for (int col = 0; col < Map.Cluster[index].Cols; col++)for (int col = 0; col < cluster.Grids[index].Cols; col++){{GridCell topcell = Map.Cluster[index - Map.Cols].GetCell(GridCell topcell = cluster.Grids[index - cols].GetCell(Map.Cluster[index - Map.Cols].Rows - 1);cluster.Grids[index - cols].Rows - 1);GridCell bottomcell = Map.Cluster[index].GetCell(GridCell bottomcell = cluster.Grids[index].GetCell({{{{Grid item = Map.ClusterGrid.Grids[index];