public override void Update()
        {
            // Return to normal if not in a hole.
            if (!monster.Physics.IsInHole) {
                monster.BeginNormalState();
                return;
            }

            // Slip toward the hole's center.
            float slipSpeed = 0.2f;
            Point2I tileLocation = monster.RoomControl.GetTileLocation(monster.Position);
            Vector2F tilePosition = tileLocation * GameSettings.TILE_SIZE;
            Vector2F tileCenter = tilePosition + new Vector2F(8, 8);
            Rectangle2F holeRect = new Rectangle2F(tilePosition.X + 6, tilePosition.Y + 8, 4, 6);

            bool fallInHole = holeRect.Contains(monster.Position);

            Vector2F trajectory = tileCenter - monster.Center;
            if (trajectory.Length > slipSpeed) {
                monster.Physics.Velocity = (tileCenter - monster.Center).Normalized * slipSpeed;
            }
            else {
                fallInHole = true;
                monster.Physics.Velocity = Vector2F.Zero;
                monster.SetPositionByCenter(tileCenter);
            }

            if (fallInHole) {
                monster.RoomControl.SpawnEntity(new EffectFallingObject(), monster.Center);
                AudioSystem.PlaySound(GameData.SOUND_OBJECT_FALL);
                monster.Destroy();
            }
        }
Пример #2
0
 // Returns true if the specified rectangle is colliding with this rectangle.
 public bool Colliding(Rectangle2F rect)
 {
     if (IsEmpty || rect.IsEmpty)
     {
         return(false);
     }
     return((rect.Min < Max) &&
            (rect.Max > Min));
 }
Пример #3
0
 // Returns true if the specified rectangle is inside this rectangle.
 public bool Contains(Rectangle2F rect)
 {
     if (IsEmpty || rect.IsEmpty)
     {
         return(false);
     }
     return((rect.Min >= Min) &&
            (rect.Max <= Max));
 }
Пример #4
0
 // Return whether this and another rectangle are intersecting.
 public bool Intersects(Rectangle2F other)
 {
     if (IsEmpty && other.IsEmpty)
     {
         return(false);
     }
     return(!(other.Left - Right >= 0 || other.Top - Bottom >= 0 ||
              Left - other.Right >= 0 || Top - other.Bottom >= 0));
 }
Пример #5
0
        // Creates a new rectangle that exactly contains two other rectangles.
        public static Rectangle2F Union(Rectangle2F r1, Rectangle2F r2)
        {
            float x1 = Math.Min(r1.Left, r2.Left);
            float y1 = Math.Min(r1.Top, r2.Top);
            float x2 = Math.Max(r1.Right, r2.Right);
            float y2 = Math.Max(r1.Bottom, r2.Bottom);

            return(new Rectangle2F(x1, y1, x2 - x1, y2 - y1));
        }
Пример #6
0
        //-----------------------------------------------------------------------------
        // Static methods
        //-----------------------------------------------------------------------------
        public static bool Intersecting(CollisionModel model,
										Vector2F modelPosition,
										Rectangle2F box,
										Vector2F boxPosition)
        {
            Rectangle2F boxTranslated = Rectangle2F.Translate(box, boxPosition - modelPosition);
            for (int i = 0; i < model.boxes.Count; i++) {
                Rectangle2F modelBox = model.boxes[i];
                if (boxTranslated.Intersects(modelBox))
                    return true;
            }
            return false;
        }
Пример #7
0
        //-----------------------------------------------------------------------------
        // Static methods
        //-----------------------------------------------------------------------------

        // Returns the intersection between two rectangles.
        // Returns the Empty rect if there is no intersection.
        public static Rectangle2F Intersect(Rectangle2F r1, Rectangle2F r2)
        {
            float x1 = Math.Max(r1.Left, r2.Left);
            float y1 = Math.Max(r1.Top, r2.Top);
            float x2 = Math.Min(r1.Right, r2.Right);
            float y2 = Math.Min(r1.Bottom, r2.Bottom);

            if (x2 > x1 && y2 > y1)
            {
                return(new Rectangle2F(x1, y1, x2 - x1, y2 - y1));
            }
            return(Rectangle2F.Zero);
        }
