working on collisions

This commit is contained in:
Dylan Wilson
2015-10-21 21:48:31 +10:00
parent 7f9f90b81d
commit 960152ca5c
10 changed files with 116 additions and 49 deletions
@@ -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
{
@@ -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<CollisionGridCell> 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<CollisionInfo> 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; }
}
}
@@ -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; }
}
}
@@ -0,0 +1,9 @@
namespace MonoGame.Extended.Collisions
{
public enum CollisionGridCellFlag
{
Empty,
Solid,
Interesting
}
}
@@ -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; }
}
}
@@ -20,14 +20,14 @@ namespace MonoGame.Extended.Collisions
private readonly List<CollisionBody> _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);
}
}
}
}
@@ -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; }
}
}
@@ -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);
@@ -40,8 +40,11 @@
<Compile Include="BitmapFonts\BitmapFontRegion.cs" />
<Compile Include="Collisions\CollisionBody.cs" />
<Compile Include="Collisions\CollisionGrid.cs" />
<Compile Include="Collisions\CollisionGridCell.cs" />
<Compile Include="Collisions\CollisionGridCellFlag.cs" />
<Compile Include="Collisions\CollisionInfo.cs" />
<Compile Include="Collisions\CollisionWorld.cs" />
<Compile Include="Collisions\ICollidable.cs" />
<Compile Include="Collisions\IDynamicCollidable.cs" />
<Compile Include="Content\ContentManagerExtensions.cs" />
<Compile Include="Camera2D.cs" />
<Compile Include="Content\ContentReaderExtensions.cs" />
+1 -1
View File
@@ -18,7 +18,7 @@ namespace Sandbox
Dying
}
public class Zombie : IUpdate, ICollidable
public class Zombie : IUpdate, IDynamicCollidable
{
public Zombie(TextureAtlas textureAtlas)
{