improved and simplified collision detection in the platformer demo

This commit is contained in:
Dylan Wilson
2018-06-04 22:38:36 +10:00
parent 511a56d00a
commit 5457d80727
6 changed files with 58 additions and 53 deletions
+3 -3
View File
@@ -11,10 +11,10 @@ namespace Platformer.Collisions
[EntityComponent]
public class Body
{
public BodyType BodyType { get; set; } = BodyType.Static;
public Vector2 Position { get; set; }
public BodyType BodyType = BodyType.Static;
public Vector2 Position;
public Vector2 Velocity;
public AABB BoundingBox => new AABB(Position - Size / 2f, Position + Size / 2f);
public Vector2 Size { get; set; }
public Vector2 Size;
}
}
@@ -17,13 +17,9 @@ namespace Platformer.Collisions
return true;
}
public static bool AabbAabb(Body bodyA, Body bodyB, out Manifold manifold)
public static bool AabbAabb(AABB aBox, AABB bBox, Vector2 vector, out Manifold manifold)
{
manifold = new Manifold {BodyA = bodyA, BodyB = bodyB};
var aBox = bodyA.BoundingBox;
var bBox = bodyB.BoundingBox;
var vector = bodyA.Position - bodyB.Position;
manifold = new Manifold();
// Calculate half extents along x axis
var axExtent = (aBox.Max.X - aBox.Min.X) / 2f;
@@ -4,8 +4,6 @@ namespace Platformer.Collisions
{
public struct Manifold
{
public Body BodyA;
public Body BodyB;
public float Penetration;
public Vector2 Normal;
public Vector2 Overlap;
+40 -29
View File
@@ -1,56 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
namespace Platformer.Collisions
{
public struct CollisionPair
{
public Body BodyA;
public Body BodyB;
}
public class World
{
public World(Vector2 gravity)
{
Gravity = gravity;
Bodies = new List<Body>();
}
private readonly List<CollisionPair> _collisionPairs = new List<CollisionPair>();
public Vector2 Gravity { get; set; }
public List<Body> Bodies { get; }
public Action<Manifold> OnCollision { get; set; }
private readonly List<Body> _dynamicBodies = new List<Body>();
private readonly List<Body> _staticBodies = new List<Body>();
public void AddBody(Body body)
{
if (body.BodyType == BodyType.Dynamic)
_dynamicBodies.Add(body);
else
_staticBodies.Add(body);
}
public void RemoveBody(Body body)
{
if (body.BodyType == BodyType.Dynamic)
_dynamicBodies.Remove(body);
else
_staticBodies.Remove(body);
}
public void Update(float deltaTime)
{
var dynamicBodies = Bodies.Where(b => b.BodyType == BodyType.Dynamic).ToArray();
foreach (var body in dynamicBodies)
{
// apply gravity (and other forces?)
foreach (var body in _dynamicBodies)
body.Velocity += Gravity;
body.Position += body.Velocity * deltaTime;
}
foreach (var bodyB in dynamicBodies)
foreach (var body in _dynamicBodies)
{
foreach (var bodyA in Bodies.Where(b => b.BodyType == BodyType.Static))
body.Position.X += body.Velocity.X * deltaTime;
ResolveCollisions(body);
body.Position.Y += body.Velocity.Y * deltaTime;
ResolveCollisions(body);
}
}
private void ResolveCollisions(Body dynamicBody)
{
foreach (var staticBody in _staticBodies)
{
var vector = staticBody.Position - dynamicBody.Position;
if (CollisionTester.AabbAabb(dynamicBody.BoundingBox, staticBody.BoundingBox, vector, out var manifold))
{
if (bodyA != bodyB && CollisionTester.AabbAabb(bodyA.BoundingBox, bodyB.BoundingBox))
_collisionPairs.Add(new CollisionPair {BodyA = bodyA, BodyB = bodyB});
dynamicBody.Position -= manifold.Normal * manifold.Penetration;
dynamicBody.Velocity = dynamicBody.Velocity * new Vector2(Math.Abs(manifold.Normal.Y), Math.Abs(manifold.Normal.X));
}
}
foreach (var collisionPair in _collisionPairs)
{
if (CollisionTester.AabbAabb(collisionPair.BodyA, collisionPair.BodyB, out var manifold))
OnCollision?.Invoke(manifold);
}
_collisionPairs.Clear();
// TODO: Dynamic bodies colliding with dynamic bodies.
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
<tileset firstgid="1" source="tileset.tsx"/>
<layer name="Tile Layer 1" width="25" height="15">
<data encoding="base64" compression="zlib">
eJzFlDsSwCAIBTFgkftfOA0FwwxPFKPFNvp0/dKIqB3gmUAmcyuOnvCIyXmHKDwY7/EZNn2RA63TZhhkKw4/D9pzdB+Z80a8CnJUuenI/h3UVgW9g521wL65rux2RJ6/aps9uxP1NMMHET8C2w==
eJy9lDsSACEIQ1Hw/le2scgwaxb8Fa/RaPgoRUTKA2oCS+pWPFrAx0DnPWygP+c9XqOwN/NgcaJGiXbHw9/Dcp71I1LvDCs9Z+iI8aYHyyP6d9jaLuwdnJwF+OYa1P30zPnyuTXbsHYv5mmEDqaoArU=
</data>
</layer>
</map>
+12 -12
View File
@@ -13,19 +13,19 @@ namespace Platformer.Systems
public WorldSystem()
{
_world = new World(new Vector2(0, 60)) {OnCollision = OnCollision};
_world = new World(new Vector2(0, 60));// {OnCollision = OnCollision};
}
public override void OnEntityAdded(Entity entity)
{
var body = entity.Get<Body>();
_world.Bodies.Add(body);
_world.AddBody(body);
}
public override void OnEntityRemoved(Entity entity)
{
var body = entity.Get<Body>();
_world.Bodies.Remove(body);
_world.RemoveBody(body);
}
protected override void Process(GameTime gameTime)
@@ -40,17 +40,17 @@ namespace Platformer.Systems
{
}
private static void OnCollision(Manifold manifold)
{
var body = manifold.BodyB.BodyType == BodyType.Dynamic ? manifold.BodyB : manifold.BodyA;
//private static void OnCollision(Manifold manifold)
//{
// var body = manifold.BodyB.BodyType == BodyType.Dynamic ? manifold.BodyB : manifold.BodyA;
body.Position -= manifold.Normal * manifold.Penetration;
// body.Position -= manifold.Normal * manifold.Penetration;
if (manifold.Normal.Y < 0 || manifold.Normal.Y > 0)
body.Velocity.Y = 0;
// if (manifold.Normal.Y < 0 || manifold.Normal.Y > 0)
// body.Velocity.Y = 0;
//if (manifold.Normal.X < 0 || manifold.Normal.X > 0)
// body.Velocity = new Vector2(0, body.Velocity.Y);
}
// //if (manifold.Normal.X < 0 || manifold.Normal.X > 0)
// // body.Velocity = new Vector2(0, body.Velocity.Y);
//}
}
}