Пример #8
0
        public static bool Intersecting(CollisionModel model,
                                        Vector2F modelPosition,
                                        Rectangle2F box,
                                        Vector2F boxPosition)
        {
            Rectangle2F boxTranslated = Rectangle2F.Translate(box, boxPosition - modelPosition);

            for (int i = 0; i < model.boxes.Count; i++)
            {
                Rectangle2F modelBox = model.boxes[i];
                if (boxTranslated.Intersects(modelBox))
                {
                    return(true);
                }
            }
            return(false);
        }
Пример #9
0
        private float zVelocity; // Z-Velocity in pixels per frame.

        #endregion Fields

        #region Constructors

        //-----------------------------------------------------------------------------
        // Constructors
        //-----------------------------------------------------------------------------
        // By default, physics are disabled.
        public PhysicsComponent(Entity entity)
        {
            this.isEnabled			= false;
            this.flags				= PhysicsFlags.None;
            this.entity				= entity;
            this.velocity			= Vector2F.Zero;
            this.zVelocity			= 0.0f;
            this.gravity			= GameSettings.DEFAULT_GRAVITY;
            this.maxFallSpeed		= GameSettings.DEFAULT_MAX_FALL_SPEED;
            this.collisionBox		= new Rectangle2F(-4, -10, 8, 9);		// TEMPORARY: this is the player collision box.
            this.softCollisionBox	= new Rectangle2F(-6, -14, 12, 13);	// TEMPORARY: this is the player collision box.
            this.topTileFlags		= TileFlags.None;
            this.allTileFlags		= TileFlags.None;
            this.isColliding		= false;
            this.autoDodgeDistance	= 6;

            this.hasLanded			= false;

            this.collisionInfo = new CollisionInfo[Directions.Count];
            for (int i = 0; i < Directions.Count; i++)
                collisionInfo[i].Clear();
        }
Пример #10
0
 /** <summary> Returns true if the specified rectangle is colliding with this line. </summary> */
 public bool Colliding(Rectangle2F rect)
 {
     if (IsEmpty || rect.IsEmpty)
     {
         return(false);
     }
     if (!Bounds.Colliding(rect) && !IsStraight)
     {
         return(false);
     }
     if (rect.Contains(End1))
     {
         return(true);
     }
     foreach (Line2F l in rect.Lines)
     {
         if (Colliding(l))
         {
             return(true);
         }
     }
     return(false);
 }
Пример #11
0
 // Creates a copy of a rectangle translated by an amount.
 public static Rectangle2F Translate(Rectangle2F r, float x, float y)
 {
     r.Point.X += x;
     r.Point.Y += y;
     return(r);
 }
Пример #12
0
        // Determine the clipping direction for a collision.
        private int GetCollisionClipDirection(Entity entity, object other, Rectangle2F solidBox)
        {
            Rectangle2F entityBox = entity.Physics.PositionedCollisionBox;

            // For moving tiles, use the move direction to determine clip direction.
            Tile tile = other as Tile;
            if (tile != null && tile.IsMoving) {
                if ((solidBox.Center - entityBox.Center).Dot(Directions.ToVector(tile.MoveDirection)) < 0.0f)
                    return Directions.Reverse(tile.MoveDirection);
            }

            // Get the nearest direction from the collision intersection to the center of the solid box.
            Vector2F intersectionCenter = Rectangle2F.Intersect(entityBox, solidBox).Center;
            int clipDirection = Directions.NearestFromVector(solidBox.Center - intersectionCenter);

            // If the collision can't be resolved, then try to use a direction on the opposite axis.
            CollisionInfoNew testCollision = CreateCollisionInfo(entity, other, solidBox, clipDirection);
            if (!testCollision.IsAllowedClipping && !CanResolveCollision(entity, testCollision)) {
                int newClipDirection;
                int a = 1 - Directions.ToAxis(clipDirection);
                if (entityBox.Center[a] < solidBox.Center[a])
                    newClipDirection = (a == Axes.X ? Directions.Right : Directions.Down);
                else
                    newClipDirection = (a == Axes.X ? Directions.Left : Directions.Up);
                testCollision = CreateCollisionInfo(entity, other, solidBox, newClipDirection);
                if (testCollision.IsAllowedClipping || CanResolveCollision(entity, testCollision))
                    clipDirection = newClipDirection;
            }

            return clipDirection;
        }
Пример #13
0
 // Calculate a collision's penetration distance in the given direction.
 public float GetClipPenetration(Rectangle2F entityBox, Rectangle2F solidBox, int clipDirection)
 {
     if (clipDirection == Directions.Right)
         return entityBox.Right - solidBox.Left;
     else if (clipDirection == Directions.Up)
         return solidBox.Bottom - entityBox.Top;
     else if (clipDirection == Directions.Left)
         return solidBox.Right - entityBox.Left;
     else if (clipDirection == Directions.Down)
         return entityBox.Bottom - solidBox.Top;
     return 0.0f;
 }
