diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..2fe98d26
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1 @@
+patreon: craftworkgames
diff --git a/Source/Demos/Features/Demos/CollisionDemo.cs b/Source/Demos/Features/Demos/CollisionDemo.cs
index 77977625..dcc448b9 100644
--- a/Source/Demos/Features/Demos/CollisionDemo.cs
+++ b/Source/Demos/Features/Demos/CollisionDemo.cs
@@ -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; }
-
+ ///
+ /// Gets or sets the actor's position and updates teh actor's bounds
+ /// position.
+ ///
public Vector2 Position
{
get { return _position; }
@@ -166,8 +160,20 @@ namespace Features.Demos
}
}
+ ///
+ /// Gets or sets the actor's collision bounds.
+ ///
public IShapeF Bounds { get; set; }
+ ///
+ /// Gets or sets how far the actor's collision bounds are offset from
+ /// the actor's position.
+ ///
+ public Vector2 Offset { get; set; }
+
+ ///
+ /// Gets or sets the actor's velocity.
+ ///
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
}
}
+ ///
+ /// Ball that doesn't move when collided with.
+ ///
+ class StationaryBall : DemoBall
+ {
+ public StationaryBall(Sprite sprite) : base(sprite)
+ {
+ }
+
+ public override void OnCollision(CollisionEventArgs collisionInfo)
+ {
+ }
+ }
+
+ ///
+ /// Player controlled ball.
+ ///
+ 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
}
\ No newline at end of file
diff --git a/Source/MonoGame.Extended.Collisions/QuadTree/CollisionComponent.cs b/Source/MonoGame.Extended.Collisions/QuadTree/CollisionComponent.cs
index c8e009d3..7d4b9b2f 100644
--- a/Source/MonoGame.Extended.Collisions/QuadTree/CollisionComponent.cs
+++ b/Source/MonoGame.Extended.Collisions/QuadTree/CollisionComponent.cs
@@ -36,20 +36,13 @@ namespace MonoGame.Extended.Collisions
///
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);
diff --git a/Source/MonoGame.Extended.Entities/World.cs b/Source/MonoGame.Extended.Entities/World.cs
index a4f34d47..022d4b8c 100644
--- a/Source/MonoGame.Extended.Entities/World.cs
+++ b/Source/MonoGame.Extended.Entities/World.cs
@@ -26,6 +26,9 @@ namespace MonoGame.Extended.Entities
foreach (var drawSystem in _drawSystems)
drawSystem.Dispose();
+ _updateSystems.Clear();
+ _drawSystems.Clear();
+
base.Dispose();
}
diff --git a/Source/MonoGame.Extended.Tiled/TiledMap.cs b/Source/MonoGame.Extended.Tiled/TiledMap.cs
index e2328b7c..d9b1d14b 100644
--- a/Source/MonoGame.Extended.Tiled/TiledMap.cs
+++ b/Source/MonoGame.Extended.Tiled/TiledMap.cs
@@ -69,6 +69,10 @@ namespace MonoGame.Extended.Tiled
private void AddLayer(TiledMapLayer layer, bool root)
{
if (root) _layers.Add(layer);
+
+ if (_layersByName.ContainsKey(layer.Name))
+ throw new ArgumentException($"The TiledMap '{Name}' contains two or more layers named '{layer.Name}'. Please ensure all layers have unique names.");
+
_layersByName.Add(layer.Name, layer);
switch(layer)
diff --git a/Source/MonoGame.Extended/Collections/Bag.cs b/Source/MonoGame.Extended/Collections/Bag.cs
index cfa59689..292c1d19 100644
--- a/Source/MonoGame.Extended/Collections/Bag.cs
+++ b/Source/MonoGame.Extended/Collections/Bag.cs
@@ -85,11 +85,11 @@ namespace MonoGame.Extended.Collections
if(Count == 0)
return;
- Count = 0;
-
// non-primitive types are cleared so the garbage collector can release them
if (!_isPrimitive)
Array.Clear(_items, 0, Count);
+
+ Count = 0;
}
public bool Contains(T element)
@@ -191,4 +191,4 @@ namespace MonoGame.Extended.Collections
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/MonoGame.Extended/Math/ShapeExtensions.cs b/Source/MonoGame.Extended/Math/ShapeExtensions.cs
index 51ea932e..30a0b59b 100644
--- a/Source/MonoGame.Extended/Math/ShapeExtensions.cs
+++ b/Source/MonoGame.Extended/Math/ShapeExtensions.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using System.Net.NetworkInformation;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MonoGame.Extended.Shapes;
@@ -276,6 +277,21 @@ namespace MonoGame.Extended
DrawPolygon(spriteBatch, new Vector2(x, y), CreateCircle(radius, sides), color, thickness);
}
+ ///
+ /// Draw an ellipse.
+ ///
+ /// The destination drawing surface
+ /// Center of the ellipse
+ /// Radius of the ellipse
+ /// The number of sides to generate.
+ /// The color of the ellipse.
+ /// The thickness of the line around the ellipse.
+ public static void DrawEllipse(this SpriteBatch spriteBatch, Vector2 center, Vector2 radius, int sides,
+ Color color, float thickness = 1f)
+ {
+ DrawPolygon(spriteBatch, center, CreateEllipse(radius.X, radius.Y, sides), color, thickness);
+ }
+
private static Vector2[] CreateCircle(double radius, int sides)
{
const double max = 2.0*Math.PI;
@@ -291,5 +307,20 @@ namespace MonoGame.Extended
return points;
}
+
+ private static Vector2[] CreateEllipse(float rx, float ry, int sides)
+ {
+ var vertices = new Vector2[sides];
+
+ var t = 0.0;
+ var dt = 2.0 * Math.PI / sides;
+ for (var i = 0; i < sides; i++, t += dt)
+ {
+ var x = (float)(rx * Math.Cos(t));
+ var y = (float)(ry * Math.Sin(t));
+ vertices[i] = new Vector2(x, y);
+ }
+ return vertices;
+ }
}
}
\ No newline at end of file