//Test for Sphere --> Sphere Collision public Contact Collides(Sphere sphere) { return base.Collides(this, sphere); }
//Sphere --> Plane Collision Detection and Contact Info generation //Returns null if no collision, a contact object if a collision occurs protected Contact Collides(Sphere sphere, Plane plane) { //Remove the absolute value to allow full penetration of the sphere //float Distance = Vector3.Dot(plane.Normal, sphere.position - plane.position) / plane.Normal.Length(); float Distance = Math.Abs(Vector3.Dot(plane.Normal, sphere.Position - plane.Position)) / plane.Normal.Length(); if (Distance <= sphere.Radius) { Contact contact = new Contact(); contact.ContactType = CollisionType.FaceFace; contact.ContactNormal = plane.Normal; contact.PenetrationDepth = sphere.Radius - Distance; contact.ContactPoint = sphere.Position - contact.ContactNormal * Distance; contact.DeepestPoint = sphere.Position - contact.ContactNormal * (Distance + contact.PenetrationDepth); return contact; } //No Collision return null; }
//Sphere --> Box Collision Detection and Contact Info generation //Returns null if no collision, a contact object if a collision occurs protected Contact Collides(Sphere sphere, Box box) { Contact contact = new Contact(); Vector3[] vertices = box.GetVertices(); //Implementation based on pages 644-645 of Geometric Tools for Computer Graphics [Philip J. Schneider & David H. Eberly, Morgan Kaufmann] //Make sure the sphere is touching the box before continuing //Distance from sphere to each of the box vertices float[] VertexDistances = new float[8]; //Compute distance for (int i = 0; i < vertices.Length; i++) { VertexDistances[i] = (vertices[i] - sphere.Position).Length(); } //Obtain Minimum and Maximum values for X,Y,Z Vector3 min = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); Vector3 max = new Vector3(vertices[0].X, vertices[0].Y, vertices[0].Z); for (int i = 0; i < vertices.Length; i++) { if (min.X > vertices[i].X) min.X = vertices[i].X; if (min.Y > vertices[i].Y) min.Y = vertices[i].Y; if (min.Z > vertices[i].Z) min.Z = vertices[i].Z; if (max.X < vertices[i].X) max.X = vertices[i].X; if (max.Y < vertices[i].Y) max.Y = vertices[i].Y; if (max.Z < vertices[i].Z) max.Z = vertices[i].Z; } //Test for collision double dSquared = 0; if (sphere.Position.X < min.X) { dSquared += (float)Math.Pow((sphere.Position.X - min.X), 2); } else if (sphere.Position.X > max.X) { dSquared += (float)Math.Pow((sphere.Position.X - max.X), 2); } if (sphere.Position.Y < min.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - min.Y), 2); } else if (sphere.Position.Y > max.Y) { dSquared += (float)Math.Pow((sphere.Position.Y - max.Y), 2); } if (sphere.Position.Z < min.Z) { dSquared += (float)Math.Pow((sphere.Position.Z - min.Z), 2); } else if (sphere.Position.Z > max.Z) { float test = sphere.Position.Z - max.Z; dSquared += (float)Math.Pow((sphere.Position.Z - max.Z), 2); } if (dSquared <= Math.Pow(sphere.Radius, 2)) { #region Vertex-Face foreach (Vector3 vertex in vertices) { float Distance = (sphere.Position - vertex).Length(); if (Distance <= sphere.Radius) { Vector3 midline = vertex - sphere.Position; contact.ContactType = CollisionType.VertexFace; contact.ContactNormal = -midline / midline.Length(); contact.ContactPoint = vertex;// sphere.position + (midline * sphere.Radius) / midline.Length(); contact.DeepestPoint = sphere.Position + (midline * sphere.Radius) / midline.Length(); contact.PenetrationDepth = ((vertex - contact.DeepestPoint)).Length(); return contact; } } #endregion #region Face-Face Vector3[] normals = box.GetNormals(); float[] Distances = new float[6]; for (int i = 0; i < normals.Length; i++) { Distances[i] = Vector3.Dot(normals[i], sphere.Position - (box.Position + (normals[i] * box.Size / 2))) / normals[i].Length(); } int index = 0; //The number of faces whose normals are not pointing away from the sphere. int PositiveCount = 0; for (int i = 0; i < Distances.Length; i++) { if (Distances[i] > 0) { if (Distances[i] <= sphere.Radius) { PositiveCount++; } if (Distances[index] > Distances[i] || Distances[index] < 0) { index = i; } } } if (Distances[index] <= sphere.Radius && PositiveCount == 1) { contact = new Contact(); contact.ContactType = CollisionType.FaceFace; contact.ContactNormal = normals[index]; contact.PenetrationDepth = sphere.Radius - Distances[index]; //+ contact.ContactPoint = sphere.Position - contact.ContactNormal * VertexDistances[index]; contact.DeepestPoint = sphere.Position - contact.ContactNormal * (sphere.Radius); return contact; } #endregion #region Edge-Face float[] PointDistances = new float[12]; Vector3[,] VertexPair = new Vector3[12, 2]; //Front Vertices Vector3 x0 = sphere.Position; Vector3 x1 = VertexPair[0, 0] = vertices[0]; Vector3 x2 = VertexPair[0, 1] = vertices[1]; PointDistances[0] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[1, 0] = vertices[1]; x2 = VertexPair[1, 1] = vertices[3]; PointDistances[1] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[2, 0] = vertices[3]; x2 = VertexPair[2, 1] = vertices[2]; PointDistances[2] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[3, 0] = vertices[2]; x2 = VertexPair[3, 1] = vertices[0]; PointDistances[3] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Back Vertices x1 = VertexPair[4, 0] = vertices[4]; x2 = VertexPair[4, 1] = vertices[5]; PointDistances[4] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[5, 0] = vertices[5]; x2 = VertexPair[5, 1] = vertices[7]; PointDistances[5] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[6, 0] = vertices[7]; x2 = VertexPair[6, 1] = vertices[6]; PointDistances[6] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[7, 0] = vertices[6]; x2 = VertexPair[7, 1] = vertices[4]; PointDistances[7] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); //Side Vertices x1 = VertexPair[8, 0] = vertices[0]; x2 = VertexPair[8, 1] = vertices[4]; PointDistances[8] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[9, 0] = vertices[1]; x2 = VertexPair[9, 1] = vertices[5]; PointDistances[9] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[10, 0] = vertices[2]; x2 = VertexPair[10, 1] = vertices[6]; PointDistances[10] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); x1 = VertexPair[11, 0] = vertices[3]; x2 = VertexPair[11, 1] = vertices[7]; PointDistances[11] = Vector3.Cross((x0 - x1), (x0 - x2)).Length() / (x2 - x1).Length(); index = 0; for (int i = 0; i < PointDistances.Length; i++) { if (PointDistances[index] > PointDistances[i]) { index = i; } } if (PointDistances[index] < sphere.Radius) { x1 = VertexPair[index, 0]; x2 = VertexPair[index, 1]; //Required to compute point on the line float t = -Vector3.Dot((x1 - x0), (x2 - x1)) / (x2 - x1).LengthSquared(); Vector3 LinePoint = new Vector3(x1.X + (x2.X - x1.X) * t, x1.Y + (x2.Y - x1.Y) * t, x1.Z + (x2.Z - x1.Z) * t); contact.ContactType = CollisionType.EdgeFace; contact.ContactNormal = Vector3.Normalize(x0 - LinePoint); contact.ContactPoint = LinePoint; contact.DeepestPoint = x0 - contact.ContactNormal / contact.ContactNormal.Length() * sphere.Radius; contact.PenetrationDepth = (contact.DeepestPoint - contact.ContactPoint).Length(); return contact; } #endregion } //No Contact found... return null; }
public Contact Collides(Sphere sphere) { return base.Collides(sphere, this); }
//Sphere --> Sphere Collision Detection and Contact Info generation //Returns null if no collision, a contact object if a collision occurs protected Contact Collides(Sphere sphere1, Sphere sphere2) { if ((sphere1.Position - sphere2.Position).Length() <= (sphere1.Radius + sphere2.Radius)) { Contact contact = new Contact(); contact.ContactType = CollisionType.FaceFace; contact.ContactNormal = (sphere1.Position - sphere2.Position) / (sphere1.Position - sphere2.Position).Length(); Vector3 Midline = (sphere1.Position - sphere2.Position); contact.ContactPoint = sphere2.Position + (Midline / Midline.Length() * sphere2.Radius); contact.DeepestPoint = (sphere1.Position - (Midline / Midline.Length() * sphere1.Radius)); contact.PenetrationDepth = sphere1.Radius + sphere2.Radius - Midline.Length(); return contact; } //No Collision return null; }
//Retrieve Objects nearby given Sphere in the Quad Tree and Superior layers of the quadrant if UpperLayerDepth > 0 public void RetrieveNearbyObjects(Sphere sphere, ref List<Primitive> primitivesNearby, int UpperLayerDepth = 0) { RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, null); }
//Retrieve Objects nearby given Sphere in the Quad Tree and Superior layers of the quadrant if UpperLayerDepth > 0 public void RetrieveNearbyObjects(Sphere sphere, ref List<Primitive> primitivesNearby, int UpperLayerDepth, QuadTreeNode node, int DepthCounter = 0) { if (node == null) node = Head; //Process North-West Part if (node.Children[0] != null) { //If Sphere can be found inside the North West quadrant of the current quadrant or if this depth level should be covered, go inside if ((sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth) { RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[0], DepthCounter + 1); } } //Process North-East Part if (node.Children[1] != null) { //If Sphere can be found inside the North East quadrant of the current quadrant or if this depth level should be covered, go inside if ((sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth) { RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[1], DepthCounter + 1); } } //Process South-West Part if (node.Children[2] != null) { //If Sphere can be found inside the South West quadrant of the current quadrant or if this depth level should be covered, go inside if ((sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth) { RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[2], DepthCounter + 1); } } //Process South-East Part if (node.Children[3] != null) { //If Sphere can be found inside the South West quadrant of the current quadrant or if this depth level should be covered, go inside if ((sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) || (this.depth - DepthCounter) <= UpperLayerDepth) { RetrieveNearbyObjects(sphere, ref primitivesNearby, UpperLayerDepth, node.Children[3], DepthCounter + 1); } } //Return all primitives found in the node if (node.Primitives != null) { //Add all primitives found in the quadrant that aren't already in the list foreach (Primitive prim in node.Primitives) { if (!primitivesNearby.Contains(prim)) { primitivesNearby.Add(prim); } } } }
private void ResolveStaticCollision(Contact contact, Entity ent, Sphere sphere) { //-contact.ContactNormal * (Vector3.Dot(-contact.ContactNormal, ent.Velocity)); Vector3 closingVelocity = contact.ContactNormal * contact.PenetrationDepth; //The Y axis vector value of the position should always remain zero. closingVelocity.Y = 0; ent.Position += closingVelocity; if (ent is Hero) { CastSoundWave(COLLISON_SOUND_RADIUS); } }
//Return boxes that generate Quad Tree Grid. It is possible to filter lower levels and display only higher ones by setting UpperLayerDepth to a value > 0 public List<Box> RetrieveBoundariesFromPosition(Sphere sphere, ref List<Box> boxes, int UpperLayerDepth = 0, QuadTreeNode node = null) { if (node == null) node = Head; if (boxes == null) boxes = new List<Box>(); float nodeSize = (float)Math.Pow(2, UpperLayerDepth); //Make sure sphere fits in the current node and go deeper if (sphere.Radius * 2 < node.Size / nodeSize) { //Process North-West Part if (node.Children[0] != null) { if (sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) { RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[0]); } } //Process North-East Part if (node.Children[1] != null) { if (sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z + sphere.Radius <= node.Position.Y) { RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[1]); } } //Process South-West Part if (node.Children[2] != null) { if (sphere.Position.X - sphere.Radius <= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) { RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[2]); } } //Process South-East Part if (node.Children[3] != null) { if (sphere.Position.X + sphere.Radius >= node.Position.X && sphere.Position.Z - sphere.Radius >= node.Position.Y) { RetrieveBoundariesFromPosition(sphere, ref boxes, UpperLayerDepth, node.Children[3]); } } } //return box sized based on depth level boxes.Add(new Box(new Vector3(node.Position.X, 1.5f, node.Position.Y), new Vector3(0), new Vector3(node.Size * 2, 3, node.Size * 2))); return boxes; }
//checking zombie to zombie collisions. //Model as a sphere (in reality just a cylinder but since all at same height it only checks for a circle radius around character private void checkZombietoZombie(Zombie z1, Zombie z2) { //creating appropriate shapes Sphere p1 = new Collisions.Sphere(z1.Position, z1.Velocity, z1.modelRadius); Sphere p2 = new Collisions.Sphere(z2.Position, z2.Velocity, z2.modelRadius); Contact c = p1.Collides(p2); if (c != null) { if (c.DeepestPoint.Length() > 0) { z1.Position -= c.DeepestPoint - c.ContactPoint; z2.Position += c.DeepestPoint - c.ContactPoint; } } }
private void DoGunAttack(Weapon weapon, Entity actionCaster) { //do soundeffect attached if (weapon.weaponType == WeaponType.Handgun9mm) { if (Player.PowerupsList.Contains(silencer)) { sound.StopSilencer(); //need to check the time sound.playSilencer(); } else { sound.Stopgun(); sound.playgun(); } } if (weapon.weaponType == WeaponType.Magnum) { sound.StopMagnum(); //need to check the time sound.playMagnum(); } // find closest zombie, if any, in the line of fire and have him take the damage Ray ray = new Ray(actionCaster.Position, Vector3.Normalize(actionCaster.Velocity)); Zombie closestVictim = null; float? closestIntersect = 100; foreach (Zombie z in zombies) { if ((z.Position - actionCaster.Position).Length() < weapon.Range) { BoundingSphere bs = new BoundingSphere(z.Position, z.modelRadius); float? intersection = ray.Intersects(bs); if (intersection != null && intersection < closestIntersect) { closestIntersect = intersection; closestVictim = z; } } } // check if ray intersects nearby primitives from quad tree // if so, check if intersections are closer than the closest zombie intersection Sphere heroSphere = new Sphere(actionCaster.Position, actionCaster.Velocity, actionCaster.modelRadius); List<Primitive> primitives = new List<Primitive>(); LevelQuadTree.RetrieveNearbyObjects(heroSphere, ref primitives); foreach (Box box in primitives) { BoundingBox bbox = new BoundingBox( new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2), new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2) ); if (ray.Intersects(bbox) != null && ray.Intersects(bbox) < closestIntersect) return; } if (closestVictim != null) { closestVictim.Alert(actionCaster as Hero); if (weapon.weaponType == WeaponType.Magnum && closestIntersect > 20) closestVictim.TakeDamage(weapon.FirePower / 10); else if (weapon.weaponType == WeaponType.Magnum && closestIntersect > 10) closestVictim.TakeDamage(weapon.FirePower / 5); else closestVictim.TakeDamage(weapon.FirePower); } }
//checking zombie to character private void checkZombietoPlayer(Zombie z) { Sphere p1 = new Collisions.Sphere(z.Position, z.Velocity, z.modelRadius); Sphere p2 = new Collisions.Sphere(Player.Position, Player.Velocity, Player.modelRadius); Contact c = p1.Collides(p2); if (c != null) { if (c.DeepestPoint.Length() > 0) { if (Player.Stance == AnimationStance.Standing)//if standing, dont push player, only affect zombie { z.Position -= c.DeepestPoint - c.ContactPoint; Player.Position += c.DeepestPoint - c.ContactPoint; } else//push player back when walking { z.Position -= c.DeepestPoint - c.ContactPoint; } } } }
// returns if there are any static obstructions between the two positions private bool CheckObstructions(Vector3 position, Vector3 destination) { Ray ray = new Ray(position, Vector3.Normalize(destination - position)); Sphere sphere = new Sphere(position, Vector3.Zero, 1); List<Primitive> primitives = new List<Primitive>(); LevelQuadTree.RetrieveNearbyObjects(sphere, ref primitives); foreach (Box box in primitives) { BoundingBox bbox = new BoundingBox( new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2), new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2) ); if (ray.Intersects(bbox) != null) return true; } return false; }
private void CheckCollisions(bool Extinguisher) { #region Player collisions Sphere heroSphere = new Sphere(Player.Position, Player.Velocity, Player.modelRadius); List<Primitive> primitivesNearby = new List<Primitive>(); LevelQuadTree.RetrieveNearbyObjects(heroSphere, ref primitivesNearby,2); /*foreach (Primitive bx in primitivesNearby) { if (!TotalNearbyBoxes.Contains(bx)) TotalNearbyBoxes.Add(bx); }*/ Contact EndingContact = heroSphere.Collides(EscapeSpot); if (EndingContact != null && (Player.ItemsList.ContainsKey(key1) || Player.ItemsList.ContainsKey(key2))) { GameStates.GameStates.ZombieGameState = GameStates.GameStates.GameState.End; } primitivesNearby.AddRange(fireHazards); foreach (Primitive p in primitivesNearby) { Contact c = heroSphere.Collides(p as Box); if (c != null) { ResolveStaticCollision(c, Player, heroSphere); if(fireDamageDelay <=0) { if(((Box)p).Tag == "Fire1" || ((Box)p).Tag == "Fire2" || ((Box)p).Tag == "Fire3" || ((Box)p).Tag == "Fire4") { Player.TakeDamage(25); fireDamageDelay = 5; } } } } if (Extinguisher) { Sphere ExtSphere = new Sphere(Player.Position + (Player.Velocity / Player.Velocity.Length()) * 20, Vector3.One, 10); for (int i = 0; i < fireHazards.Count;i++) { Sphere boxSphere = new Sphere(fireHazards[i].Position, Vector3.One, fireHazards[i].Size.X / 2); Contact contact = ExtSphere.Collides(boxSphere); if (contact != null) { if (fireHazards[i].Tag == "Fire1") { FireEmitter.particleGroups[0].controller.LifeSpan -= 5; if (FireEmitter.particleGroups[0].controller.LifeSpan <= 0) { FireEmitter.Stop(); fireHazards.Remove(fireHazards[i]); } } if (fireHazards.Count > 0) { if (fireHazards[i].Tag == "Fire2") { FireEmitter2.particleGroups[0].controller.LifeSpan -= 5; if (FireEmitter2.particleGroups[0].controller.LifeSpan <= 0) { FireEmitter2.Stop(); fireHazards.Remove(fireHazards[i]); } } if (fireHazards[i].Tag == "Fire3") { FireEmitter3.particleGroups[0].controller.LifeSpan -= 5; if (FireEmitter3.particleGroups[0].controller.LifeSpan <= 0) { FireEmitter3.Stop(); fireHazards.Remove(fireHazards[i]); } } if (fireHazards[i].Tag == "Fire4") { FireEmitter4.particleGroups[0].controller.LifeSpan -= 5; if (FireEmitter4.particleGroups[0].controller.LifeSpan <= 0) { FireEmitter4.Stop(); fireHazards.Remove(fireHazards[i]); } } } } } } #endregion #region Zombie collisions foreach (Zombie z in zombies) { // Check for zombies in sight radius and zombies who are not wandering if ((z.Position - Player.Position).Length() < SIGHT_RADIUS || z.BehaviouralState != BehaviourState.Wander) { Sphere zombieSphere = new Sphere(z.Position, z.Velocity, z.modelRadius); List<Primitive> primitives = new List<Primitive>(); LevelQuadTree.RetrieveNearbyObjects(zombieSphere, ref primitives); primitives.AddRange(fireHazards); foreach (Primitive p in primitives) { Contact c = zombieSphere.Collides(p as Box); if (c != null) { if (z.BehaviouralState == BehaviourState.Wander) z.Velocity = Vector3.Cross( z.Velocity, Vector3.Up); ResolveStaticCollision(c, z, zombieSphere); } } } } #endregion foreach (Zombie z1 in zombies) { if ((z1.Position - Player.Position).Length() < SIGHT_RADIUS || z1.BehaviouralState != BehaviourState.Wander) { checkZombietoPlayer(z1); foreach (Zombie z2 in zombies) { if (!z2.Equals(z1) && ((z2.Position - Player.Position).Length() < SIGHT_RADIUS || z2.BehaviouralState != BehaviourState.Wander)) { checkZombietoZombie(z1, z2); } } } } checkItemCollisions(); }
// Creates a bounding sphere with the specified radius. Any Zombie intersecting the // bounding sphere will be alerted to the Hero's presence private void CastSoundWave(float radius) { if (radius > 0) { Sphere soundSphere = new Sphere(Player.Position, new Vector3(), radius); foreach (Zombie z in zombies) { Sphere zs = new Sphere(z.Position, z.Velocity, z.modelRadius); if (zs.Collides(soundSphere) != null) z.Alert(Player); } } }
// get closest feasible pathfinding node to the given position public PathFinding.Node GetPathfindingNode(Vector3 position, Vector3 destination) { // perform super secret second purpose if (destination != Vector3.Up) { // if path between positions is clear, return origin, else return up vector if (CheckObstructions(position, destination)) return new PathFinding.Node(Vector3.Up); else return new PathFinding.Node(Vector3.Zero); } List<PathFinding.Node> possibleMatches = new List<PathFinding.Node>(); PathFinding.Node reachableNode = null; float distanceToNode = 100; LevelQuadTree.RetrieveNearbyObjects(position, ref possibleMatches, 2, null, 2); foreach (PathFinding.Node node in possibleMatches) { float separatingDistance = (node.position - position).Length(); bool clearPath = true; Ray ray = new Ray(position, Vector3.Normalize(node.position - position)); Sphere sphere = new Sphere(position, Vector3.Zero, 1); List<Primitive> primitives = new List<Primitive>(); LevelQuadTree.RetrieveNearbyObjects(sphere, ref primitives); foreach (Box box in primitives) { BoundingBox bbox = new BoundingBox( new Vector3(box.Position.X - box.Size.X / 2, box.Position.Y - box.Size.Y / 2, box.Position.Z - box.Size.Z / 2), new Vector3(box.Position.X + box.Size.X / 2, box.Position.Y + box.Size.Y / 2, box.Position.Z + box.Size.Z / 2) ); if (ray.Intersects(bbox) != null && ray.Intersects(bbox) < separatingDistance) { clearPath = false; break; } } if (clearPath && distanceToNode > separatingDistance) { distanceToNode = separatingDistance; reachableNode = node; } } return reachableNode; }