Пример #14
0
        // Resolve any movement collision between the entity and a solid object
        private void ResolveMovementCollision(Entity entity, int axis, object other, Rectangle2F solidBox)
        {
            // Setup the entity's translated collision box based on which axis we're checking.
            Rectangle2F entityBox;
            if (axis == Axes.X) {
                entityBox = Rectangle2F.Translate(
                    entity.Physics.CollisionBox, entity.X + entity.Physics.Velocity.X, entity.Y);
            }
            else {
                entityBox = Rectangle2F.Translate(
                    entity.Physics.CollisionBox, entity.Position + entity.Physics.Velocity);
            }

            // Check if there actually is a collision.
            if (!entityBox.Intersects(solidBox))
                return;

            // Determine clipping direction.
            int clipDirection = -1;
            if (axis == Axes.X) {
                if (entityBox.Center.X < solidBox.Center.X)
                    clipDirection = Directions.Right;
                else
                    clipDirection = Directions.Left;
            }
            else {
                if (entityBox.Center.Y < solidBox.Center.Y)
                    clipDirection = Directions.Down;
                else
                    clipDirection = Directions.Up;
            }

            // Ignore collision if the entity is already colliding in the opposite
            // direction or if the entity is not moving in the clip direction.
            if (entity.Physics.ClipCollisionInfo[Directions.Reverse(clipDirection)].IsCollidingAndNotAllowedClipping ||
                entity.Physics.Velocity.Dot(Directions.ToVector(clipDirection)) <= 0.0f)
                return;

            // Ignore collisions that are within the allowed clipping range.
            if (IsSafeClipping(entity, 1 - axis, entityBox, other, solidBox))
                return;

            // Ignore the collision if the entity is clipped into a solid object that shares
            // a clip edge with this object and the entity is also moving parallel with that edge.
            for (int i = 0; i < 2; i++) {
                int dir = Axes.GetOpposite(axis) + (i * 2);
                CollisionInfoNew checkCollision = entity.Physics.ClipCollisionInfo[dir];
                if (checkCollision.IsColliding && AreEdgesAligned(
                    checkCollision.CollisionBox, solidBox, Directions.Reverse(dir)))
                {
                    return;
                }
            }

            // Resolve the collision.
            if (!entity.Physics.IsColliding && !entity.Physics.ClipCollisionInfo[clipDirection].IsColliding) {
                // Determine the penetration.
                float penetrationDistance = GetClipPenetration(entityBox, solidBox, clipDirection);
                float maxAllowedPenetration = 0.0f;
                if (entity.Physics.Velocity[axis] == 0.0f)
                    maxAllowedPenetration = GetAllowedEdgeClipAmount(entity, other);

                // Snap the entity's position to the edge of the solid object.
                Vector2F newPos = entity.Position;
                newPos[axis] += entity.Physics.Velocity[axis];
                newPos -= Directions.ToVector(clipDirection) * penetrationDistance;
                if (penetrationDistance <= maxAllowedPenetration)
                    newPos += Directions.ToVector(clipDirection) * penetrationDistance;
                entity.Position = newPos;

                entity.Physics.CollisionInfo[clipDirection].SetCollision(other, clipDirection);
            }

            // Zero the entity's velocity for this axis.
            Vector2F velocity = entity.Physics.Velocity;
            velocity[axis] = 0.0f;
            entity.Physics.Velocity = velocity;

            entity.Physics.MovementCollisions[clipDirection] = true;
            if (!entity.Physics.CollisionInfo[clipDirection].IsColliding)
                entity.Physics.CollisionInfo[clipDirection].SetCollision(other, clipDirection);

            // Perform collision dodging.
            bool canDodge = true;
            if (entity is Player) // TODO: this won't work for when player is knocked back
                canDodge = ((Player) entity).Movement.AllowMovementControl && Controls.Arrows[clipDirection].IsDown();
            if (entity.Physics.AutoDodges && canDodge) {
                if (roomControl.IsSideScrolling && axis == Axes.X &&
                    (!(entity is Player) || !((Player) entity).Movement.IsOnSideScrollLadder || ((other is Tile) && ((Tile) other).IsInMotion)) &&
                    (entity.IsOnGround || entity.Physics.PreviousCollisionInfo[Directions.Down].IsColliding))
                {
                    // Step up onto blocks if it is a small enough distance.
                    PerformSideScrollCollisionSnap(entity, clipDirection, other, solidBox);
                }
                else {
                    // Auto dodging.
                    PerformCollisionDodge(entity, clipDirection, other, solidBox);
                }
            }
        }
