예제 #1
0
 public virtual void Collided(PhysicsObject collider, Edge collidingEdge, Vector2 projectionVector, float deltaTime)
 {
 }
예제 #2
0
        private void CheckCollisions(PhysicsObject physicsObject, float deltaTime)
        {
            // Check collision with all objects within our cells

            Bag <PhysicsObject> collidedObjects = new Bag <PhysicsObject>();

            physicsObject.ContainingCells.ForEach((cell) =>
            {
                Bag <PhysicsObject> possibleColliders = _grid[cell.Column, cell.Row];
                possibleColliders.ForEachWith((collider) =>
                {
                    /// IMPLEMENT BETTER MOUDLAR VERSION TO FIGURE OUT IF OBJECTS SHOULD COLLIDE. MAYBE SOMETHING LIKE BITWISE COLLISION GROUPS ETC...
                    if (physicsObject is CharacterObject && collider is CharacterObject)
                    {
                        return;
                    }

                    #region Depricated collision filters
                    /// IMPLEMENT A BETTER MODULAR VERSION TO FIGURE OUT COLLISIONS. MAYBE USE BITWISE COLLISION GROUPS ETC...

                    /*if (physicsObject.Owner != null && physicsObject.Owner.Type == Actor.ActorType.Spirit)
                     * {
                     *  // Spirits don't collide with objects
                     *  if (curCollider.Owner != null && curCollider.Owner.Type == Actor.ActorType.Object)
                     *      continue;
                     * }
                     * if (curCollider.Owner != null && curCollider.Owner.Type == Actor.ActorType.Spirit)
                     * {
                     *  // Spirits don't collide with objects
                     *  if (physicsObject.Owner != null && physicsObject.Owner.Type == Actor.ActorType.Object)
                     *      continue;
                     * }*/
                    #endregion

                    // Don't collide with ourselfs.
                    if (collider == physicsObject)
                    {
                        return;
                    }

                    // Has this object already been checked
                    if (collider.IsCollisionChecked)
                    {
                        return;
                    }

                    #region Collide with AABB shape
                    // Coarse collision.
                    AABB A = physicsObject.BoundingBox;
                    AABB B = collider.BoundingBox;

                    float xDist = Math.Abs(A.Position.X - B.Position.X);
                    float yDist = Math.Abs(A.Position.Y - B.Position.Y);

                    // Project half widths.
                    float xProj = A.XHalfWidth.X + B.XHalfWidth.X;
                    float yProj = A.YHalfWidth.Y + B.YHalfWidth.Y;

                    // Early exit.
                    if (xProj < xDist)
                    {
                        return;
                    }
                    if (yProj < yDist)
                    {
                        return;
                    }
                    #endregion

                    // If we should test AABB only we are done now.
                    if (physicsObject.TestAABBOnly && collider.TestAABBOnly)
                    {
                        #region Test AABB only
                        // Calculate projection vector.
                        Vector2 projectionVector;
                        Vector2 diff = B.Position - A.Position;
                        float xDiff  = ((xProj - xDist) * 1.0f) + ConvertUnits.ToSimUnits(1);
                        float yDiff  = ((yProj - yDist) * 1.0f) + ConvertUnits.ToSimUnits(1);

                        if (xDiff < yDiff)
                        {
                            projectionVector = new Vector2(xDiff * Math.Sign(diff.X), 0);
                        }
                        else
                        {
                            projectionVector = new Vector2(0, yDiff * Math.Sign(diff.Y));
                        }

                        // Are we dealing with sensors
                        if (!physicsObject.IsSensor && !collider.IsSensor)
                        {
                            // Get colliding edge (O(4))
                            Edge collidingEdge = null;
                            if (collider.CollisionShape.Type == Shape.ShapeType.SH_POLYGON)
                            {
                                var poly    = collider.CollisionShape as Polygon;
                                var projDir = Vector2.Normalize(projectionVector);

                                for (int i = 0; i < poly.Edges.Length; i++)
                                {
                                    var edge = poly.Edges[i];
                                    if (Vector2.Dot(projDir, edge.Normal) > 0.9f)
                                    {
                                        collidingEdge = edge;
                                    }
                                }
                            }
                            physicsObject.Collided(collider, collidingEdge, projectionVector, deltaTime);
                        }
                        if (physicsObject.OnCollision != null)
                        {
                            physicsObject.OnCollision(physicsObject, collider, projectionVector);
                        }
                        if (collider.OnCollision != null)
                        {
                            collider.OnCollision(collider, physicsObject, Vector2.Zero);
                        }

                        collider.IsCollisionChecked = true;
                        collidedObjects.Add(collider);
                        #endregion
                    }
                    else
                    {
                        #region Test Polygon
                        if (physicsObject.CollisionShape.Type == Shape.ShapeType.SH_POLYGON &&
                            collider.CollisionShape.Type == Shape.ShapeType.SH_POLYGON)
                        {
                            if (CollidePolyPoly(physicsObject.CollisionShape as Polygon, collider.CollisionShape as Polygon, deltaTime))
                            {
                                collidedObjects.Add(collider);  // Flag object as checked and add to collided list.
                            }
                        }
                        #endregion
                    }
                }, (collider) => { return(collider.IsActive); });
            });

            // Uncheck collision flags for next object
            collidedObjects.ForEach((collider) => { collider.IsCollisionChecked = false; });
        }
예제 #3
0
 public Shape(PhysicsObject owner)
 {
     Owner = owner;
 }
