From 7387a8f8728ecdd6554de6adc71303c632632a55 Mon Sep 17 00:00:00 2001 From: Dylan Wilson Date: Thu, 15 Oct 2015 23:00:08 +1000 Subject: [PATCH] attempt to introduce a collision world --- .../Collisions/CollisionBody.cs | 37 +++++++++++++ .../Collisions/CollisionWorld.cs | 53 +++++++++++++++++++ .../Collisions/ICollidable.cs | 13 +++++ .../Maps/Tiled/CollisionWorldExtensions.cs | 17 ++++++ .../Maps/Tiled/TiledTileLayer.cs | 10 ++++ .../MonoGame.Extended.csproj | 4 ++ Source/Sandbox/SandboxGame.cs | 47 ++++++++-------- Source/Sandbox/Zombie.cs | 11 ++-- 8 files changed, 165 insertions(+), 27 deletions(-) create mode 100644 Source/MonoGame.Extended/Collisions/CollisionBody.cs create mode 100644 Source/MonoGame.Extended/Collisions/CollisionWorld.cs create mode 100644 Source/MonoGame.Extended/Collisions/ICollidable.cs create mode 100644 Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs diff --git a/Source/MonoGame.Extended/Collisions/CollisionBody.cs b/Source/MonoGame.Extended/Collisions/CollisionBody.cs new file mode 100644 index 00000000..f6ba891e --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/CollisionBody.cs @@ -0,0 +1,37 @@ +using Microsoft.Xna.Framework; +using MonoGame.Extended.Shapes; + +namespace MonoGame.Extended.Collisions +{ + public class CollisionBody : ICollidable + { + public CollisionBody(ICollidable target) + { + _target = target; + } + + private readonly ICollidable _target; + + public Vector2 Velocity + { + get { return _target.Velocity; } + set { _target.Velocity = value; } + } + + public Vector2 Position + { + get { return _target.Position; } + set { _target.Position = value; } + } + + public RectangleF GetAxisAlignedBoundingBox() + { + return _target.GetAxisAlignedBoundingBox(); + } + + public void OnCollision(CollisionInfo collisionInfo) + { + _target.OnCollision(collisionInfo); + } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/CollisionWorld.cs b/Source/MonoGame.Extended/Collisions/CollisionWorld.cs new file mode 100644 index 00000000..a115e2f6 --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/CollisionWorld.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace MonoGame.Extended.Collisions +{ + public class CollisionWorld : IDisposable, IUpdate + { + public CollisionWorld(Vector2 gravity) + { + _gravity = gravity; + _bodies = new List(); + } + + public void Dispose() + { + } + + private readonly Vector2 _gravity; + private readonly List _bodies; + private CollisionGrid _grid; + + public CollisionBody CreateBody(ICollidable collidable) + { + var body = new CollisionBody(collidable); + _bodies.Add(body); + return body; + } + + public CollisionGrid CreateGrid(byte[] data, int columns, int rows, int cellWidth, int cellHeight) + { + if (_grid != null) + throw new InvalidOperationException("Only one collision grid can be created per world"); + + _grid = new CollisionGrid(data, columns, rows, cellWidth, cellHeight); + return _grid; + } + + public void Update(GameTime gameTime) + { + var deltaTime = (float)gameTime.ElapsedGameTime.TotalSeconds; + + foreach (var body in _bodies) + { + body.Velocity += _gravity * deltaTime; + body.Position += body.Velocity * deltaTime; + + if(_grid != null) + _grid.CollidesWith(body.GetAxisAlignedBoundingBox(), body.OnCollision); + } + } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Collisions/ICollidable.cs b/Source/MonoGame.Extended/Collisions/ICollidable.cs new file mode 100644 index 00000000..59e4f69b --- /dev/null +++ b/Source/MonoGame.Extended/Collisions/ICollidable.cs @@ -0,0 +1,13 @@ +using Microsoft.Xna.Framework; +using MonoGame.Extended.Shapes; + +namespace MonoGame.Extended.Collisions +{ + public interface ICollidable + { + Vector2 Position { get; set; } + Vector2 Velocity { get; set; } + RectangleF GetAxisAlignedBoundingBox(); + void OnCollision(CollisionInfo collisionInfo); + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs b/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs new file mode 100644 index 00000000..ac083f40 --- /dev/null +++ b/Source/MonoGame.Extended/Maps/Tiled/CollisionWorldExtensions.cs @@ -0,0 +1,17 @@ +using System.Linq; +using MonoGame.Extended.Collisions; + +namespace MonoGame.Extended.Maps.Tiled +{ + public static class CollisionWorldExtensions + { + public static CollisionGrid CreateGrid(this CollisionWorld world, TiledTileLayer tileLayer) + { + var data = tileLayer.Tiles + .Select(t => (byte)t.Id) + .ToArray(); + + return world.CreateGrid(data, tileLayer.Width, tileLayer.Height, tileLayer.TileWidth, tileLayer.TileHeight); + } + } +} \ No newline at end of file diff --git a/Source/MonoGame.Extended/Maps/Tiled/TiledTileLayer.cs b/Source/MonoGame.Extended/Maps/Tiled/TiledTileLayer.cs index 69b8170d..f1cbdb98 100644 --- a/Source/MonoGame.Extended/Maps/Tiled/TiledTileLayer.cs +++ b/Source/MonoGame.Extended/Maps/Tiled/TiledTileLayer.cs @@ -31,6 +31,16 @@ namespace MonoGame.Extended.Maps.Tiled get { return _tiles; } } + public int TileWidth + { + get { return _map.TileWidth; } + } + + public int TileHeight + { + get { return _map.TileHeight; } + } + private TiledTile[] CreateTiles(int[] data) { var tiles = new TiledTile[data.Length]; diff --git a/Source/MonoGame.Extended/MonoGame.Extended.csproj b/Source/MonoGame.Extended/MonoGame.Extended.csproj index b860f670..a4b7d040 100644 --- a/Source/MonoGame.Extended/MonoGame.Extended.csproj +++ b/Source/MonoGame.Extended/MonoGame.Extended.csproj @@ -38,7 +38,10 @@ + + + @@ -62,6 +65,7 @@ + diff --git a/Source/Sandbox/SandboxGame.cs b/Source/Sandbox/SandboxGame.cs index b02a9437..5452c69c 100644 --- a/Source/Sandbox/SandboxGame.cs +++ b/Source/Sandbox/SandboxGame.cs @@ -1,6 +1,4 @@ -using System; -using System.Linq; -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using MonoGame.Extended; @@ -27,8 +25,9 @@ namespace Sandbox private FramesPerSecondCounter _fpsCounter; private SpriteAnimator _spriteAnimator; private Zombie _zombie; - private CollisionGrid _collisionGrid; - private Point _mousePoint; + //private CollisionGrid _collisionGrid; + //private Point _mousePoint; + private readonly CollisionWorld _world; public SandboxGame() { @@ -37,6 +36,15 @@ namespace Sandbox IsMouseVisible = true; Window.Position = new Point(50, 50); Window.Title = string.Format("MonoGame.Extended - {0}", GetType().Name); + + _world = new CollisionWorld(new Vector2(0, 900)); + } + + protected override void Dispose(bool disposing) + { + _world.Dispose(); + + base.Dispose(disposing); } protected override void Initialize() @@ -63,12 +71,8 @@ namespace Sandbox _spriteBatch = new SpriteBatch(GraphicsDevice); _bitmapFont = Content.Load("Fonts/courier-new-32"); _tiledMap = Content.Load("Tilesets/level01"); - var collisionData = _tiledMap - .GetLayer("Tile Layer 1") - .Tiles - .Select(t => (byte) t.Id) - .ToArray(); - _collisionGrid = new CollisionGrid(collisionData, _tiledMap.Width, _tiledMap.Height, _tiledMap.TileWidth, _tiledMap.TileHeight); + + _world.CreateGrid(_tiledMap.GetLayer("Tile Layer 1")); var fireballTexture = Content.Load("Sprites/fireball"); var spriteSheetAtlas = TextureAtlas.Create(fireballTexture, 512, 197); @@ -85,6 +89,8 @@ namespace Sandbox { Position = new Vector2(300, 500) }; + + _world.CreateBody(_zombie); } protected override void UnloadContent() @@ -97,7 +103,7 @@ namespace Sandbox var keyboardState = Keyboard.GetState(); var mouseState = Mouse.GetState(); - _mousePoint = _camera.ScreenToWorld(new Vector2(mouseState.X, mouseState.Y)).ToPoint(); + //_mousePoint = _camera.ScreenToWorld(new Vector2(mouseState.X, mouseState.Y)).ToPoint(); // camera if (keyboardState.IsKeyDown(Keys.R)) @@ -122,15 +128,14 @@ namespace Sandbox if (keyboardState.IsKeyDown(Keys.Enter)) _zombie.Die(); - _zombie.Velocity += new Vector2(0, 900) * deltaSeconds; - _zombie.Position += _zombie.Velocity * deltaSeconds; - // update must be called before collision detection _zombie.Update(gameTime); - var boundingBox = _zombie.GetAxisAlignedBoundingBox(); - _collisionGrid.CollidesWith(boundingBox, _zombie.OnCollision); - + _world.Update(gameTime); + + //var boundingBox = _zombie.GetAxisAlignedBoundingBox(); + //_collisionGrid.CollidesWith(boundingBox, _zombie.OnCollision); + _camera.LookAt(_zombie.Position); // fireball @@ -156,11 +161,11 @@ namespace Sandbox _zombie.Draw(_spriteBatch); _spriteBatch.End(); - var x = _mousePoint.X / _collisionGrid.CellWidth; - var y = _mousePoint.Y / _collisionGrid.CellHeight; + //var x = _mousePoint.X / _collisionGrid.CellWidth; + //var y = _mousePoint.Y / _collisionGrid.CellHeight; _spriteBatch.Begin(); - _spriteBatch.DrawString(_bitmapFont, string.Format("CD: {0}, {1} = {2}", x, y, _collisionGrid.GetDataAt(x, y)), new Vector2(5, 35), new Color(0.5f, 0.5f, 0.5f)); + //_spriteBatch.DrawString(_bitmapFont, string.Format("CD: {0}, {1} = {2}", x, y, _collisionGrid.GetDataAt(x, y)), new Vector2(5, 35), new Color(0.5f, 0.5f, 0.5f)); _spriteBatch.DrawString(_bitmapFont, string.Format("FPS: {0} Zoom: {1}", _fpsCounter.AverageFramesPerSecond, _camera.Zoom), new Vector2(5, 5), new Color(0.5f, 0.5f, 0.5f)); _spriteBatch.End(); diff --git a/Source/Sandbox/Zombie.cs b/Source/Sandbox/Zombie.cs index ab49840c..b202d2ac 100644 --- a/Source/Sandbox/Zombie.cs +++ b/Source/Sandbox/Zombie.cs @@ -18,7 +18,7 @@ namespace Sandbox Dying } - public class Zombie : IUpdate + public class Zombie : IUpdate, ICollidable { public Zombie(TextureAtlas textureAtlas) { @@ -85,9 +85,7 @@ namespace Sandbox public RectangleF GetAxisAlignedBoundingBox() { - const float heightOffset = 52; - var spriteRectangle = _sprite.GetBoundingRectangle(); - return new RectangleF(spriteRectangle.X, spriteRectangle.Y + heightOffset, spriteRectangle.Width, spriteRectangle.Height - heightOffset); + return _sprite.GetBoundingRectangle(); } public Vector2 Position @@ -102,8 +100,9 @@ namespace Sandbox _animator.Update(gameTime); - if(State == ZombieState.Walking) - Position += new Vector2(200f * _direction, 0) * (float)gameTime.ElapsedGameTime.TotalSeconds; + Velocity = State == ZombieState.Walking + ? new Vector2(200f*_direction, Velocity.Y) + : new Vector2(0, Velocity.Y); } public void Draw(SpriteBatch spriteBatch)