Пример #15
0
 // Create a clip collision info between an entity and solid object with a specified clip direction.
 private CollisionInfoNew CreateCollisionInfo(Entity entity, object other, Rectangle2F solidBox, int clipDirection)
 {
     return new CollisionInfoNew() {
         IsColliding						= true,
         Entity							= entity,
         CollidedObject					= other,
         CollisionBox					= solidBox,
         PenetrationDirection			= clipDirection,
         PenetrationDistance				= GetClipPenetration(entity.Physics.PositionedCollisionBox, solidBox, clipDirection),
         MaxAllowedPenetrationDistance	= GetAllowedEdgeClipAmount(entity, other)
     };
 }
Пример #16
0
 public CollisionTestSettings(Type entityType, Rectangle2F myBox, Rectangle2F otherBox, float maxZDistance = 10)
 {
     this.requiredType		= entityType;
     this.collisionBox1		= myBox;
     this.collisionBox2		= otherBox;
     this.collisionBoxType1	= CollisionBoxType.Custom;
     this.collisionBoxType2	= CollisionBoxType.Custom;
     this.requiredFlags		= PhysicsFlags.None;
     this.maxZDistance		= maxZDistance;
 }
Пример #17
0
        // Attempt to snap a collision.
        private bool PerformSideScrollCollisionSnap(Entity entity, int direction, object solidObject, Rectangle2F solidBox)
        {
            Rectangle2F entityBox = entity.Physics.PositionedCollisionBox;
            float penetrationDistance = GetClipPenetration(
                entity.Physics.PositionedCollisionBox, solidBox, direction);
            float distanceToEdge = entityBox.Bottom - solidBox.Top;
            //Vector2F goalPosition = entity.Position + Directions.ToVector(direction) +
                //(Directions.ToVector(Directions.Up) * distanceToEdge);

            Vector2F goalPosition = entity.Position +
                Directions.ToVector(direction) -
                new Vector2F(0.0f, distanceToEdge);

            // Check if the distance to the edge is within dodge range.
            // Make sure the entity is not colliding when placed at the solid object's edge.
            if (distanceToEdge <= entity.Physics.AutoDodgeDistance &&
                !IsCollidingAt(entity, goalPosition, false, direction, penetrationDistance))
            {
                entity.Position = goalPosition;
                entity.Physics.MovementCollisions[Directions.Down] = true;
                entity.Physics.CollisionInfo[Directions.Down].SetCollision(solidObject, Directions.Down);
                return true;
            }
            return false;
        }
Пример #18
0
 // Translates the rectangle based on the translation and precision settings.
 private Rectangle NewRect(Rectangle2F destinationRect)
 {
     if (useTranslation)
     return (UseIntegerPrecision ? (Rectangle)new Rectangle2F(GMath.Round(destinationRect.Point + translation), GMath.Round(destinationRect.Size)) : (Rectangle)(destinationRect + translation));
     else
     return (Rectangle)destinationRect;
 }
Пример #19
0
 public void DrawSprite(Sprite sprite, int variantID, Rectangle2F destination, Color color, float depth = 0.0f)
 {
     if (sprite.Image == null)
     return;
     for (Sprite part = sprite; part != null; part = part.NextPart) {
     Image image = sprite.Image.GetVariant(variantID);
     destination.Point = NewPos(destination.Point) + (Vector2F)part.DrawOffset;
     spriteBatch.Draw(image, (Rectangle)destination, (Rectangle)part.SourceRect,
         (XnaColor)color, 0.0f, Vector2.Zero, SpriteEffects.None, depth);
     }
 }
Пример #20
0
 // Draws the specified rectangle.
 public void DrawRectangle(Rectangle2F rect, float thickness, Color color, float depth = 0.0f)
 {
     DrawLine(new Line2F(rect.Point, rect.Point + new Vector2F(rect.Width - 1, 0.0f)), thickness, color, depth);
     DrawLine(new Line2F(rect.Point, rect.Point + new Vector2F(0.0f, rect.Height - 1)), thickness, color, depth);
     DrawLine(new Line2F(rect.Point + rect.Size - Vector2F.One, rect.Point + new Vector2F(rect.Width - 1, 0.0f)), thickness, color, depth);
     DrawLine(new Line2F(rect.Point + rect.Size - Vector2F.One, rect.Point + new Vector2F(0.0f, rect.Height - 1)), thickness, color, depth);
 }
