Пример #1
0
        protected override CollisionResult IsOverlappingBox(BoundingBox other)
        {
            // First trivial case.
            #region SPHERE_CHECK
            BoundingSphere sphere = new BoundingSphere();
            sphere.Center = other.GlobalCenter();
            sphere.Radius = other.HalfDiagonal();

            CollisionResult resSphere = sphere.IsOverlapping(this);
            if (!resSphere.CollisionDetected)
            {
                return(resSphere);
            }
            #endregion

            // Need to check if any of the faces of the cube are intersecting sphere.
            bool inside = true;
            // First find intersection point with plane of the face, then check if casted circle intersects face.
            #region PLANES_VERTICES_DEFINITION
            Vector3[] faceCorners = other.Corners();
            Vector3   center      = GlobalCenter();
            Plane[]   planes      = new Plane[6]
            {
                other.FrontFace(), other.BackFace(),
                      other.LeftFace(), other.RightFace(),
                      other.UpFace(), other.DownFace()
            };
            // Corners: 0 - right upper front, 1 - left upper front, 2 - left lower front,
            // 3 - right lower front, 4 - right upper back, 5 - left upper back,
            // 6 - left lower back, 7 - right lower back.
            int[] ind = new int[24]
            {
                0, 1, 2, 3,
                4, 5, 6, 7,
                5, 1, 2, 6,
                4, 0, 3, 7,
                0, 1, 5, 4,
                3, 2, 6, 7
            };
            #endregion

            for (int i = 0; i < 6; ++i)
            {
                float t = planes[i].D - Vector3.Dot(planes[i].Normal, center);
                if (t < 0.0f)
                {
                    inside = false;
                }
                if (Math.Abs(t) <= radius)
                {
                    // Check if circle created by casting sphere on plane intersect with box's face.
                    Vector3 intersect   = center + t * planes[i].Normal;
                    float   interRadius = (float)Math.Sqrt(radius * radius - t * t);
                    // Trivial check.
                    #region CIRCLE_CHECK
                    Vector3 faceCenter = (faceCorners[ind[4 * i]] + faceCorners[ind[4 * i + 2]]) / 2.0f;
                    if (interRadius + Vector3.Distance(faceCenter, faceCorners[ind[4 * i]]) < Vector3.Distance(intersect, faceCenter))
                    {
                        continue;
                    }
                    #endregion
                    // Intersection if circle's center lies in rectangle.
                    // 0 <= AP*AB <= AB*AB && 0 <= AP*AD <= AD*AD
                    #region CIRCLE_CENTER_INSIDE_FACE
                    Vector3 AP   = intersect - faceCorners[ind[4 * i]];
                    Vector3 AB   = faceCorners[ind[4 * i + 1]] - faceCorners[ind[4 * i]];
                    Vector3 AD   = faceCorners[ind[4 * i + 3]] - faceCorners[ind[4 * i]];
                    float   APAB = Vector3.Dot(AP, AB);
                    float   APAD = Vector3.Dot(AP, AD);
                    if (APAB >= 0 && APAB <= AB.LengthSquared() && APAD >= 0 && APAD <= AD.LengthSquared())
                    {
                        return(new CollisionResult(true, planes[i], null, intersect));
                    }
                    #endregion
                    // Intersection if any edge lies close enough and shares at least one point with circle.
                    for (int j = 0; j < 4; ++j)
                    {
                        #region EDGE_INTERSECT_CIRCLE
                        AP = intersect - faceCorners[ind[4 * i + j]];
                        AB = faceCorners[ind[4 * i + ((j + 1) % 4)]] - faceCorners[ind[4 * i + j]];
                        float t1 = Vector3.Dot(AP, AB) / AB.LengthSquared();
                        if (t1 > 0.0f && t1 < 1.0f)
                        {
                            Vector3 X = faceCorners[ind[4 * i + j]] + t1 * AB;
                            if ((X - intersect).LengthSquared() <= interRadius)
                            {
                                return(new CollisionResult(true, planes[i], null, X));
                            }
                        }
                        // Check vertices of the edge.
                        if (AP.LengthSquared() <= interRadius)
                        {
                            return(new CollisionResult(true, planes[i], null, faceCorners[ind[4 * i + j]]));
                        }
                        if ((faceCorners[ind[4 * i + ((j + 1) % 4)]] - intersect).LengthSquared() <= interRadius)
                        {
                            return(new CollisionResult(true, planes[i], null, faceCorners[ind[4 * i + ((j + 1) % 4)]]));
                        }
                        #endregion
                    }
                }
            }

            // The sphere can still be inside the box without touching it.
            if (inside)
            {
                Vector3 otherCenter = other.GlobalCenter();
                Vector3 centerDiff  = center - otherCenter;
                centerDiff.Normalize();
                return(new CollisionResult(true, new Plane(centerDiff, Vector3.Dot(otherCenter, centerDiff)), new Plane(-centerDiff, Vector3.Dot(center, centerDiff)), otherCenter));
            }
            else
            {
                return(new CollisionResult());
            }
        }
