diff --git a/Source/MonoGame.Extended/Collisions/CollisionBody.cs b/Source/MonoGame.Extended/Collisions/CollisionBody.cs index f6ba891e..0a8049dd 100644 --- a/Source/MonoGame.Extended/Collisions/CollisionBody.cs +++ b/Source/MonoGame.Extended/Collisions/CollisionBody.cs @@ -3,14 +3,14 @@ using MonoGame.Extended.Shapes; namespace MonoGame.Extended.Collisions { - public class CollisionBody : ICollidable + public class CollisionBody : IDynamicCollidable { - public CollisionBody(ICollidable target) + public CollisionBody(IDynamicCollidable target) { _target = target; } - private readonly ICollidable _target; + private readonly IDynamicCollidable _target; public Vector2 Velocity { diff --git a/Source/MonoGame.Extended/Collisions/CollisionGrid.cs b/Source/MonoGame.Extended/Collisions/CollisionGrid.cs index 98a58f84..176894d1 100644 --- a/Source/MonoGame.Extended/Collisions/CollisionGrid.cs +++ b/Source/MonoGame.Extended/Collisions/CollisionGrid.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Microsoft.Xna.Framework; using MonoGame.Extended.Shapes; @@ -6,9 +7,18 @@ namespace MonoGame.Extended.Collisions { public class CollisionGrid { - public CollisionGrid(byte[] data, int columns, int rows, int cellWidth, int cellHeight) + public CollisionGrid(int[] data, int columns, int rows, int cellWidth, int cellHeight) { - _data = data; + _data = new CollisionGridCell[data.Length]; + + for (var y = 0; y < rows; y++) + { + for (var x = 0; x < columns; x++) + { + var index = x + y * columns; + _data[index] = new CollisionGridCell(x, y, data[index]); + } + } Columns = columns; Rows = rows; @@ -21,18 +31,40 @@ namespace MonoGame.Extended.Collisions public int CellWidth { get; private set; } public int CellHeight { get; private set; } - private readonly byte[] _data; + private readonly CollisionGridCell[] _data; - public byte GetDataAt(int column, int row) + public CollisionGridCell GetCellAtIndex(int column, int row) { var index = column + row * Columns; if (index < 0 || index >= _data.Length) - return 0; + return new CollisionGridCell(column, row, 0); return _data[index]; } + public CollisionGridCell GetCellAtPosition(Vector3 position) + { + var column = (int)(position.X / CellWidth); + var row = (int)(position.Y / CellHeight); + + return GetCellAtIndex(column, row); + } + + public IEnumerable GetCellsOverlappingRectangle(RectangleF rectangle) + { + var sx = (int) (rectangle.Left/CellWidth); + var sy = (int) (rectangle.Top/CellHeight); + var ex = (int) ((rectangle.Right/CellWidth) + 1); + var ey = (int) ((rectangle.Bottom/CellHeight) + 1); + + for (var y = sy; y < ey; y++) + { + for (var x = sx; x < ex; x++) + yield return GetCellAtIndex(x, y); + } + } + public Rectangle GetCellRectangle(int column, int row) { return new Rectangle(column * CellWidth, row * CellHeight, CellWidth, CellHeight); @@ -40,43 +72,27 @@ namespace MonoGame.Extended.Collisions public void CollidesWith(RectangleF boundingBox, Action onCollision) { - var sx = (int)(boundingBox.Left / CellWidth); - var sy = (int)(boundingBox.Top / CellHeight); - var ex = (int)((boundingBox.Right / CellWidth) + 1); - var ey = (int)((boundingBox.Bottom / CellHeight) + 1); - - for (var y = sy; y < ey; y++) + foreach (var cell in GetCellsOverlappingRectangle(boundingBox)) { - for (var x = sx; x < ex; x++) + if (cell.Flag == CollisionGridCellFlag.Empty) + continue; + + var cellRectangle = GetCellRectangle(cell.Column, cell.Row); + var intersectingRectangle = RectangleF.Intersect(cellRectangle.ToRectangleF(), boundingBox); + + if (intersectingRectangle.IsEmpty) + continue; + + var collisionInfo = new CollisionInfo { - if (GetDataAt(x, y) == 0) - continue; + Row = cell.Row, + Column = cell.Column, + IntersectingRectangle = intersectingRectangle, + CellRectangle = cellRectangle + }; - var cellRectangle = GetCellRectangle(x, y); - var intersectingRectangle = RectangleF.Intersect(cellRectangle.ToRectangleF(), boundingBox); - - if (intersectingRectangle.IsEmpty) - continue; - - var collisionInfo = new CollisionInfo - { - Row = y, - Column = x, - IntersectingRectangle = intersectingRectangle, - CellRectangle = cellRectangle - }; - - onCollision(collisionInfo); - } + onCollision(collisionInfo); } } } - - public class CollisionInfo - { - public int Column { get; internal set; } - public int Row { get; internal set; } - public RectangleF IntersectingRectangle { get; internal set; } - public Rectangle CellRectangle { get; internal set; } - } } \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/CollisionGridCell.cs b/Source/MonoGame.Extended/Collisions/CollisionGridCell.cs new file mode 100644 index 00000000..bc9d3630 --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/CollisionGridCell.cs @@ -0,0 +1,19 @@ +namespace MonoGame.Extended.Collisions +{ + public class CollisionGridCell + { + public CollisionGridCell(int column, int row, int data) + { + Column = column; + Row = row; + Data = data; + Flag = data == 0 ? CollisionGridCellFlag.Empty : CollisionGridCellFlag.Solid; + } + + public int Column { get; private set; } + public int Row { get; private set; } + public int Data { get; private set; } + public object Tag { get; set; } + public CollisionGridCellFlag Flag { get; set; } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/CollisionGridCellFlag.cs b/Source/MonoGame.Extended/Collisions/CollisionGridCellFlag.cs new file mode 100644 index 00000000..546d2be9 --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/CollisionGridCellFlag.cs @@ -0,0 +1,9 @@ +namespace MonoGame.Extended.Collisions +{ + public enum CollisionGridCellFlag + { + Empty, + Solid, + Interesting + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/CollisionInfo.cs b/Source/MonoGame.Extended/Collisions/CollisionInfo.cs new file mode 100644 index 00000000..59fc0925 --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/CollisionInfo.cs @@ -0,0 +1,13 @@ +using Microsoft.Xna.Framework; +using MonoGame.Extended.Shapes; + +namespace MonoGame.Extended.Collisions +{ + public class CollisionInfo + { + public int Column { get; internal set; } + public int Row { get; internal set; } + public RectangleF IntersectingRectangle { get; internal set; } + public Rectangle CellRectangle { get; internal set; } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/CollisionWorld.cs b/Source/MonoGame.Extended/Collisions/CollisionWorld.cs index a115e2f6..a4e53389 100644 --- a/Source/MonoGame.Extended/Collisions/CollisionWorld.cs +++ b/Source/MonoGame.Extended/Collisions/CollisionWorld.cs @@ -20,14 +20,14 @@ namespace MonoGame.Extended.Collisions private readonly List _bodies; private CollisionGrid _grid; - public CollisionBody CreateBody(ICollidable collidable) + public CollisionBody CreateBody(IDynamicCollidable collidable) { var body = new CollisionBody(collidable); _bodies.Add(body); return body; } - public CollisionGrid CreateGrid(byte[] data, int columns, int rows, int cellWidth, int cellHeight) + public CollisionGrid CreateGrid(int[] data, int columns, int rows, int cellWidth, int cellHeight) { if (_grid != null) throw new InvalidOperationException("Only one collision grid can be created per world"); @@ -46,7 +46,10 @@ namespace MonoGame.Extended.Collisions body.Position += body.Velocity * deltaTime; if(_grid != null) - _grid.CollidesWith(body.GetAxisAlignedBoundingBox(), body.OnCollision); + { + var boundingBox = body.GetAxisAlignedBoundingBox(); + _grid.CollidesWith(boundingBox, body.OnCollision); + } } } } diff --git a/Source/MonoGame.Extended/Collisions/ICollidable.cs b/Source/MonoGame.Extended/Collisions/IDynamicCollidable.cs similarity index 83% rename from Source/MonoGame.Extended/Collisions/ICollidable.cs rename to Source/MonoGame.Extended/Collisions/IDynamicCollidable.cs index 59e4f69b..7270527f 100644 --- a/Source/MonoGame.Extended/Collisions/ICollidable.cs +++ b/Source/MonoGame.Extended/Collisions/IDynamicCollidable.cs @@ -5,9 +5,13 @@ namespace MonoGame.Extended.Collisions { public interface ICollidable { - Vector2 Position { get; set; } - Vector2 Velocity { get; set; } RectangleF GetAxisAlignedBoundingBox(); void OnCollision(CollisionInfo collisionInfo); } + + public interface IDynamicCollidable : ICollidable + { + Vector2 Position { get; set; } + Vector2 Velocity { get; set; } + } } \ No newline at end of file diff --git a/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs b/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs index ac083f40..d2dbdc0a 100644 --- a/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs +++ b/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs @@ -8,7 +8,7 @@ namespace MonoGame.Extended.Maps.Tiled public static CollisionGrid CreateGrid(this CollisionWorld world, TiledTileLayer tileLayer) { var data = tileLayer.Tiles - .Select(t => (byte)t.Id) + .Select(t => t.Id) .ToArray(); return world.CreateGrid(data, tileLayer.Width, tileLayer.Height, tileLayer.TileWidth, tileLayer.TileHeight); diff --git a/Source/MonoGame.Extended/MonoGame.Extended.csproj b/Source/MonoGame.Extended/MonoGame.Extended.csproj index 1ba04a0e..feec6895 100644 --- a/Source/MonoGame.Extended/MonoGame.Extended.csproj +++ b/Source/MonoGame.Extended/MonoGame.Extended.csproj @@ -40,8 +40,11 @@ + + + - + diff --git a/Source/Sandbox/Zombie.cs b/Source/Sandbox/Zombie.cs index b202d2ac..5d9eda5b 100644 --- a/Source/Sandbox/Zombie.cs +++ b/Source/Sandbox/Zombie.cs @@ -18,7 +18,7 @@ namespace Sandbox Dying } - public class Zombie : IUpdate, ICollidable + public class Zombie : IUpdate, IDynamicCollidable { public Zombie(TextureAtlas textureAtlas) {