Пример #21
0
 // Draws part of the image at the specified position.
 public void DrawImage(Texture2D texture, Vector2F position, Rectangle2F sourceRect, Color color, double depth = 0.0)
 {
     spriteBatch.Draw(texture, NewPos(position), (Rectangle)sourceRect, color, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, (float)depth);
 }
Пример #22
0
        //-----------------------------------------------------------------------------
        // Static methods
        //-----------------------------------------------------------------------------

        public static bool Intersecting(CollisionModel model,
                                        Vector2F modelPosition,
                                        Rectangle2F box)
        {
            return(Intersecting(model, modelPosition, box, Vector2F.Zero));
        }
Пример #23
0
 // Draws part of the image at the specified region.
 public void DrawImage(Texture2D texture, Rectangle2F destinationRect, Rectangle2F sourceRect, Vector2F origin, double rotation, Color? color = null, SpriteEffects flipEffect = SpriteEffects.None, double depth = 0.0)
 {
     spriteBatch.Draw(texture, NewRect(destinationRect), (Rectangle)sourceRect, color ?? XnaColor.White, (float)GMath.ConvertToRadians(rotation), (Vector2)origin, flipEffect, (float)depth);
 }
Пример #24
0
 // Creates a copy of a rectangle translated by an amount.
 public static Rectangle2F Translate(Rectangle2F r, Vector2F amount)
 {
     r.Point += amount;
     return(r);
 }
Пример #25
0
 public void DrawSprite(Sprite sprite, Rectangle2F destination, Color color, float depth = 0.0f)
 {
     DrawSprite(sprite, 0, destination, color, depth);
 }
Пример #26
0
 // Constructs a copy of the specified rectangle.
 public Rectangle2F(Rectangle2F r)
 {
     this.Point = r.Point;
     this.Size  = r.Size;
 }
Пример #27
0
 // Draws the specified filled rectangle.
 public void FillRectangle(Rectangle2F rect, Color color, double depth = 0.0)
 {
     rect.X = GMath.Round(rect.X);
     rect.Y = GMath.Round(rect.Y);
     DrawImage(white1x1, rect, Vector2F.Zero, 0.0, color, SpriteEffects.None, depth);
     //DrawImage(white1x1, rect.Center + 0.5, new Vector2D(0.5, 0.5), rect.Size, 0, color, SpriteEffects.None, depth);
 }
Пример #28
0
 /** <summary> Returns true if the specified rectangle is inside this line. </summary> */
 public bool Contains(Rectangle2F rect)
 {
     return false;
 }
Пример #29
0
 // Translates the rectangle based on the translation and precision settings.
 private Rectangle NewRect(Vector2F position, Vector2F size)
 {
     Rectangle2F destinationRect = new Rectangle2F(position, size);
     if (useTranslation)
     return (UseIntegerPrecision ? (Rectangle)new Rectangle2F(GMath.Round(destinationRect.Point + translation), GMath.Round(destinationRect.Size + translation)) : (Rectangle)(destinationRect + translation));
     else
     return (Rectangle)destinationRect;
 }
Пример #30
0
 // Return an enumerable list of solid tiles colliding with the given collision box.
 public IEnumerable<Tile> GetSolidTilesColliding(Rectangle2F collisionBox, TileLayerOrder layerOrder = TileLayerOrder.LowestToHighest)
 {
     Rectangle2I area = GetTileAreaFromRect(collisionBox);
     foreach (Tile tile in GetTilesInArea(area, layerOrder)) {
         if (tile.IsSolid && tile.CollisionModel != null &&
             CollisionModel.Intersecting(tile.CollisionModel, tile.Position, collisionBox))
             yield return tile;
     }
 }
