Improve collision demo (#612)

* Replace square in center of level with stationary ball

* Improve collision demo

- Collisions between balls are smoother.
- Fixed an issue with collision bounds not being set properly. (This is what made the collision appear unsmooth)
This commit is contained in:
Jon Seaman
2019-06-30 21:52:17 -07:00
committed by Dylan Wilson
parent 2144ca871e
commit 31b77e5689
2 changed files with 73 additions and 36 deletions
+64 -25
View File
@@ -36,21 +36,21 @@ namespace Features.Demos
_blankTexture = new Texture2D(GraphicsDevice, 1, 1);
_blankTexture.SetData(new[] { Color.WhiteSmoke });
var demoBall1 = new DemoBall(new Sprite(_spikeyBallTexture))
var spikyBallLeft = new DemoBall(new Sprite(_spikeyBallTexture))
{
Position = new Vector2(200, 240),
Velocity = new Vector2(0, -120)
};
_actors.Add(demoBall1);
_actors.Add(spikyBallLeft);
var demoBall2 = new DemoBall(new Sprite(_spikeyBallTexture))
var spikeyBallRight = new DemoBall(new Sprite(_spikeyBallTexture))
{
Position = new Vector2(600, 240),
Velocity = new Vector2(0, 120)
};
_actors.Add(demoBall2);
_actors.Add(spikeyBallRight);
var controllableBall = new DemoBall(new Sprite(_spikeyBallTexture))
var controllableBall = new ControllableBall(new Sprite(_spikeyBallTexture))
{
Position = new Vector2(400, 240),
Velocity = new Vector2(0, 0)
@@ -58,26 +58,26 @@ namespace Features.Demos
_actors.Add(controllableBall);
_controllableBall = controllableBall;
var wall1 = new DemoWall(new Sprite(_blankTexture))
var topWall = new DemoWall(new Sprite(_blankTexture))
{
Bounds = new RectangleF(0, 0, 800, 20),
Position = new Vector2(0, 0)
};
_actors.Add(wall1);
_actors.Add(topWall);
var wall2 = new DemoWall(new Sprite(_blankTexture))
var bottomWall = new DemoWall(new Sprite(_blankTexture))
{
Position = new Vector2(0, 460),
Bounds = new RectangleF(0, 0, 800, 20)
};
_actors.Add(wall2);
_actors.Add(bottomWall);
var centerWall = new DemoWall(new Sprite(_blankTexture))
var spikeyBallCenter = new StationaryBall(new Sprite(_spikeyBallTexture))
{
Bounds = new RectangleF(0, 0, 50, 50),
Position = new Vector2(400, 200)
Position = new Vector2(400, 240),
Velocity = Vector2.Zero,
};
_actors.Add(centerWall);
_actors.Add(spikeyBallCenter);
foreach (var actor in _actors)
{
@@ -126,13 +126,6 @@ namespace Features.Demos
foreach (var actor in _actors)
{
actor.Draw(_spriteBatch);
if (actor.Bounds is RectangleF rect)
{
_spriteBatch.Draw(_blankTexture, rect.ToRectangle(), Color.WhiteSmoke);
} else if (actor.Bounds is CircleF circle)
{
_spriteBatch.Draw(_blankTexture, circle.Position, Color.WhiteSmoke);
}
}
_spriteBatch.End();
@@ -153,9 +146,10 @@ namespace Features.Demos
Bounds = sprite.GetBoundingRectangle(new Transform2());
}
public Vector2 Offset { get; set; }
/// <summary>
/// Gets or sets the actor's position and updates teh actor's bounds
/// position.
/// </summary>
public Vector2 Position
{
get { return _position; }
@@ -166,8 +160,20 @@ namespace Features.Demos
}
}
/// <summary>
/// Gets or sets the actor's collision bounds.
/// </summary>
public IShapeF Bounds { get; set; }
/// <summary>
/// Gets or sets how far the actor's collision bounds are offset from
/// the actor's position.
/// </summary>
public Vector2 Offset { get; set; }
/// <summary>
/// Gets or sets the actor's velocity.
/// </summary>
public Vector2 Velocity { get; set; }
public virtual void OnCollision(CollisionEventArgs collisionInfo)
@@ -201,14 +207,12 @@ namespace Features.Demos
{
public DemoBall(Sprite sprite) : base(sprite)
{
Offset = new Vector2(75, 75);
Bounds = new CircleF(Position + Offset, 60);
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
Bounds.Position = Position;
}
public override void OnCollision(CollisionEventArgs collisionInfo)
@@ -220,5 +224,40 @@ namespace Features.Demos
}
}
/// <summary>
/// Ball that doesn't move when collided with.
/// </summary>
class StationaryBall : DemoBall
{
public StationaryBall(Sprite sprite) : base(sprite)
{
}
public override void OnCollision(CollisionEventArgs collisionInfo)
{
}
}
/// <summary>
/// Player controlled ball.
/// </summary>
class ControllableBall : DemoBall
{
public ControllableBall(Sprite sprite) : base(sprite)
{
Bounds = new CircleF(Position + Offset, 60);
}
public override void Update(GameTime gameTime)
{
base.Update(gameTime);
}
public override void OnCollision(CollisionEventArgs collisionInfo)
{
Position -= collisionInfo.PenetrationVector;
}
}
#endregion
}
@@ -36,20 +36,13 @@ namespace MonoGame.Extended.Collisions
/// <param name="gameTime"></param>
public override void Update(GameTime gameTime)
{
// Update bounding box locations.
foreach (var value in _targetDataDictionary.Values)
{
_collisionTree.Remove(value);
value.Bounds = value.Target.Bounds;
_collisionTree.Insert(value);
}
// Detect collisions
foreach (var value in _targetDataDictionary.Values)
{
_collisionTree.Remove(value);
var target = value.Target;
var collisions =_collisionTree.Query(target.Bounds)
.Where(data => data.Target != target);
var collisions =_collisionTree.Query(target.Bounds);
// Generate list of collision Infos
foreach (var other in collisions)
@@ -61,7 +54,9 @@ namespace MonoGame.Extended.Collisions
};
target.OnCollision(collisionInfo);
value.Bounds = value.Target.Bounds;
}
_collisionTree.Insert(value);
}
}
@@ -156,7 +151,10 @@ namespace MonoGame.Extended.Collisions
private static Vector2 PenetrationVector(CircleF circ1, CircleF circ2)
{
Debug.Assert(circ1.Intersects(circ2));
if (!circ1.Intersects(circ2))
{
return Vector2.Zero;
}
var displacement = Point2.Displacement(circ1.Center, circ2.Center);