예제 #4
0
        private bool CheckLineCollisions(int col, int row, Line line, RayCastCallback callback, bool isFirst, bool isLast, bool ignoreSensor, bool ignoreProjectile)
        {
            Bag <PhysicsObject> possibleColliders = _grid[col, row];
            Vector2             collisionPoint    = line.P2;
            Vector2             collisionNormal   = Vector2.Zero;
            PhysicsObject       collidingObject   = null;
            float distance = float.PositiveInfinity;

            if (possibleColliders == null)
            {
                return(false);
            }

            /// I actually don't now why I put this in - it may causes bugs in future but for the moment it seems to work when commented.

            /*if (possibleColliders.Count > 0)
             * {
             *  // Cut out segment within the current cell.
             *  //
             *
             *  // Create a sensor within the cell to collide with
             *  float xCell = (col + 0.5f) * _cellSize + Origin.X;
             *  float yCell = (row + 0.5f) * _cellSize + Origin.Y;
             *
             *  var cellCollider = new Sensor(this, new Vector2(xCell, yCell), new Vector2(_cellSize, _cellSize));
             *
             *  var newStart = Vector2.Zero;
             *  var newEnd = Vector2.Zero;
             *  var newNorm = Vector2.Zero;
             *  var mirrorLine = new Line(line.P2, line.P1);
             *
             *  if (!CollideLinePoly(line, (Polygon)cellCollider.CollisionShape, out newStart, out newNorm))
             *  {
             *      newStart = line.P1;
             *  }
             *  if (!CollideLinePoly(mirrorLine, (Polygon)cellCollider.CollisionShape, out newEnd, out newNorm))
             *  {
             *      newEnd = line.P2;
             *  }
             *
             *  line = new Line(newStart, newEnd);
             *
             *  cellCollider.Dispense(); // Remove from world
             * }*/

            // Test each object to collide with line.
            possibleColliders.ForEachWith((collider) =>
            {
                if (ignoreSensor)
                {
                    if (collider.IsSensor)
                    {
                        return;
                    }
                }

                if (ignoreProjectile)
                {
                    if (collider.IsProjectile)
                    {
                        return;
                    }
                }

                if (collider.CollisionShape.Type == Shape.ShapeType.SH_POLYGON)
                {
                    var poly = collider.CollisionShape as Polygon;
                    if (isFirst)
                    {
                        if (CollidePointPoly(line.P1, poly))
                        {
                            return;
                        }
                    }

                    Vector2 curCollisionPoint, curCollisionNormal;
                    if (CollideLinePoly(line, poly, out curCollisionPoint, out curCollisionNormal))
                    {
                        // Check for closest point
                        float curDistance = (curCollisionPoint - line.P1).Length();
                        if (curDistance < distance)
                        {
                            distance        = curDistance;
                            collidingObject = collider;
                            collisionPoint  = curCollisionPoint;
                            collisionNormal = curCollisionNormal;
                        }
                    }
                }
            }, (collider) => { return(collider.IsActive); });

            if (collidingObject != null)
            {
                callback(collidingObject, collisionPoint, collisionNormal);
                _drawPoints.Add(collisionPoint);
                return(true);
            }

            return(false);
        }
예제 #5
0
        public override void Collided(PhysicsObject collider, Edge collidingEdge, Vector2 projectionVector, float deltaTime)
        {
            if (!IsActive)
            {
                return;
            }

            if (IsEthereal || collider.IsEthereal)
            {
                return;
            }

            _projectionVector = projectionVector;
            // After collision project out of colliding surface.
            Position -= projectionVector;

            if (projectionVector.Length() == 0.0f)  // Return when no projection.
            {
                return;
            }
            // Split reflection velocity into friction and bounce vector.
            var surfaceNorm = Vector2.Normalize(projectionVector);
            var surfaceDir  = new Vector2(surfaceNorm.Y, -surfaceNorm.X);

            _surfaceNormal = surfaceNorm;

            // Get collision point
            //

            // Distance to line
            Vector2 p1             = collidingEdge.P1;
            Vector2 p2             = collidingEdge.P2;
            float   normalLength   = (float)Math.Sqrt((p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y));
            float   dist           = Math.Abs((Position.X - p1.X) * (p2.Y - p1.Y) - (Position.Y - p1.Y) * (p2.X - p1.X)) / normalLength;
            Vector2 collisionPoint = Position + surfaceNorm * dist;

            if ((p1 - collisionPoint).Length() < 0.3f || (p2 - collisionPoint).Length() < 0.3f)
            {
                //Position += surfaceDir * 0.09f * Math.Sign(Velocity.X);
            }

            Vector2 bounce   = surfaceNorm * Vector2.Dot(Velocity, surfaceNorm) * Restitution * -1 * 0;
            Vector2 friction = surfaceDir * Vector2.Dot(Velocity, surfaceDir) * (1 - Friction);

            if (Vector2.Dot(surfaceNorm, Vector2.UnitY) > _maxSlope)
            {
                MotionState = MotionStates.MS_LANDED;

                // Enable character to walk up and down a specific slope at a certain speed
                Vector2 velDirection = surfaceDir;
                if (Vector2.Dot(velDirection, Velocity) < 0)
                {
                    velDirection = -velDirection;
                }

                Velocity = velDirection * Velocity.Length() * Friction;

                // Move with dynamic object.
                if (collider.IsStatic == false)
                {
                    var dynamicObject = collider as DynamicObject;
                    Position += dynamicObject.Velocity * deltaTime;
                }
            }
            else
            {
                _bounceVector   = bounce;
                _frictionVector = friction;

                // Add up to reflection vector.
                _reflectionVector = bounce + friction;
                Velocity          = _reflectionVector;
            }

            // Check if we push colliding object.
            float xProj = Math.Abs(Vector2.Dot(surfaceNorm, Vector2.UnitX));

            if (xProj > 0.9f && xProj < 1.1f)
            {
                CharacterState = CharacterPhysicsState.CPS_PUSHING;
            }
        }