Пример #31
0
        // Attempt to dodge a collision.
        private bool PerformCollisionDodge(Entity entity, int direction, object solidObject, Rectangle2F solidBox)
        {
            // Only dodge if moving perpendicular to the edge.
            int axis = Directions.ToAxis(direction);
            if (Math.Abs(entity.Physics.Velocity[1 - axis]) > 0.001f)
                return false;

            // Can't dodge moving tiles.
            if ((solidObject is Tile) && ((Tile) solidObject).IsMoving)
                return false;

            Rectangle2F entityBox = entity.Physics.PositionedCollisionBox;
            float penetrationDistance = GetClipPenetration(
                entity.Physics.PositionedCollisionBox, solidBox, direction);

            // Check dodging for both edges of the solid object.
            for (int side = 0; side < 2; side++) {
                int moveDirection = (direction + (side == 0 ? 1 : 3)) % 4;
                float distanceToEdge = Math.Abs(entityBox.GetEdge(
                    Directions.Reverse(moveDirection)) - solidBox.GetEdge(moveDirection));

                // Check if the distance to the edge is within dodge range.
                if (distanceToEdge <= entity.Physics.AutoDodgeDistance) {
                    float moveAmount = Math.Min(entity.Physics.AutoDodgeSpeed, distanceToEdge);

                    Vector2F nextPosition = GMath.Round(entity.Position) +
                        (Directions.ToVector(moveDirection) * moveAmount);
                    Vector2F goalPosition = entity.Position + Directions.ToVector(direction) +
                        (Directions.ToVector(moveDirection) * distanceToEdge);

                    // Make sure the entity is not colliding when placed at the solid object's edge.
                    if (!IsCollidingAt(entity, nextPosition, false, direction, penetrationDistance) &&
                        !IsCollidingAt(entity, goalPosition, false, direction, penetrationDistance))
                    {
                        entity.Position += Directions.ToVector(moveDirection) * moveAmount;
                        entity.Physics.CollisionInfo[direction].IsAutoDodged = true;
                        //entity.Physics.MovementCollisions[direction] = false; // TODO: Figure out complications for removing this.
                        return true;
                    }
                }
            }

            return false;
        }
Пример #32
0
 // inflateAmount inflates the output rectangle.
 public Rectangle2I GetTileAreaFromRect(Rectangle2F rect, int inflateAmount = 0)
 {
     Rectangle2I area;
     area.Point	= (Point2I) GMath.Floor(rect.TopLeft / tileGridCellSize);
     area.Size	= (Point2I) GMath.Ceiling(rect.BottomRight / tileGridCellSize) - area.Point;
     if (inflateAmount != 0)
         area.Inflate(inflateAmount, inflateAmount);
     return Rectangle2I.Intersect(area, new Rectangle2I(Point2I.Zero, gridDimensions));
 }
Пример #33
0
        private void ResolveCircularCollision(Entity entity, object solidObject, Rectangle2F solidBox)
        {
            Rectangle2F collisionBox = entity.Physics.CollisionBox;
            Rectangle2F entityBoxPrev = entity.Physics.CollisionBox;
            entityBoxPrev.Point += entity.Position;

            // If already colliding with the object, then push away from its center.
            if (entityBoxPrev.Intersects(solidBox)) {
                Vector2F correction = (entity.Position - solidBox.Center).Normalized;
                correction = Vector2F.SnapDirectionByCount(correction, 16);
                entity.Position += 1.0f * correction;
                return;
            }

            // Predict collisions for each axis.
            for (int axis = 0; axis < 2; axis++) {
                Rectangle2F entityBox = entity.Physics.CollisionBox;
                entityBox.Point += entity.Position;
                if (axis == 0)
                    entityBox.X += entity.Physics.VelocityX;
                else
                    entityBox.Point += entity.Physics.Velocity;

                if (entityBox.Intersects(solidBox)) {
                    // Snap the position.
                    Vector2F newPos = entity.Position;
                    if (entityBox.Center[axis] < solidBox.Center[axis])
                        newPos[axis] = solidBox.TopLeft[axis] - collisionBox.BottomRight[axis];
                    else
                        newPos[axis] = solidBox.BottomRight[axis] - collisionBox.TopLeft[axis];
                    entity.Position = newPos;

                    Vector2F newVelocity = entity.Physics.Velocity;
                    if (Math.Abs(entity.Physics.Velocity[1 - axis]) < 0.1f) {
                        // Slightly push away from the center of the solid object.
                        Vector2F distance = entity.Physics.PositionedCollisionBox.Center - solidBox.Center;
                        //Vector2F correction = (entity.Position - solidBox.Center).Normalized;
                        //correction = Vector2F.SnapDirectionByCount(correction, 16);
                        if (GMath.Abs(distance[1 - axis]) > 1.0f) {
                            //distance = GMath.Sqr(GMath.Abs(distance)) * GMath.Sign(distance);
                            distance = (distance * distance) * GMath.Sign(distance);
                            //newVelocity[1 - axis] += distance[1 - axis] * 0.015f;
                            newPos = entity.Position;
                            newPos[1 - axis] += distance[1 - axis] * 0.015f;
                            if (!IsCollidingAt(entity, newPos, false))
                                entity.Position = newPos;
                        }
                    }
                    newVelocity[axis] = 0.0f;
                    entity.Physics.Velocity = newVelocity;
                }
            }
        }
