public new void UpdateArea (GraphUpdateObject o) {
if (nodes == null || nodes.Length != width*depth*layerCount) {
Debug.LogWarning ("The Grid Graph is not scanned, cannot update area ");
//Not scanned
return;
}
//Copy the bounds
Bounds b = o.bounds;
//Matrix inverse
//node.position = matrix.MultiplyPoint3x4 (new Vector3 (x+0.5F,0,z+0.5F));
Vector3 min, max;
GetBoundsMinMax (b,inverseMatrix,out min, out max);
int minX = Mathf.RoundToInt (min.x-0.5F);
int maxX = Mathf.RoundToInt (max.x-0.5F);
int minZ = Mathf.RoundToInt (min.z-0.5F);
int maxZ = Mathf.RoundToInt (max.z-0.5F);
//We now have coordinates in local space (i.e 1 unit = 1 node)
IntRect originalRect = new IntRect(minX,minZ,maxX,maxZ);
IntRect affectRect = originalRect;
IntRect gridRect = new IntRect(0,0,width-1,depth-1);
IntRect physicsRect = originalRect;
#if ASTARDEBUG
Matrix4x4 debugMatrix = matrix;
debugMatrix *= Matrix4x4.TRS (new Vector3(0.5f,0,0.5f),Quaternion.identity,Vector3.one);
originalRect.DebugDraw (debugMatrix,Color.red);
#endif
bool willChangeWalkability = o.updatePhysics || o.modifyWalkability;
bool willChangeNodeInstances = (o is LayerGridGraphUpdate ? ((LayerGridGraphUpdate)o).recalculateNodes : false);
bool preserveExistingNodes = (o is LayerGridGraphUpdate ? ((LayerGridGraphUpdate)o).preserveExistingNodes : true);
int erosion = o.updateErosion ? erodeIterations : 0;
if (o.trackChangedNodes && willChangeNodeInstances) {
Debug.LogError ("Cannot track changed nodes when creating or deleting nodes.\nWill not update LayerGridGraph");
return;
}
//Calculate the largest bounding box which might be affected
if (o.updatePhysics && !o.modifyWalkability) {
//Add the collision.diameter margin for physics calls
if (collision.collisionCheck) {
Vector3 margin = new Vector3 (collision.diameter,0,collision.diameter)*0.5F;
min -= margin*1.02F;//0.02 safety margin, physics is rarely very accurate
max += margin*1.02F;
physicsRect = new IntRect(
Mathf.RoundToInt (min.x-0.5F),
Mathf.RoundToInt (min.z-0.5F),
Mathf.RoundToInt (max.x-0.5F),
Mathf.RoundToInt (max.z-0.5F)
);
affectRect = IntRect.Union (physicsRect, affectRect);
}
}
if (willChangeWalkability || erosion > 0) {
//Add affect radius for erosion. +1 for updating connectivity info at the border
affectRect = affectRect.Expand (erosion + 1);
}
IntRect clampedRect = IntRect.Intersection (affectRect,gridRect);
//Mark nodes that might be changed
if (!willChangeNodeInstances) {
for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) {
for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) {
for (int y=0;y<layerCount;y++) {
o.WillUpdateNode (nodes[y*width*depth + z*width+x]);
}
}
}
}
//Update Physics
if (o.updatePhysics && !o.modifyWalkability) {
collision.Initialize (matrix,nodeSize);
clampedRect = IntRect.Intersection (physicsRect,gridRect);
bool addedNodes = false;
for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) {
for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) {
/** \todo FIX */
addedNodes |= RecalculateCell (x,z,preserveExistingNodes);
}
}
for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) {
for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
CalculateConnections (nodes,node,x,z,y);
}
}
}
}
//Apply GUO
clampedRect = IntRect.Intersection (originalRect, gridRect);
for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) {
for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
if (willChangeWalkability) {
node.Walkable = node.WalkableErosion;
if (o.bounds.Contains ((Vector3)node.position)) o.Apply (node);
node.WalkableErosion = node.Walkable;
} else {
if (o.bounds.Contains ((Vector3)node.position)) o.Apply (node);
}
}
}
}
#if ASTARDEBUG
physicsRect.DebugDraw (debugMatrix,Color.blue);
affectRect.DebugDraw (debugMatrix,Color.black);
#endif
//Recalculate connections
if (willChangeWalkability && erosion == 0) {
clampedRect = IntRect.Intersection (affectRect, gridRect);
for (int x = clampedRect.xmin; x <= clampedRect.xmax;x++) {
for (int z = clampedRect.ymin;z <= clampedRect.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
CalculateConnections (nodes,node,x,z,y);
}
}
}
} else if (willChangeWalkability && erosion > 0) {
clampedRect = IntRect.Union (originalRect, physicsRect);
IntRect erosionRect1 = clampedRect.Expand (erosion);
IntRect erosionRect2 = erosionRect1.Expand (erosion);
erosionRect1 = IntRect.Intersection (erosionRect1,gridRect);
erosionRect2 = IntRect.Intersection (erosionRect2,gridRect);
#if ASTARDEBUG
erosionRect1.DebugDraw (debugMatrix,Color.magenta);
erosionRect2.DebugDraw (debugMatrix,Color.cyan);
#endif
/*
all nodes inside clampedRect might have had their walkability changed
all nodes inside erosionRect1 might get affected by erosion from clampedRect and erosionRect2
all nodes inside erosionRect2 (but outside erosionRect1) will be reset to previous walkability
after calculation since their erosion might not be correctly calculated (nodes outside erosionRect2 would maybe have effect)
*/
for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) {
for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
bool tmp = node.Walkable;
node.Walkable = node.WalkableErosion;
if (!erosionRect1.Contains (x,z)) {
//Save the border's walkabilty data in bit 16 (will be reset later)
node.TmpWalkable = tmp;
}
}
}
}
for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) {
for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
#if ASTARDEBUG
if (!node.walkable)
Debug.DrawRay ((Vector3)node.position, Vector3.up*2,Color.red);
#endif
CalculateConnections (nodes,node,x,z,y);
}
}
}
//Erode the walkable area
ErodeWalkableArea (erosionRect2.xmin,erosionRect2.ymin,erosionRect2.xmax+1,erosionRect2.ymax+1);
for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) {
for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) {
if (erosionRect1.Contains (x,z)) continue;
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
//Restore temporarily stored data
node.Walkable = node.TmpWalkable;
}
}
}
//Recalculate connections of all affected nodes
for (int x = erosionRect2.xmin; x <= erosionRect2.xmax;x++) {
for (int z = erosionRect2.ymin;z <= erosionRect2.ymax;z++) {
for (int y=0;y<layerCount;y++) {
int index = y*width*depth + z*width+x;
LevelGridNode node = nodes[index] as LevelGridNode;
if (node == null) continue;
CalculateConnections (nodes,node,x,z,y);
}
}
}
}
//Debug.LogError ("No support for Graph Updates to Layered Grid Graphs");
}