Пример #2
0
        public void Update(GameTime gameTime)
        {
            sceneTime += (float)gameTime.ElapsedGameTime.TotalSeconds;

            foreach (GraphNode <Room, BoundingBox> node in roomGraph)
            {
                Room room = node.Value;
                room.go.Update(gameTime);
            }

            foreach (GameObject go in objectsToDestroy)
            {
                go.Destroy();
            }
            objectsToDestroy.Clear();

            foreach (GameObject go in objectsToRespace)
            {
                RemoveObject(go);

                foreach (GraphNode <Room, BoundingBox> node in roomGraph)
                {
                    if (node.Value.go.Bound.Intersects(go.Bound))
                    {
                        node.Value.contents.Add(go);
                    }
                }
            }
            objectsToRespace.Clear();

            foreach (GraphNode <Room, BoundingBox> node in roomGraph)
            {
                foreach (GameObject go in node.Value.contents)
                {
                    Collider  goCol = go.GetComponent <Collider>();
                    Rigidbody rig   = go.GetComponent <Rigidbody>();
                    if (goCol != null && rig != null)
                    {
                        bool grounded = false;
                        foreach (GameObject go2 in node.Value.contents)
                        {
                            Collider go2Col = go2.GetComponent <Collider>();
                            if (go2Col != null && !go.Equals(go2))
                            {
                                if (go2Col.IsTrigger)
                                {
                                    if (go.Name == "Player")
                                    {
                                        Bounding_Volumes.CollisionResult col = goCol.Collide(go2Col);
                                        if (col.CollisionDetected)
                                        {
                                            go2Col.Trigger();
                                        }
                                        else
                                        {
                                            go2Col.Untrigger();
                                        }
                                    }
                                }
                                else
                                {
                                    Bounding_Volumes.CollisionResult collision = goCol.Collide(go2Col);
                                    if (collision.CollisionDetected)
                                    {
                                        float lostVel = Vector3.Dot(collision.CollisionPlane.Value.Normal, rig.Velocity);
                                        if (lostVel < 0.0f)
                                        {
                                            Vector3 lostVelocity = -collision.CollisionPlane.Value.Normal * lostVel;
                                            rig.AddVelocityChange(lostVelocity);
                                            if (rig.IsGrounded || !rig.GravityEnabled)
                                            {
                                                go.GlobalPosition = go.GlobalPosition + lostVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
                                            }
                                        }
                                        if (Vector3.Dot(collision.CollisionPlane.Value.Normal, Vector3.Up) > 0.8f)
                                        {
                                            if (!rig.IsGrounded && rig.GravityEnabled)
                                            {
                                                go.GlobalPosition = go.GlobalPosition + collision.CollisionPlane.Value.Normal * lostVel * (float)gameTime.ElapsedGameTime.TotalSeconds;
                                            }
                                            rig.IsGrounded = true;
                                            grounded       = true;
                                        }
                                    }
                                }
                            }
                        }

                        /*foreach(GraphNode<Room, BoundingBox> neighbour in node.Neighbours)
                         * {
                         *  foreach(GameObject go2 in neighbour.Value.contents)
                         *  {
                         *      Collider go2Col = go2.GetComponent<Collider>();
                         *      if (go2Col != null && !go.Equals(go2))
                         *      {
                         *          Bounding_Volumes.CollisionResult collision = goCol.Collide(go2Col);
                         *          if (collision.CollisionDetected)
                         *          {
                         *              float lostVel = Vector3.Dot(collision.CollisionPlane.Value.Normal, rig.Velocity);
                         *              if (lostVel < 0.0f)
                         *              {
                         *                  Vector3 lostVelocity = -collision.CollisionPlane.Value.Normal * lostVel;
                         *                  rig.AddVelocityChange(lostVelocity);
                         *                  if (rig.IsGrounded) go.GlobalPosition = go.GlobalPosition + lostVelocity * (float)gameTime.ElapsedGameTime.TotalSeconds;
                         *              }
                         *              if (Vector3.Dot(collision.CollisionPlane.Value.Normal, Vector3.Up) > 0.8f)
                         *              {
                         *                  if (!rig.IsGrounded) go.GlobalPosition = go.GlobalPosition + collision.CollisionPlane.Value.Normal * lostVel * (float)gameTime.ElapsedGameTime.TotalSeconds;
                         *                  rig.IsGrounded = true;
                         *                  grounded = true;
                         *              }
                         *          }
                         *      }
                         *  }
                         * }*/

                        if (!grounded)
                        {
                            rig.IsGrounded = false;
                        }
                    }
                }
            }
        }