Пример #34
0
 // Return an enumerable list of tiles touching the given rectangular bounds.
 public IEnumerable<Tile> GetTilesTouching(Rectangle2F bounds, TileLayerOrder layerOrder = TileLayerOrder.LowestToHighest)
 {
     Rectangle2I area = GetTileAreaFromRect(bounds);
     foreach (Tile tile in GetTilesInArea(area, layerOrder)) {
         if (tile.Bounds.Intersects(bounds))
             yield return tile;
     }
 }
Пример #35
0
 // Returns true if two rectangles share an edge in the given direction.
 public static bool AreEdgesAligned(Rectangle2F box1, Rectangle2F box2, int edgeDirection)
 {
     return Math.Abs(box1.GetEdge(edgeDirection) - box2.GetEdge(edgeDirection)) < 0.1f;
 }
Пример #36
0
        //-----------------------------------------------------------------------------
        // Tile Mutators
        //-----------------------------------------------------------------------------
        // Place a tile in highest empty layer at the given location.
        // Returns true if there was an empty space to place the tile.
        public bool PlaceTileOnHighestLayer(Tile tile, Point2I location)
        {
            Rectangle2F tileBounds = new Rectangle2F(
                location * GameSettings.TILE_SIZE,
                tile.Size * GameSettings.TILE_SIZE);
            Rectangle2I area = GetTileAreaFromRect(tileBounds);

            // Determine which layers are free.
            bool[] freeLayers = new bool[layerCount];
            for (int i = 0; i < layerCount; i++) {
                freeLayers[i] = true;
                for (int x = area.Left; x < area.Right && freeLayers[i]; x++) {
                    for (int y = area.Top; y < area.Bottom && freeLayers[i]; y++) {
                        Tile t = tiles[x, y, i];
                        if (t != null)
                            freeLayers[i] = false;
                    }
                }
            }

            // Choose the highest free layer.
            int layer = -1;
            for (int i = layerCount - 1; i >= 0; i--) {
                if (freeLayers[i]) {
                    layer = i;
                    break;
                }
            }
            if (layer < 0)
                return false;

            // Place the tile in that layer.
            PlaceTile(tile, location, layer);
            return true;
        }
Пример #37
0
        // Detect a clip collision between the entity and a solid object.
        private void DetectClipCollision(Entity entity, object other, Rectangle2F solidBox)
        {
            // Check if there actually is a collision.
            Rectangle2F entityBox = entity.Physics.PositionedCollisionBox;
            if (entityBox.Intersects(solidBox)) {
                // Determine clip direction.
                int clipDirection = GetCollisionClipDirection(entity, other, solidBox);

                // Set or replace the collision info for this clip direction.
                if (clipDirection >= 0) {
                    CollisionInfoNew oldCollisionInfo = entity.Physics.ClipCollisionInfo[clipDirection];
                    CollisionInfoNew newCollisionInfo = CreateCollisionInfo(entity, other, solidBox, clipDirection);
                    if (!oldCollisionInfo.IsColliding || (newCollisionInfo.PenetrationDistance > oldCollisionInfo.PenetrationDistance))
                        entity.Physics.ClipCollisionInfo[clipDirection] = newCollisionInfo;
                }
            }
        }
Пример #38
0
        private void UpdateTileGridArea(Tile tile)
        {
            Rectangle2F tileBounds	= new Rectangle2F(tile.Position, tile.Size * GameSettings.TILE_SIZE);
            Rectangle2I nextArea	= GetTileAreaFromRect(tileBounds);
            Rectangle2I prevArea	= tile.TileGridArea;

            if (nextArea != prevArea) {
                // Determine the highest free layer for the tile to move to.
                int newLayer = -1;
                for (int i = tile.Layer; i < layerCount; i++) {
                    bool isLayerFree = true;
                    for (int x = nextArea.Left; x < nextArea.Right && isLayerFree; x++) {
                        for (int y = nextArea.Top; y < nextArea.Bottom && isLayerFree; y++) {
                            Tile t = tiles[x, y, i];
                            if (t != null && t != tile)
                                isLayerFree = false;
                        }
                    }
                    if (isLayerFree) {
                        newLayer = i;
                        break;
                    }
                }
                if (newLayer < 0) {
                    RemoveTile(tile);
                    return;
                }

                // Remove the tile from its old area.
                for (int x = prevArea.Left; x < prevArea.Right; x++) {
                    for (int y = prevArea.Top; y < prevArea.Bottom; y++) {
                        tiles[x, y, tile.Layer] = null;
                    }
                }

                // Place the tile into its new area.
                for (int x = nextArea.Left; x < nextArea.Right; x++) {
                    for (int y = nextArea.Top; y < nextArea.Bottom; y++) {
                        tiles[x, y, tile.Layer] = tile;
                    }
                }

                tile.TileGridArea = nextArea;
            }

            // Check for covered/uncovered tiles.
            Rectangle2F tileBoundsOld = tile.PreviousBounds;
            Rectangle2F tileBoundsNew = tile.Bounds;
            if (tileBoundsOld != tileBoundsNew) {
                foreach (Tile t in GetTilesInArea(nextArea).Union(GetTilesInArea(prevArea))) {
                    Rectangle2F tBounds = t.Bounds;
                    if (t != tile) {
                        if (tileBoundsNew.Contains(tBounds) && !tileBoundsOld.Contains(tBounds))
                            t.OnCoverComplete(tile);
                        else if (tileBoundsNew.Intersects(tBounds) && !tileBoundsOld.Intersects(tBounds))
                            t.OnCoverBegin(tile);
                        else if (tileBoundsOld.Contains(tBounds) && !tileBoundsNew.Contains(tBounds))
                            t.OnUncoverBegin(tile);
                        else if (tileBoundsOld.Intersects(tBounds) && !tileBoundsNew.Intersects(tBounds))
                            t.OnUncoverComplete(tile);
                    }
                }
            }
        }
Пример #39
0
 // Returns an enumerable list of all possible collisions.
 private IEnumerable<CollisionCheck> GetCollisions(Entity entity, Rectangle2F area)
 {
     // Find nearby solid entities.
     if (entity.Physics.CollideWithEntities) {
         foreach (Entity other in RoomControl.Entities) {
             if (other != entity && CanCollideWithEntity(entity, other)) {
                 yield return new CollisionCheck() {
                     SolidBox = other.Physics.PositionedCollisionBox,
                     SolidObject = other
                 };
             }
         }
     }
     // Find nearby solid tiles tiles.
     if (entity.Physics.CollideWithWorld) {
         foreach (Tile tile in RoomControl.TileManager.GetTilesTouching(area)) {
             if (CanCollideWithTile(entity, tile) && tile.CollisionStyle == CollisionStyle.Rectangular) {
                 foreach (Rectangle2I box in tile.CollisionModel.Boxes) {
                     Rectangle2F tileBox = box;
                     tileBox.Point += tile.Position;
                     yield return new CollisionCheck() {
                         SolidBox = tileBox,
                         SolidObject = tile
                     };
                 }
             }
         }
     }
 }
Пример #40
0
 // Draws part of the image at the specified position.
 public void DrawImage(Texture2D texture, Vector2F position, Rectangle2F sourceRect)
 {
     spriteBatch.Draw(texture, NewPos(position), (Rectangle)sourceRect, XnaColor.White);
 }
Пример #41
0
 // Returns true if the entity allowably clipping the given collision.
 private bool IsSafeClipping(Entity entity, int axis, Rectangle2F entityBox, object other, Rectangle2F solidBox)
 {
     if (entity.Physics.AllowEdgeClipping) {
         float allowedEdgeClipAmount = GetAllowedEdgeClipAmount(entity, other);
         float penetration = Math.Min(
             solidBox.BottomRight[axis] - entityBox.TopLeft[axis],
             entityBox.BottomRight[axis] - solidBox.TopLeft[axis]);
         return (penetration <= allowedEdgeClipAmount);
     }
     return false;
 }
Пример #42
0
 /** <summary> Returns true if the specified rectangle is inside this line. </summary> */
 public bool Contains(Rectangle2F rect)
 {
     return(false);
 }