From 670842c1e35a26392a48025d78f495e40465279d Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 30 Nov 2023 17:52:09 +0300 Subject: [PATCH 01/81] Test1 --- Game/Physics2D/Abstract/ICollider2D.cs | 23 ++++++ .../Abstract/ICollisionResolver2D.cs | 6 ++ Game/Physics2D/Abstract/IPhysicsEngine2D.cs | 11 +++ Game/Physics2D/Abstract/IPhysicsMaterial2D.cs | 7 ++ Game/Physics2D/Abstract/IRigidBody2D.cs | 15 ++++ Game/Physics2D/Collider2DBehaviourBase.cs | 41 ++++++++++ Game/Physics2D/Collider2DBox.cs | 16 ++++ Game/Physics2D/PhysicsEngine2D.cs | 78 +++++++++++++++++++ Game/Physics2D/RigidBody2D.cs | 25 ++++++ 9 files changed, 222 insertions(+) create mode 100644 Game/Physics2D/Abstract/ICollider2D.cs create mode 100644 Game/Physics2D/Abstract/ICollisionResolver2D.cs create mode 100644 Game/Physics2D/Abstract/IPhysicsEngine2D.cs create mode 100644 Game/Physics2D/Abstract/IPhysicsMaterial2D.cs create mode 100644 Game/Physics2D/Abstract/IRigidBody2D.cs create mode 100644 Game/Physics2D/Collider2DBehaviourBase.cs create mode 100644 Game/Physics2D/Collider2DBox.cs create mode 100644 Game/Physics2D/PhysicsEngine2D.cs create mode 100644 Game/Physics2D/RigidBody2D.cs diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs new file mode 100644 index 0000000..730d7d0 --- /dev/null +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Physics2D.Abstract; + +public interface ICollider2D : IBehaviour, IAssignableTransform +{ + Action? OnCollision { get; set; } + + Vector2 OffsetPosition { get; set; } + Vector2 OffsetScale { get; set; } + float OffsetRotation { get; set; } + + IReadOnlyList Vertices { get; } + + bool CheckCollision(ICollider2D collider); + + void RecalculateVertices(); +} diff --git a/Game/Physics2D/Abstract/ICollisionResolver2D.cs b/Game/Physics2D/Abstract/ICollisionResolver2D.cs new file mode 100644 index 0000000..83d54b4 --- /dev/null +++ b/Game/Physics2D/Abstract/ICollisionResolver2D.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Physics2D.Abstract; + +public interface ICollisionResolver2D +{ + void ResolveCollision(ICollider2D colliderA, ICollider2D colliderB); +} diff --git a/Game/Physics2D/Abstract/IPhysicsEngine2D.cs b/Game/Physics2D/Abstract/IPhysicsEngine2D.cs new file mode 100644 index 0000000..aed1d10 --- /dev/null +++ b/Game/Physics2D/Abstract/IPhysicsEngine2D.cs @@ -0,0 +1,11 @@ +namespace Syntriax.Engine.Physics2D.Abstract; + +public interface IPhysicsEngine2D +{ + int IterationCount { get; set; } + + void AddRigidBody(IRigidBody2D rigidBody); + void RemoveRigidBody(IRigidBody2D rigidBody); + + void Step(float deltaTime); +} diff --git a/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs b/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs new file mode 100644 index 0000000..266545d --- /dev/null +++ b/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs @@ -0,0 +1,7 @@ +namespace Syntriax.Engine.Physics2D.Abstract; + +public interface IPhysicsMaterial2D +{ + float Friction { get; set; } + float Restitution { get; set; } +} diff --git a/Game/Physics2D/Abstract/IRigidBody2D.cs b/Game/Physics2D/Abstract/IRigidBody2D.cs new file mode 100644 index 0000000..0881c48 --- /dev/null +++ b/Game/Physics2D/Abstract/IRigidBody2D.cs @@ -0,0 +1,15 @@ +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Physics2D.Abstract; + +public interface IRigidBody2D : IBehaviour, IAssignableTransform +{ + IPhysicsMaterial2D Material { get; set; } + + Vector2 Velocity { get; set; } + float AngularVelocity { get; set; } + + float Mass { get; set; } +} diff --git a/Game/Physics2D/Collider2DBehaviourBase.cs b/Game/Physics2D/Collider2DBehaviourBase.cs new file mode 100644 index 0000000..6706751 --- /dev/null +++ b/Game/Physics2D/Collider2DBehaviourBase.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public abstract class Collider2DBehaviourBase : BehaviourOverride, ICollider2D +{ + public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } + public Action? OnCollision { get; set; } = null; + + public Vector2 OffsetPosition { get; set; } = Vector2.Zero; + public Vector2 OffsetScale { get; set; } = Vector2.One; + public float OffsetRotation { get; set; } = 0f; + + ITransform IAssignableTransform.Transform => Transform; + + + public bool Assign(ITransform transform) => GameObject.Assign(transform); + + public void RecalculateVertices() + { + throw new NotImplementedException(); + } + + public bool CheckCollision(ICollider2D collider) + { + return false; + + OnCollision?.Invoke(this, collider); + return true; + } + + + public abstract IReadOnlyList Vertices { get; } +} diff --git a/Game/Physics2D/Collider2DBox.cs b/Game/Physics2D/Collider2DBox.cs new file mode 100644 index 0000000..930604b --- /dev/null +++ b/Game/Physics2D/Collider2DBox.cs @@ -0,0 +1,16 @@ +using System; + +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +// public class Collider2DBox : Collider2DBehaviourBase +// { +// protected override bool ProcessCollision(ICollider2D collider) +// { +// if (collider is not Collider2DBox) +// return false; + + +// } +// } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs new file mode 100644 index 0000000..1cd722f --- /dev/null +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public class PhysicsEngine2D : IPhysicsEngine2D +{ + private IList rigidBodies = new List(32); + private IList colliders = new List(64); + + private int _iterationCount = 1; + + + public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; } + + public void AddRigidBody(IRigidBody2D rigidBody) + { + if (rigidBodies.Contains(rigidBody)) + return; + + rigidBodies.Add(rigidBody); + + foreach (var collider2D in rigidBody.BehaviourController.GetBehaviours()) + colliders.Add(collider2D); + + rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; + rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; + } + + public void RemoveRigidBody(IRigidBody2D rigidBody) + { + rigidBodies.Remove(rigidBody); + } + + public void Step(float deltaTime) + { + float intervalDeltaTime = deltaTime / IterationCount; + + for (int i = 0; i < IterationCount; i++) + { + foreach (var rigidBody in rigidBodies) + { + Vector2 nextPosition = rigidBody.Transform.Position; + nextPosition += rigidBody.Velocity * intervalDeltaTime; + + rigidBody.Transform.Position += nextPosition; + } + + for (int colliderIX = 0; colliderIX < colliders.Count; colliderIX++) + { + ICollider2D colliderX = colliders[colliderIX]; + for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) + if (colliderX.CheckCollision(colliders[colliderIY])) + Console.WriteLine($"Collision"); + } + } + } + + + private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) + { + if (behaviour is not ICollider2D collider2D) + return; + + colliders.Add(collider2D); + } + + private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour) + { + if (behaviour is not ICollider2D collider2D) + return; + + colliders.Remove(collider2D); + } +} diff --git a/Game/Physics2D/RigidBody2D.cs b/Game/Physics2D/RigidBody2D.cs new file mode 100644 index 0000000..efc384d --- /dev/null +++ b/Game/Physics2D/RigidBody2D.cs @@ -0,0 +1,25 @@ +using System; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public class RigidBody2D : BehaviourOverride, IRigidBody2D +{ + public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } + + + public IPhysicsMaterial2D Material { get; set; } = null!; + + public Vector2 Velocity { get; set; } = Vector2.Zero; + public float AngularVelocity { get; set; } = 0f; + public float Mass { get; set; } = 0f; + ITransform IAssignableTransform.Transform => Transform; + + + public bool Assign(ITransform transform) => GameObject.Assign(transform); +} From 0649494f9c5393b1daa00705fd3aa26f29a0555a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 1 Dec 2023 17:42:07 +0300 Subject: [PATCH 02/81] feat: Basic Collider --- Engine | 2 +- Game/Game1.cs | 60 ++++-- Game/Physics2D/Abstract/ICollider2D.cs | 4 +- Game/Physics2D/Collider2DBehaviour.cs | 233 ++++++++++++++++++++++ Game/Physics2D/Collider2DBehaviourBase.cs | 41 ---- Game/Physics2D/Collider2DBox.cs | 16 -- Game/Physics2D/PhysicsEngine2D.cs | 14 +- 7 files changed, 288 insertions(+), 82 deletions(-) create mode 100644 Game/Physics2D/Collider2DBehaviour.cs delete mode 100644 Game/Physics2D/Collider2DBehaviourBase.cs delete mode 100644 Game/Physics2D/Collider2DBox.cs diff --git a/Engine b/Engine index bb6990a..c03d74d 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit bb6990a80c499a93de9c23be7c8821d66c4c3377 +Subproject commit c03d74dbe0949d75411cd368c8b07dbafd871a20 diff --git a/Game/Game1.cs b/Game/Game1.cs index 8278dc5..eddfe0b 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -7,12 +7,14 @@ using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Input; +using Syntriax.Engine.Physics2D; namespace Pong; public class Game1 : Game { private GraphicsDeviceManager _graphics = null!; + private PhysicsEngine2D engine; private SpriteBatch _spriteBatch = null!; private GameManager gameManager = null!; @@ -40,9 +42,10 @@ public class Game1 : Game protected override void LoadContent() { + engine = new PhysicsEngine2D(); _spriteBatch = new SpriteBatch(GraphicsDevice); - Sprite spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + // Sprite spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); @@ -52,32 +55,44 @@ public class Game1 : Game gameManager.Camera = gameObjectCamera.BehaviourController.AddBehaviour(); gameManager.Camera.Viewport = GraphicsDevice.Viewport; - IGameObject gameObjectPlayArea = gameManager.InstantiateGameObject(); - PlayAreaBehaviour playAreaBehaviour = gameObjectPlayArea.BehaviourController.AddBehaviour(); - playAreaBehaviour.PlayArea = new Vector2(_graphics.PreferredBackBufferWidth, _graphics.PreferredBackBufferHeight); + // IGameObject gameObjectPlayArea = gameManager.InstantiateGameObject(); + // PlayAreaBehaviour playAreaBehaviour = gameObjectPlayArea.BehaviourController.AddBehaviour(); + // playAreaBehaviour.PlayArea = new Vector2(_graphics.PreferredBackBufferWidth, _graphics.PreferredBackBufferHeight); IGameObject gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); + engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); + gameObjectBall.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + // gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + IGameObject gameObjectBall2 = gameManager.InstantiateGameObject(); + gameObjectBall2.Name = "Ball2"; + gameObjectBall2.Transform.Position = Vector2.UnitY * -40; + gameObjectBall2.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + RigidBody2D rigidBody = gameObjectBall2.BehaviourController.AddBehaviour(); + rigidBody.Velocity = Vector2.UnitY * 10f; + engine.AddRigidBody(rigidBody); + gameObjectBall2.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + // gameObjectBall2.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); + gameObjectBall2.BehaviourController.AddBehaviour().Assign(spriteBall); - IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); - gameObjectLeft.Name = "Left"; - gameObjectLeft.Transform.Position = new Vector2(-452, 0f); - gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); - gameObjectLeft.BehaviourController.AddBehaviour(); - gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); + // gameObjectLeft.Name = "Left"; + // gameObjectLeft.Transform.Position = new Vector2(-452, 0f); + // gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); + // gameObjectLeft.BehaviourController.AddBehaviour(); + // gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + // gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - IGameObject gameObjectRight = gameManager.InstantiateGameObject(); - gameObjectRight.Name = "Right"; - gameObjectRight.Transform.Position = new Vector2(452, 0f); - gameObjectRight.Transform.Scale = new Vector2(10f, 40f); - gameObjectRight.BehaviourController.AddBehaviour(); - gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); - gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); + // IGameObject gameObjectRight = gameManager.InstantiateGameObject(); + // gameObjectRight.Name = "Right"; + // gameObjectRight.Transform.Position = new Vector2(452, 0f); + // gameObjectRight.Transform.Scale = new Vector2(10f, 40f); + // gameObjectRight.BehaviourController.AddBehaviour(); + // gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); + // gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); // TODO: use this.Content to load your game content here } @@ -114,10 +129,15 @@ public class Game1 : Game gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; // TODO: Add your update logic here + while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f) + { + physicsTimer += 0.01f; + engine.Step(.01f); + } gameManager.Update(gameTime); - base.Update(gameTime); } + static float physicsTimer = 0f; protected override void Draw(GameTime gameTime) { diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index 730d7d0..f458b40 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -14,10 +14,10 @@ public interface ICollider2D : IBehaviour, IAssignableTransform Vector2 OffsetPosition { get; set; } Vector2 OffsetScale { get; set; } float OffsetRotation { get; set; } - IReadOnlyList Vertices { get; } - bool CheckCollision(ICollider2D collider); + + bool CheckCollision(Vector2 point, ICollider2D otherCollider); void RecalculateVertices(); } diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs new file mode 100644 index 0000000..94c0e4a --- /dev/null +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public class Collider2DBehaviour(IList vertices) : BehaviourOverride, ICollider2D +{ + private List triangles = new List(32); + private readonly List _vertices = new List(32); + + public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } + public Action? OnCollision { get; set; } = null; + + public Vector2 OffsetPosition { get; set; } = Vector2.Zero; + public Vector2 OffsetScale { get; set; } = Vector2.One; + public float OffsetRotation { get; set; } = 0f; + + ITransform IAssignableTransform.Transform => Transform; + + public bool Assign(ITransform transform) => GameObject.Assign(transform); + + public bool CheckCollision(Vector2 point, ICollider2D otherCollider) + { + foreach (var triangle in triangles) + { + if (!isInside(point, triangle)) + continue; + + OnCollision?.Invoke(this, otherCollider); + return true; + } + + return false; + } + + public void RecalculateVertices() + { + triangles.Clear(); + + Triangle superTriangle = GetSuperTriangle(Vertices); + triangles.Add(superTriangle); + + List badTriangles = new(32); + List polygon = new(32); + + _vertices.Clear(); + foreach (var vertex in VerticesOriginal) + _vertices.Add(vertex + Transform.Position); + + foreach (var vertex in _vertices) + { + badTriangles.Clear(); + polygon.Clear(); + + foreach (var triangle in triangles) + { + Circle circle = GetCircumCircle(triangle); + if (Vector2.DistanceSquared(circle.Center, vertex) <= circle.Radius * circle.Radius) + badTriangles.Add(triangle); + } + + foreach (var triangle in badTriangles) + foreach (var edge in GetEdges(triangle)) + { + if (DoesEdgeExistInTriangles(edge, badTriangles)) + polygon.Add(edge); + } + + foreach (var triangle in badTriangles) + triangles.Remove(triangle); + + foreach (var edge in polygon) + { + triangles.Add(new() + { + A = edge.A, + B = edge.B, + C = vertex + }); + } + } + + for (int i = triangles.Count - 1; i >= 0; i--) + { + Triangle triangle = triangles[i]; + if ( + triangle.A == superTriangle.A || triangle.A == superTriangle.B || triangle.A == superTriangle.C || + triangle.B == superTriangle.A || triangle.B == superTriangle.B || triangle.B == superTriangle.C || + triangle.C == superTriangle.A || triangle.C == superTriangle.B || triangle.C == superTriangle.C + ) + triangles.RemoveAt(i); + } + + // for (int i = 0; i < triangles.Count; i++) + // { + // Triangle triangle = triangles[i]; + + // triangle.A += Transform.Position; + // triangle.B += Transform.Position; + // triangle.C += Transform.Position; + + // triangles[i] = triangle; + // } + } + + private bool DoesEdgeExistInTriangles(Edge edge, List triangles) + { + foreach (var triangle in triangles) + foreach (var edgeOther in GetEdges(triangle)) + if (edge.A == edgeOther.A && edge.B == edgeOther.B) + return true; + else if (edge.A == edgeOther.B && edge.B == edgeOther.A) + return true; + return false; + } + + private List GetEdges(Triangle triangle) + => [ + new() { A = triangle.A, B = triangle.B }, + new() { A = triangle.B, B = triangle.C }, + new() { A = triangle.C, B = triangle.A } + ]; + + private Triangle GetSuperTriangle(IReadOnlyList vertices) + { + float minX = float.MaxValue, minY = float.MaxValue; + float maxX = float.MinValue, maxY = float.MinValue; + + foreach (Vector2 point in vertices) + { + minX = Math.Min(minX, point.X); + minY = Math.Min(minY, point.Y); + maxX = Math.Max(maxX, point.X); + maxY = Math.Max(maxY, point.Y); + } + + float dx = maxX - minX; + float dy = maxY - minY; + float deltaMax = Math.Max(dx, dy); + float midX = (minX + maxX) / 2; + float midY = (minY + maxY) / 2; + + Vector2 p1 = new Vector2(midX - 20 * deltaMax, midY - deltaMax); + Vector2 p2 = new Vector2(midX, midY + 20 * deltaMax); + Vector2 p3 = new Vector2(midX + 20 * deltaMax, midY - deltaMax); + + return new Triangle() { A = p1, B = p2, C = p3 }; + } + + private struct Triangle { public Vector2 A, B, C; } + + private double GetArea(Triangle triangle) + { + return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + + triangle.B.X * (triangle.C.Y - triangle.A.Y) + + triangle.C.X * (triangle.A.Y - triangle.B.Y)) / 2.0); + } + + /* A function to check whether point P(x, y) lies + inside the triangle formed by A(x1, y1), + B(x2, y2) and C(x3, y3) */ + private bool isInside(Vector2 point, Triangle triangle) + { + double A = GetArea(triangle); + /* Calculate area of triangle ABC */ + // double A = area(x1, y1, x2, y2, x3, y3); + + double A1 = GetArea(new() { A = point, B = triangle.B, C = triangle.C }); + /* Calculate area of triangle PBC */ + // double A1 = area(x, y, x2, y2, x3, y3); + + /* Calculate area of triangle PAC */ + double A2 = GetArea(new() { A = triangle.A, B = point, C = triangle.C }); + // double A2 = area(x1, y1, x, y, x3, y3); + + /* Calculate area of triangle PAB */ + double A3 = GetArea(new() { A = triangle.A, B = triangle.B, C = point }); + // double A3 = area(x1, y1, x2, y2, x, y); + + /* Check if sum of A1, A2 and A3 is same as A */ + return A == A1 + A2 + A3; + } + + private struct Edge + { + public Vector2 A; + public Vector2 B; + } + + private struct Circle + { + public double Radius; + public Vector2 Center; + } + + private Circle GetCircumCircle(Triangle triangle) + { + Circle result = new(); + + Vector2 midAB = (triangle.A + triangle.B) / 2; + Vector2 midBC = (triangle.B + triangle.C) / 2; + + float slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); + float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); + + // Check if the slopes are not parallel + if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) + { + float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); + float y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; + + result.Center = new Vector2(x, y); + result.Radius = Vector2.Distance(result.Center, triangle.A); + } + else + { + // If slopes are parallel, use the midpoints of the sides as the circumcenter + result.Center = (midAB + midBC) / 2; + result.Radius = Vector2.Distance(result.Center, triangle.A); + } + + return result; + } + + public IList VerticesOriginal { get; } = vertices; + public IReadOnlyList Vertices => _vertices; +} diff --git a/Game/Physics2D/Collider2DBehaviourBase.cs b/Game/Physics2D/Collider2DBehaviourBase.cs deleted file mode 100644 index 6706751..0000000 --- a/Game/Physics2D/Collider2DBehaviourBase.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System; -using System.Collections.Generic; - -using Microsoft.Xna.Framework; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Physics2D.Abstract; - -namespace Syntriax.Engine.Physics2D; - -public abstract class Collider2DBehaviourBase : BehaviourOverride, ICollider2D -{ - public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } - public Action? OnCollision { get; set; } = null; - - public Vector2 OffsetPosition { get; set; } = Vector2.Zero; - public Vector2 OffsetScale { get; set; } = Vector2.One; - public float OffsetRotation { get; set; } = 0f; - - ITransform IAssignableTransform.Transform => Transform; - - - public bool Assign(ITransform transform) => GameObject.Assign(transform); - - public void RecalculateVertices() - { - throw new NotImplementedException(); - } - - public bool CheckCollision(ICollider2D collider) - { - return false; - - OnCollision?.Invoke(this, collider); - return true; - } - - - public abstract IReadOnlyList Vertices { get; } -} diff --git a/Game/Physics2D/Collider2DBox.cs b/Game/Physics2D/Collider2DBox.cs deleted file mode 100644 index 930604b..0000000 --- a/Game/Physics2D/Collider2DBox.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; - -using Syntriax.Engine.Physics2D.Abstract; - -namespace Syntriax.Engine.Physics2D; - -// public class Collider2DBox : Collider2DBehaviourBase -// { -// protected override bool ProcessCollision(ICollider2D collider) -// { -// if (collider is not Collider2DBox) -// return false; - - -// } -// } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 1cd722f..35209da 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -46,15 +46,25 @@ public class PhysicsEngine2D : IPhysicsEngine2D Vector2 nextPosition = rigidBody.Transform.Position; nextPosition += rigidBody.Velocity * intervalDeltaTime; - rigidBody.Transform.Position += nextPosition; + rigidBody.Transform.Position = nextPosition; } + + foreach (var collider in colliders) + collider.RecalculateVertices(); + for (int colliderIX = 0; colliderIX < colliders.Count; colliderIX++) { ICollider2D colliderX = colliders[colliderIX]; for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) - if (colliderX.CheckCollision(colliders[colliderIY])) + foreach (var vertex in colliderX.Vertices) + { + if (!colliders[colliderIY].CheckCollision(vertex, colliderX)) + continue; + Console.WriteLine($"Collision"); + break; + } } } } From 6dbd2b1407bc0a223ff6e60c9c4d986c9225ab23 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 12:32:28 +0300 Subject: [PATCH 03/81] fix: Algorithm Error --- Game/Physics2D/Collider2DBehaviour.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index 94c0e4a..e9672c7 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -43,16 +43,16 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I { triangles.Clear(); - Triangle superTriangle = GetSuperTriangle(Vertices); + _vertices.Clear(); + foreach (var vertex in VerticesOriginal) + _vertices.Add(vertex + Transform.Position); + + Triangle superTriangle = GetSuperTriangle(_vertices); triangles.Add(superTriangle); List badTriangles = new(32); List polygon = new(32); - _vertices.Clear(); - foreach (var vertex in VerticesOriginal) - _vertices.Add(vertex + Transform.Position); - foreach (var vertex in _vertices) { badTriangles.Clear(); From 682bd62ffc78133d6898f481e9cf86a0f9bfc930 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 13:14:23 +0300 Subject: [PATCH 04/81] Test --- Game/Game1.cs | 12 +++++++++-- Game/Physics2D/Abstract/ICollider2D.cs | 6 ++++-- Game/Physics2D/Collider2DBehaviour.cs | 28 +++++++++++++++++++++----- Game/Physics2D/CollisionInformation.cs | 12 +++++++++++ Game/Physics2D/PhysicsEngine2D.cs | 8 ++++++-- 5 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 Game/Physics2D/CollisionInformation.cs diff --git a/Game/Game1.cs b/Game/Game1.cs index eddfe0b..6fb4ce2 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -69,15 +69,23 @@ public class Game1 : Game gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); IGameObject gameObjectBall2 = gameManager.InstantiateGameObject(); gameObjectBall2.Name = "Ball2"; - gameObjectBall2.Transform.Position = Vector2.UnitY * -40; + gameObjectBall2.Transform.Position = Vector2.UnitY * -50f; gameObjectBall2.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); RigidBody2D rigidBody = gameObjectBall2.BehaviourController.AddBehaviour(); - rigidBody.Velocity = Vector2.UnitY * 10f; + rigidBody.Velocity = Vector2.UnitY * 100f; engine.AddRigidBody(rigidBody); gameObjectBall2.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); // gameObjectBall2.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); gameObjectBall2.BehaviourController.AddBehaviour().Assign(spriteBall); + IGameObject gameObjectBall3 = gameManager.InstantiateGameObject(); + gameObjectBall3.Name = "Ball"; + gameObjectBall3.Transform.Position = Vector2.UnitY * -120f + Vector2.UnitX * 10f; + gameObjectBall3.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + engine.AddRigidBody(gameObjectBall3.BehaviourController.AddBehaviour()); + gameObjectBall3.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + // gameObjectBall3.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); + gameObjectBall3.BehaviourController.AddBehaviour().Assign(spriteBall); // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); // gameObjectLeft.Name = "Left"; // gameObjectLeft.Transform.Position = new Vector2(-452, 0f); diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index f458b40..dad186f 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; - +using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework; using Syntriax.Engine.Core.Abstract; @@ -9,6 +9,8 @@ namespace Syntriax.Engine.Physics2D.Abstract; public interface ICollider2D : IBehaviour, IAssignableTransform { + IRigidBody2D? RigidBody2D { get; } + Action? OnCollision { get; set; } Vector2 OffsetPosition { get; set; } @@ -17,7 +19,7 @@ public interface ICollider2D : IBehaviour, IAssignableTransform IReadOnlyList Vertices { get; } - bool CheckCollision(Vector2 point, ICollider2D otherCollider); + bool CheckCollision(Vector2 point, ICollider2D otherCollider, out Vector2 normal); void RecalculateVertices(); } diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index e9672c7..0480eef 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework; using Syntriax.Engine.Core; @@ -13,26 +14,46 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I { private List triangles = new List(32); private readonly List _vertices = new List(32); + private IRigidBody2D? _rigidBody2D = null; public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } public Action? OnCollision { get; set; } = null; + + private IList verticesOriginal { get; } = vertices; + public Vector2 OffsetPosition { get; set; } = Vector2.Zero; public Vector2 OffsetScale { get; set; } = Vector2.One; public float OffsetRotation { get; set; } = 0f; ITransform IAssignableTransform.Transform => Transform; + public IReadOnlyList Vertices => _vertices; + + public IRigidBody2D? RigidBody2D + { + get + { + if (_rigidBody2D is null) + BehaviourController.TryGetBehaviour(out _rigidBody2D); + + return _rigidBody2D; + } + } public bool Assign(ITransform transform) => GameObject.Assign(transform); - public bool CheckCollision(Vector2 point, ICollider2D otherCollider) + public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out Vector2 normal) { + normal = Vector2.Zero; + foreach (var triangle in triangles) { if (!isInside(point, triangle)) continue; OnCollision?.Invoke(this, otherCollider); + + normal = Transform.Position - otherCollider.Transform.Position; return true; } @@ -44,7 +65,7 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I triangles.Clear(); _vertices.Clear(); - foreach (var vertex in VerticesOriginal) + foreach (var vertex in verticesOriginal) _vertices.Add(vertex + Transform.Position); Triangle superTriangle = GetSuperTriangle(_vertices); @@ -227,7 +248,4 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I return result; } - - public IList VerticesOriginal { get; } = vertices; - public IReadOnlyList Vertices => _vertices; } diff --git a/Game/Physics2D/CollisionInformation.cs b/Game/Physics2D/CollisionInformation.cs new file mode 100644 index 0000000..d7da43d --- /dev/null +++ b/Game/Physics2D/CollisionInformation.cs @@ -0,0 +1,12 @@ +using Microsoft.Xna.Framework; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public record CollisionInformation +( + Vector2 Normal, + float Impulse, + IRigidBody2D? RigidBodyX, + IRigidBody2D? RigidBodyY +); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 35209da..7567262 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -59,10 +59,14 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) foreach (var vertex in colliderX.Vertices) { - if (!colliders[colliderIY].CheckCollision(vertex, colliderX)) + if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var collisionInformation)) continue; - Console.WriteLine($"Collision"); + // Console.WriteLine($"Collision"); + // if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) + // rigidX.Velocity = -rigidX.Velocity; + // if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) + // rigidY.Velocity = -rigidY.Velocity; break; } } From c66eec61acd11c3fc0893eddc00047eaf0629510 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 13:35:31 +0300 Subject: [PATCH 05/81] Test 43124 --- Game/Game1.cs | 6 +-- Game/Physics2D/Collider2DBehaviour.cs | 78 +++++++++++++++++++++++++-- Game/Physics2D/PhysicsEngine2D.cs | 11 ++-- 3 files changed, 84 insertions(+), 11 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 6fb4ce2..3c82bca 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -64,7 +64,7 @@ public class Game1 : Game gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + gameObjectBall.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; // gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); IGameObject gameObjectBall2 = gameManager.InstantiateGameObject(); @@ -74,7 +74,7 @@ public class Game1 : Game RigidBody2D rigidBody = gameObjectBall2.BehaviourController.AddBehaviour(); rigidBody.Velocity = Vector2.UnitY * 100f; engine.AddRigidBody(rigidBody); - gameObjectBall2.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + gameObjectBall2.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; // gameObjectBall2.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); gameObjectBall2.BehaviourController.AddBehaviour().Assign(spriteBall); @@ -83,7 +83,7 @@ public class Game1 : Game gameObjectBall3.Transform.Position = Vector2.UnitY * -120f + Vector2.UnitX * 10f; gameObjectBall3.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall3.BehaviourController.AddBehaviour()); - gameObjectBall3.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]); + gameObjectBall3.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; // gameObjectBall3.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); gameObjectBall3.BehaviourController.AddBehaviour().Assign(spriteBall); // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index 0480eef..336f98a 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -44,7 +44,7 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out Vector2 normal) { - normal = Vector2.Zero; + normal = Vector2.UnitX; foreach (var triangle in triangles) { @@ -53,7 +53,17 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I OnCollision?.Invoke(this, otherCollider); - normal = Transform.Position - otherCollider.Transform.Position; + Edge main = new() { A = otherCollider.Transform.Position, B = point }; + + foreach (var edge in GetEdges(triangle)) + { + if (!DoIntersect(main, edge)) + continue; + normal = edge.A - edge.B; + normal.Normalize(); + normal = new Vector2(normal.Y, normal.X); + break; + } return true; } @@ -66,7 +76,10 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I _vertices.Clear(); foreach (var vertex in verticesOriginal) - _vertices.Add(vertex + Transform.Position); + { + Vector2 scaledPosition = new Vector2(vertex.X * Transform.Scale.X * OffsetScale.X, vertex.Y * Transform.Scale.Y * OffsetScale.Y); + _vertices.Add(scaledPosition + Transform.Position); + } Triangle superTriangle = GetSuperTriangle(_vertices); triangles.Add(superTriangle); @@ -248,4 +261,63 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I return result; } + + // Given three collinear points p, q, r, the function checks if + // point q lies on line segment 'pr' + private bool OnSegment(Vector2 p, Vector2 q, Vector2 r) + { + if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && + q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) + return true; + + return false; + } + + // To find orientation of ordered triplet (p, q, r). + // The function returns following values + // 0 --> p, q and r are collinear + // 1 --> Clockwise + // 2 --> Counterclockwise + private int Orientation(Vector2 p, Vector2 q, Vector2 r) + { + // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ + // for details of below formula. + float val = (q.Y - p.Y) * (r.X - q.X) - + (q.X - p.X) * (r.Y - q.Y); + + if (val == 0) return 0; // collinear + + return (val > 0) ? 1 : 2; // clock or counterclock wise + } + + // The main function that returns true if line segment 'edge1.Aedge1.B' + // and 'edge2.Aedge2.B' intersect. + private bool DoIntersect(Edge edge1, Edge edge2) + { + // Find the four orientations needed for general and + // special cases + int o1 = Orientation(edge1.A, edge1.B, edge2.A); + int o2 = Orientation(edge1.A, edge1.B, edge2.B); + int o3 = Orientation(edge2.A, edge2.B, edge1.A); + int o4 = Orientation(edge2.A, edge2.B, edge1.B); + + // General case + if (o1 != o2 && o3 != o4) + return true; + + // Special Cases + // edge1.A, edge1.B and edge2.A are collinear and edge2.A lies on segment edge1.Aedge1.B + if (o1 == 0 && OnSegment(edge1.A, edge2.A, edge1.B)) return true; + + // edge1.A, edge1.B and edge2.B are collinear and edge2.B lies on segment edge1.Aedge1.B + if (o2 == 0 && OnSegment(edge1.A, edge2.B, edge1.B)) return true; + + // edge2.A, edge2.B and edge1.A are collinear and edge1.A lies on segment edge2.Aedge2.B + if (o3 == 0 && OnSegment(edge2.A, edge1.A, edge2.B)) return true; + + // edge2.A, edge2.B and edge1.B are collinear and edge1.B lies on segment edge2.Aedge2.B + if (o4 == 0 && OnSegment(edge2.A, edge1.B, edge2.B)) return true; + + return false; // Doesn't fall in any of the above cases + } } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 7567262..c5a6f72 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -59,14 +59,15 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) foreach (var vertex in colliderX.Vertices) { - if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var collisionInformation)) + if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var normal)) continue; + if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) + rigidX.Velocity = -normal * rigidX.Velocity.Length(); + if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) + rigidY.Velocity = normal * rigidY.Velocity.Length(); + // Console.WriteLine($"Collision"); - // if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) - // rigidX.Velocity = -rigidX.Velocity; - // if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) - // rigidY.Velocity = -rigidY.Velocity; break; } } From 84ecc68320b7e213dfa8a4441678227ac5496896 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 14:06:52 +0300 Subject: [PATCH 06/81] Tets1231 --- Game/Behaviours/MovementBallBehaviour.cs | 66 ++++++++++--------- Game/Game1.cs | 82 +++++++++++++----------- Game/Physics2D/PhysicsEngine2D.cs | 4 +- 3 files changed, 82 insertions(+), 70 deletions(-) diff --git a/Game/Behaviours/MovementBallBehaviour.cs b/Game/Behaviours/MovementBallBehaviour.cs index b7cd436..d6c6b2a 100644 --- a/Game/Behaviours/MovementBallBehaviour.cs +++ b/Game/Behaviours/MovementBallBehaviour.cs @@ -3,43 +3,49 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Syntriax.Engine.Core; using Syntriax.Engine.Input; +using Syntriax.Engine.Physics2D.Abstract; namespace Pong.Behaviours; -public class MovementBallBehaviour(Vector2 StartDirection, PlayAreaBehaviour PlayAreaBehaviour, float Speed) : BehaviourOverride +public class MovementBallBehaviour(Vector2 StartDirection, float Speed) : BehaviourOverride { - public Vector2 StartDirection { get; private set; } = StartDirection; - public PlayAreaBehaviour PlayAreaBehaviour { get; } = PlayAreaBehaviour; + public Vector2 StartDirection { get; private set; } = Vector2.Normalize(StartDirection); public float Speed { get; set; } = Speed; - protected override void OnInitialize() => StartDirection.Normalize(); - - protected override void OnUpdate(GameTime time) + protected override void OnFirstActiveFrame(GameTime time) { - GameObject.Transform.Position += StartDirection * (time.ElapsedGameTime.Nanoseconds * .001f) * Speed; + if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidBody)) + throw new Exception($"Where's my {nameof(IRigidBody2D)}????"); - float absY = MathF.Abs(GameObject.Transform.Position.Y); - float differenceY = absY - PlayAreaBehaviour.PlayArea.Y * 0.5f; - if (differenceY > 0f) - { - if (GameObject.Transform.Position.Y > 0f) - GameObject.Transform.Position -= Vector2.UnitY * differenceY * 2f; - else - GameObject.Transform.Position += Vector2.UnitY * differenceY * 2f; - - StartDirection = new(StartDirection.X, -StartDirection.Y); - } - - float absX = MathF.Abs(GameObject.Transform.Position.X); - float differenceX = absX - PlayAreaBehaviour.PlayArea.X * 0.5f; - if (differenceX > 0f) - { - if (GameObject.Transform.Position.X > 0f) - GameObject.Transform.Position -= Vector2.UnitX * differenceX * 2f; - else - GameObject.Transform.Position += Vector2.UnitX * differenceX * 2f; - - StartDirection = new(-StartDirection.X, StartDirection.Y); - } + rigidBody.Velocity = StartDirection * Speed; } + + // protected override void OnUpdate(GameTime time) + // { + // GameObject.Transform.Position += StartDirection * (time.ElapsedGameTime.Nanoseconds * .001f) * Speed; + + // float absY = MathF.Abs(GameObject.Transform.Position.Y); + // float differenceY = absY - PlayAreaBehaviour.PlayArea.Y * 0.5f; + // if (differenceY > 0f) + // { + // if (GameObject.Transform.Position.Y > 0f) + // GameObject.Transform.Position -= Vector2.UnitY * differenceY * 2f; + // else + // GameObject.Transform.Position += Vector2.UnitY * differenceY * 2f; + + // StartDirection = new(StartDirection.X, -StartDirection.Y); + // } + + // float absX = MathF.Abs(GameObject.Transform.Position.X); + // float differenceX = absX - PlayAreaBehaviour.PlayArea.X * 0.5f; + // if (differenceX > 0f) + // { + // if (GameObject.Transform.Position.X > 0f) + // GameObject.Transform.Position -= Vector2.UnitX * differenceX * 2f; + // else + // GameObject.Transform.Position += Vector2.UnitX * differenceX * 2f; + + // StartDirection = new(-StartDirection.X, StartDirection.Y); + // } + // } } diff --git a/Game/Game1.cs b/Game/Game1.cs index 3c82bca..9cb06d1 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -45,7 +45,7 @@ public class Game1 : Game engine = new PhysicsEngine2D(); _spriteBatch = new SpriteBatch(GraphicsDevice); - // Sprite spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + Sprite spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); @@ -55,52 +55,58 @@ public class Game1 : Game gameManager.Camera = gameObjectCamera.BehaviourController.AddBehaviour(); gameManager.Camera.Viewport = GraphicsDevice.Viewport; - // IGameObject gameObjectPlayArea = gameManager.InstantiateGameObject(); - // PlayAreaBehaviour playAreaBehaviour = gameObjectPlayArea.BehaviourController.AddBehaviour(); - // playAreaBehaviour.PlayArea = new Vector2(_graphics.PreferredBackBufferWidth, _graphics.PreferredBackBufferHeight); - IGameObject gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); gameObjectBall.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; - // gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); + gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - IGameObject gameObjectBall2 = gameManager.InstantiateGameObject(); - gameObjectBall2.Name = "Ball2"; - gameObjectBall2.Transform.Position = Vector2.UnitY * -50f; - gameObjectBall2.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); - RigidBody2D rigidBody = gameObjectBall2.BehaviourController.AddBehaviour(); - rigidBody.Velocity = Vector2.UnitY * 100f; - engine.AddRigidBody(rigidBody); - gameObjectBall2.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; - // gameObjectBall2.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); - gameObjectBall2.BehaviourController.AddBehaviour().Assign(spriteBall); - IGameObject gameObjectBall3 = gameManager.InstantiateGameObject(); - gameObjectBall3.Name = "Ball"; - gameObjectBall3.Transform.Position = Vector2.UnitY * -120f + Vector2.UnitX * 10f; - gameObjectBall3.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); - engine.AddRigidBody(gameObjectBall3.BehaviourController.AddBehaviour()); - gameObjectBall3.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; - // gameObjectBall3.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), playAreaBehaviour, 100f); - gameObjectBall3.BehaviourController.AddBehaviour().Assign(spriteBall); - // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); - // gameObjectLeft.Name = "Left"; - // gameObjectLeft.Transform.Position = new Vector2(-452, 0f); - // gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); - // gameObjectLeft.BehaviourController.AddBehaviour(); - // gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - // gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); + gameObjectLeft.Name = "Left"; + gameObjectLeft.Transform.Position = new Vector2(-452, 0f); + gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); + gameObjectLeft.BehaviourController.AddBehaviour(); + gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + gameObjectLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); + + IGameObject gameObjectRight = gameManager.InstantiateGameObject(); + gameObjectRight.Name = "Right"; + gameObjectRight.Transform.Position = new Vector2(452, 0f); + gameObjectRight.Transform.Scale = new Vector2(10f, 40f); + gameObjectRight.BehaviourController.AddBehaviour(); + gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); + gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); + gameObjectRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); + + + IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); + goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); + goPlayAreaTop.Transform.Scale = new Vector2(1024f, 40f); + goPlayAreaTop.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); + IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); + goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); + goPlayAreaBottom.Transform.Scale = new Vector2(1024f, 40f); + goPlayAreaBottom.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); + + IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); + goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); + goPlayAreaRight.Transform.Scale = new Vector2(40f, 576f); + goPlayAreaRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); + IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); + goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); + goPlayAreaLeft.Transform.Scale = new Vector2(40f, 576f); + goPlayAreaLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); - // IGameObject gameObjectRight = gameManager.InstantiateGameObject(); - // gameObjectRight.Name = "Right"; - // gameObjectRight.Transform.Position = new Vector2(452, 0f); - // gameObjectRight.Transform.Scale = new Vector2(10f, 40f); - // gameObjectRight.BehaviourController.AddBehaviour(); - // gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); - // gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); // TODO: use this.Content to load your game content here } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index c5a6f72..83f50f4 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -63,9 +63,9 @@ public class PhysicsEngine2D : IPhysicsEngine2D continue; if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) - rigidX.Velocity = -normal * rigidX.Velocity.Length(); + rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, normal); if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) - rigidY.Velocity = normal * rigidY.Velocity.Length(); + rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, normal); // Console.WriteLine($"Collision"); break; From def463afcf32cfef1274a398e6bea97e96443e3f Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 17:48:22 +0300 Subject: [PATCH 07/81] Test pNIADIPSDNIP --- Game/Game1.cs | 23 +++++++++++---- Game/Physics2D/Abstract/ICollider2D.cs | 2 +- Game/Physics2D/Collider2DBehaviour.cs | 40 ++++++++++++++++++++++---- Game/Physics2D/CollisionInformation.cs | 5 +--- Game/Physics2D/PhysicsEngine2D.cs | 31 ++++++++++++++++---- 5 files changed, 80 insertions(+), 21 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 9cb06d1..9d822d4 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -16,7 +16,8 @@ public class Game1 : Game private GraphicsDeviceManager _graphics = null!; private PhysicsEngine2D engine; private SpriteBatch _spriteBatch = null!; - private GameManager gameManager = null!; + public static GameManager gameManager = null!; + public static Sprite spriteBox = null!; public Game1() { @@ -45,7 +46,7 @@ public class Game1 : Game engine = new PhysicsEngine2D(); _spriteBatch = new SpriteBatch(GraphicsDevice); - Sprite spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); @@ -87,23 +88,27 @@ public class Game1 : Game IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); - goPlayAreaTop.Transform.Scale = new Vector2(1024f, 40f); + goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); + goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaTop.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); - goPlayAreaBottom.Transform.Scale = new Vector2(1024f, 40f); + goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); + goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaBottom.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); - goPlayAreaRight.Transform.Scale = new Vector2(40f, 576f); + goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); + goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); - goPlayAreaLeft.Transform.Scale = new Vector2(40f, 576f); + goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); + goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); @@ -142,9 +147,14 @@ public class Game1 : Game if (Keyboard.GetState().IsKeyDown(Keys.E)) gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + + if (Keyboard.GetState().IsKeyDown(Keys.Space)) + seconds += gameTime.ElapsedGameTime.Milliseconds * .0005f; + // TODO: Add your update logic here while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f) { + Console.WriteLine($"Physics Timer: {physicsTimer}"); physicsTimer += 0.01f; engine.Step(.01f); } @@ -152,6 +162,7 @@ public class Game1 : Game base.Update(gameTime); } static float physicsTimer = 0f; + static float seconds = 0f; protected override void Draw(GameTime gameTime) { diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index dad186f..f0717ee 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -19,7 +19,7 @@ public interface ICollider2D : IBehaviour, IAssignableTransform IReadOnlyList Vertices { get; } - bool CheckCollision(Vector2 point, ICollider2D otherCollider, out Vector2 normal); + bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation collisionInformation); void RecalculateVertices(); } diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index 336f98a..f2b0c5c 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -3,9 +3,10 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework; - +using Pong; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; @@ -42,9 +43,9 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I public bool Assign(ITransform transform) => GameObject.Assign(transform); - public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out Vector2 normal) + public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation collisionInformation) { - normal = Vector2.UnitX; + collisionInformation = new CollisionInformation(Vector2.Zero, Vector2.Zero); foreach (var triangle in triangles) { @@ -59,9 +60,19 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I { if (!DoIntersect(main, edge)) continue; - normal = edge.A - edge.B; + + Vector2 contactPoint = ClosestPointOnEdge(point, edge); + + Vector2 normal = contactPoint - point; normal.Normalize(); - normal = new Vector2(normal.Y, normal.X); + + collisionInformation = new CollisionInformation(normal, contactPoint); + + GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + gameObject.BehaviourController.AddBehaviour().Assign(Game1.spriteBox); + gameObject.Transform.Position = point; + gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; + gameObject.Transform.Rotation = (float)Math.Atan2(normal.Y, normal.X); break; } return true; @@ -143,6 +154,25 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I // } } + private Vector2 ClosestPointOnEdge(Vector2 point, Edge edge) + { + // Convert edge points to vectors + var edgeVector = new Vector2(edge.B.X - edge.A.X, edge.B.Y - edge.A.Y); + var pointVector = new Vector2(point.X - edge.A.X, point.Y - edge.A.Y); + + // Calculate the projection of pointVector onto edgeVector + float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); + + // Clamp t to the range [0, 1] to ensure the closest point is on the edge + t = Math.Max(0, Math.Min(1, t)); + + // Calculate the closest point on the edge + float closestX = edge.A.X + t * edgeVector.X; + float closestY = edge.A.Y + t * edgeVector.Y; + + return new Vector2(closestX, closestY); + } + private bool DoesEdgeExistInTriangles(Edge edge, List triangles) { foreach (var triangle in triangles) diff --git a/Game/Physics2D/CollisionInformation.cs b/Game/Physics2D/CollisionInformation.cs index d7da43d..24d561d 100644 --- a/Game/Physics2D/CollisionInformation.cs +++ b/Game/Physics2D/CollisionInformation.cs @@ -1,12 +1,9 @@ using Microsoft.Xna.Framework; -using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; public record CollisionInformation ( Vector2 Normal, - float Impulse, - IRigidBody2D? RigidBodyX, - IRigidBody2D? RigidBodyY + Vector2 ContactPosition ); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 83f50f4..f4a3737 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -57,18 +57,39 @@ public class PhysicsEngine2D : IPhysicsEngine2D { ICollider2D colliderX = colliders[colliderIX]; for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) - foreach (var vertex in colliderX.Vertices) + for (int i1 = 0; i1 < colliderX.Vertices.Count; i1++) { - if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var normal)) + Vector2 vertex = colliderX.Vertices[i1]; + if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var collisionInformation)) continue; + Console.WriteLine($"normal = {collisionInformation.Normal}"); + // // if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) + // // rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) - rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, normal); + { + Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); + rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); + + Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidX.Velocity.X, collisionInformation.Normal.Y * rigidX.Velocity.Y); + Console.WriteLine($"Displacement = {vector2}"); + rigidX.Transform.Position += vector2 * intervalDeltaTime * 2; + Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); + } if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) - rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, normal); + { + Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); + rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); + Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidY.Velocity.X, collisionInformation.Normal.Y * rigidY.Velocity.Y); + Console.WriteLine($"Displacement = {vector2}"); + rigidY.Transform.Position += vector2 * intervalDeltaTime * 2; + Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); + } + Console.WriteLine($"/////////////////////////////////////////////"); + colliders[colliderIY].RecalculateVertices(); + colliders[colliderIX].RecalculateVertices(); // Console.WriteLine($"Collision"); - break; } } } From 259941c867202ea60b4424a7a0f9e293e3d04fcc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 17:53:48 +0300 Subject: [PATCH 08/81] Tesset --- Game/Physics2D/PhysicsEngine2D.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index f4a3737..3ea7922 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -68,23 +68,26 @@ public class PhysicsEngine2D : IPhysicsEngine2D // // rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) { + Vector2 toContact = colliderX.Transform.Position - collisionInformation.ContactPosition; + Vector2 mirrored = Vector2.Reflect(toContact, new Vector2(collisionInformation.Normal.X, collisionInformation.Normal.Y)); Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidX.Velocity.X, collisionInformation.Normal.Y * rigidX.Velocity.Y); Console.WriteLine($"Displacement = {vector2}"); - rigidX.Transform.Position += vector2 * intervalDeltaTime * 2; + rigidX.Transform.Position -= mirrored * 2; Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); } - if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) - { - Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); - rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); - Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidY.Velocity.X, collisionInformation.Normal.Y * rigidY.Velocity.Y); - Console.WriteLine($"Displacement = {vector2}"); - rigidY.Transform.Position += vector2 * intervalDeltaTime * 2; - Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); - } + // if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) + // { + // Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); + // rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); + // rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); + // Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidY.Velocity.X, collisionInformation.Normal.Y * rigidY.Velocity.Y); + // Console.WriteLine($"Displacement = {vector2}"); + // rigidY.Transform.Position += vector2 * intervalDeltaTime * 2; + // Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); + // } Console.WriteLine($"/////////////////////////////////////////////"); colliders[colliderIY].RecalculateVertices(); colliders[colliderIX].RecalculateVertices(); From 1e8cc82dc4ce3954171520c3ca30d71f24bc000b Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 4 Dec 2023 23:55:43 +0300 Subject: [PATCH 09/81] Testset --- Game/Game1.cs | 2 +- Game/Physics2D/PhysicsEngine2D.cs | 63 +++++++++++++++---------------- 2 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 9d822d4..b7db248 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -152,7 +152,7 @@ public class Game1 : Game seconds += gameTime.ElapsedGameTime.Milliseconds * .0005f; // TODO: Add your update logic here - while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f) + while (physicsTimer + 0.01f < seconds) { Console.WriteLine($"Physics Timer: {physicsTimer}"); physicsTimer += 0.01f; diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 3ea7922..2b1997c 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -42,12 +42,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int i = 0; i < IterationCount; i++) { foreach (var rigidBody in rigidBodies) - { - Vector2 nextPosition = rigidBody.Transform.Position; - nextPosition += rigidBody.Velocity * intervalDeltaTime; - - rigidBody.Transform.Position = nextPosition; - } + StepRigidBody(rigidBody, intervalDeltaTime); foreach (var collider in colliders) @@ -57,47 +52,49 @@ public class PhysicsEngine2D : IPhysicsEngine2D { ICollider2D colliderX = colliders[colliderIX]; for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) - for (int i1 = 0; i1 < colliderX.Vertices.Count; i1++) + for (int verticesIndex = 0; verticesIndex < colliderX.Vertices.Count; verticesIndex++) { - Vector2 vertex = colliderX.Vertices[i1]; - if (!colliders[colliderIY].CheckCollision(vertex, colliderX, out var collisionInformation)) + if (!colliders[colliderIY].CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var collisionInformation)) continue; - Console.WriteLine($"normal = {collisionInformation.Normal}"); - // // if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) - // // rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); - if (colliders[colliderIX].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) + ICollider2D colliderY = colliders[colliderIY]; + if (colliderX.BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) { - Vector2 toContact = colliderX.Transform.Position - collisionInformation.ContactPosition; - Vector2 mirrored = Vector2.Reflect(toContact, new Vector2(collisionInformation.Normal.X, collisionInformation.Normal.Y)); - Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); + Vector2 xVertex = colliderX.Vertices[verticesIndex]; + Vector2 edgeDirection = new Vector2(collisionInformation.Normal.Y, collisionInformation.Normal.X); + Vector2 p1 = xVertex - rigidX.Velocity * intervalDeltaTime; + float t = IntersectionParameterT(collisionInformation.ContactPosition - edgeDirection * 100f, collisionInformation.ContactPosition + edgeDirection * 100f, xVertex, p1); + Vector2 vertexNewPosition = Vector2.Lerp(xVertex, p1, t); rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); + rigidX.Transform.Position -= xVertex - vertexNewPosition; - Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidX.Velocity.X, collisionInformation.Normal.Y * rigidX.Velocity.Y); - Console.WriteLine($"Displacement = {vector2}"); - rigidX.Transform.Position -= mirrored * 2; - Console.WriteLine($"rigidX.Velocity = {rigidX.Velocity}"); + StepRigidBody(rigidX, intervalDeltaTime * (1f - t)); + colliders[colliderIX].RecalculateVertices(); } - // if (colliders[colliderIY].BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidY)) - // { - // Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); - // rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); - // rigidY.Velocity = Vector2.Reflect(rigidY.Velocity, collisionInformation.Normal); - // Vector2 vector2 = -new Vector2(collisionInformation.Normal.X * rigidY.Velocity.X, collisionInformation.Normal.Y * rigidY.Velocity.Y); - // Console.WriteLine($"Displacement = {vector2}"); - // rigidY.Transform.Position += vector2 * intervalDeltaTime * 2; - // Console.WriteLine($"rigidY.Velocity = {rigidY.Velocity}"); - // } - Console.WriteLine($"/////////////////////////////////////////////"); - colliders[colliderIY].RecalculateVertices(); - colliders[colliderIX].RecalculateVertices(); + Console.WriteLine($"/////////////////////////////////////////////"); // Console.WriteLine($"Collision"); } } } } + private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) + { + Vector2 nextPosition = rigidBody.Transform.Position; + nextPosition += rigidBody.Velocity * intervalDeltaTime; + + rigidBody.Transform.Position = nextPosition; + } + + private float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) + { + // Solve the linear interpolation equation for 't' + float t = ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / + ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); + + return t; + } private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) { From b8706e82d8546271cc2690ad709a9c26d03b65cc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 14:47:17 +0300 Subject: [PATCH 10/81] Tetstests --- Game/Game1.cs | 17 +++++++- Game/Physics2D/Collider2DBehaviour.cs | 61 +++++++++++++++++++++------ Game/Physics2D/PhysicsEngine2D.cs | 44 +++++++++++++++++-- 3 files changed, 104 insertions(+), 18 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index b7db248..43c697e 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -112,6 +112,12 @@ public class Game1 : Game goPlayAreaLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); + // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); + // goPlayAreaCenter.Transform.Position = new Vector2(100f, 100f); + // goPlayAreaCenter.Transform.Scale = new Vector2(40f, 40f); + // // goPlayAreaCenter.BehaviourController.AddBehaviour().Assign(spriteBox); + // goPlayAreaCenter.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); + // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour()); // TODO: use this.Content to load your game content here } @@ -150,8 +156,17 @@ public class Game1 : Game if (Keyboard.GetState().IsKeyDown(Keys.Space)) seconds += gameTime.ElapsedGameTime.Milliseconds * .0005f; + if (Keyboard.GetState().IsKeyDown(Keys.B)) + { + seconds -= gameTime.ElapsedGameTime.Milliseconds * .0005f; + while (physicsTimer - 0.01f > seconds) + { + Console.WriteLine($"Physics Timer: {physicsTimer}"); + physicsTimer -= 0.01f; + engine.Step(-.01f); + } + } - // TODO: Add your update logic here while (physicsTimer + 0.01f < seconds) { Console.WriteLine($"Physics Timer: {physicsTimer}"); diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index f2b0c5c..4908688 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -64,15 +64,12 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I Vector2 contactPoint = ClosestPointOnEdge(point, edge); Vector2 normal = contactPoint - point; + if (normal.LengthSquared() < 0.001f) + normal = new Vector2(0f, 1f); + normal.Normalize(); collisionInformation = new CollisionInformation(normal, contactPoint); - - GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - gameObject.BehaviourController.AddBehaviour().Assign(Game1.spriteBox); - gameObject.Transform.Position = point; - gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; - gameObject.Transform.Rotation = (float)Math.Atan2(normal.Y, normal.X); break; } return true; @@ -142,18 +139,54 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I triangles.RemoveAt(i); } - // for (int i = 0; i < triangles.Count; i++) - // { - // Triangle triangle = triangles[i]; + for (int i = gameObjects.Count - 1; i >= 0; i--) + { + IGameObject gameObject = gameObjects[i]; + Game1.gameManager.RemoveGameObject(gameObject); + gameObjects.RemoveAt(i); + } - // triangle.A += Transform.Position; - // triangle.B += Transform.Position; - // triangle.C += Transform.Position; - // triangles[i] = triangle; - // } + for (int i = 0; i < triangles.Count; i++) + { + Triangle triangle = triangles[i]; + foreach (var edge in GetEdges(triangle)) + { + GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + displayableSpriteBehaviour.Color = Color.Aqua; + displayableSpriteBehaviour.Origin = new(0.5f, 1f); + displayableSpriteBehaviour.Assign(Game1.spriteBox); + gameObject.Transform.Position = edge.A; + Vector2 vector2 = edge.B - edge.A; + gameObject.Transform.Scale = new Vector2(2f, .0f) + Vector2.UnitY * vector2.Length(); + gameObject.Transform.Rotation = (float)Math.Atan2(vector2.X, vector2.Y); + gameObjects.Add(gameObject); + + gameObject = Game1.gameManager.InstantiateGameObject(); + displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + displayableSpriteBehaviour.Color = Color.Crimson; + displayableSpriteBehaviour.Assign(Game1.spriteBox); + gameObject.Transform.Position = edge.B; + gameObject.Transform.Scale = new Vector2(4f, 4f); + gameObjects.Add(gameObject); + } + } + + foreach (var vertex in Vertices) + { + GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + displayableSpriteBehaviour.Color = Color.GreenYellow; + displayableSpriteBehaviour.Assign(Game1.spriteBox); + gameObject.Transform.Position = vertex; + gameObject.Transform.Scale = new Vector2(2f, 2f); + gameObjects.Add(gameObject); + } } + private List gameObjects = new List(32); + private Vector2 ClosestPointOnEdge(Vector2 point, Edge edge) { // Convert edge points to vectors diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 2b1997c..ad4a36b 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; +using Pong; +using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; @@ -54,10 +57,10 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) for (int verticesIndex = 0; verticesIndex < colliderX.Vertices.Count; verticesIndex++) { - if (!colliders[colliderIY].CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var collisionInformation)) + ICollider2D colliderY = colliders[colliderIY]; + if (!colliderY.CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var collisionInformation)) continue; - ICollider2D colliderY = colliders[colliderIY]; if (colliderX.BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) { Vector2 xVertex = colliderX.Vertices[verticesIndex]; @@ -68,10 +71,45 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); rigidX.Transform.Position -= xVertex - vertexNewPosition; + // { + // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + // displayableSpriteBehaviour.Assign(Game1.spriteBox); + // gameObject.Transform.Position = collisionInformation.ContactPosition; + // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; + // gameObject.Transform.Rotation = (float)Math.Atan2(collisionInformation.Normal.Y, collisionInformation.Normal.X); + // } + // { + // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + // displayableSpriteBehaviour.Color = Color.Aqua; + // displayableSpriteBehaviour.Assign(Game1.spriteBox); + // gameObject.Transform.Position = collisionInformation.ContactPosition; + // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; + // gameObject.Transform.Rotation = (float)Math.Atan2(rigidX.Velocity.Y, rigidX.Velocity.X); + // } + // { + // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + // displayableSpriteBehaviour.Color = Color.Pink; + // displayableSpriteBehaviour.Assign(Game1.spriteBox); + // gameObject.Transform.Position = collisionInformation.ContactPosition; + // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; + // gameObject.Transform.Rotation = (float)Math.Atan2(edgeDirection.Y, edgeDirection.X); + // } + // { + // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); + // displayableSpriteBehaviour.Color = Color.DarkGoldenrod; + // displayableSpriteBehaviour.Assign(Game1.spriteBox); + // gameObject.Transform.Position = collisionInformation.ContactPosition; + // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; + // gameObject.Transform.Rotation = (float)Math.Atan2((xVertex - p1).Y, (xVertex - p1).X); + // } + StepRigidBody(rigidX, intervalDeltaTime * (1f - t)); colliders[colliderIX].RecalculateVertices(); } - Console.WriteLine($"/////////////////////////////////////////////"); // Console.WriteLine($"Collision"); } From 4692b4e25ebd093360c773dca682a67d966c6fba Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 15:27:31 +0300 Subject: [PATCH 11/81] afgdggdfga --- Game/Game1.cs | 43 +++++++++++++++----------- Game/Physics2D/Collider2DBehaviour.cs | 44 +++++++++++++-------------- Game/Physics2D/PhysicsEngine2D.cs | 2 ++ 3 files changed, 49 insertions(+), 40 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 43c697e..f28e575 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -56,7 +56,7 @@ public class Game1 : Game gameManager.Camera = gameObjectCamera.BehaviourController.AddBehaviour(); gameManager.Camera.Viewport = GraphicsDevice.Viewport; - IGameObject gameObjectBall = gameManager.InstantiateGameObject(); + gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); @@ -89,26 +89,26 @@ public class Game1 : Game IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); - goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); + // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaTop.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); - goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); + // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaBottom.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); - goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); + // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); - goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); goPlayAreaLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); @@ -154,20 +154,23 @@ public class Game1 : Game gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; - if (Keyboard.GetState().IsKeyDown(Keys.Space)) - seconds += gameTime.ElapsedGameTime.Milliseconds * .0005f; - if (Keyboard.GetState().IsKeyDown(Keys.B)) - { - seconds -= gameTime.ElapsedGameTime.Milliseconds * .0005f; - while (physicsTimer - 0.01f > seconds) - { - Console.WriteLine($"Physics Timer: {physicsTimer}"); - physicsTimer -= 0.01f; - engine.Step(-.01f); - } - } + // if (Keyboard.GetState().IsKeyDown(Keys.N)) + // seconds = 39.12f; + // if (Keyboard.GetState().IsKeyDown(Keys.Space)) + // seconds += gameTime.ElapsedGameTime.Milliseconds * .005f; + // if (Keyboard.GetState().IsKeyDown(Keys.B)) + // { + // seconds -= gameTime.ElapsedGameTime.Milliseconds * .005f; + // while (physicsTimer - 0.01f > seconds) + // { + // Console.WriteLine($"Physics Timer: {physicsTimer}"); + // physicsTimer -= 0.01f; + // engine.Step(-.01f); + // } + // } - while (physicsTimer + 0.01f < seconds) + + while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) { Console.WriteLine($"Physics Timer: {physicsTimer}"); physicsTimer += 0.01f; @@ -178,11 +181,15 @@ public class Game1 : Game } static float physicsTimer = 0f; static float seconds = 0f; + private GameObject gameObjectBall; protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(new Color() { R = 32, G = 32, B = 32 }); + // gameManager.Camera.Position = gameObjectBall.Transform.Position; + // Console.WriteLine($"Pos: {gameManager.Camera.Position}"); + // TODO: Add your drawing code here gameManager.PreDraw(gameTime); gameManager.Camera.Update(); diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index 4908688..b71af97 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -194,16 +194,16 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I var pointVector = new Vector2(point.X - edge.A.X, point.Y - edge.A.Y); // Calculate the projection of pointVector onto edgeVector - float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); + double t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); // Clamp t to the range [0, 1] to ensure the closest point is on the edge t = Math.Max(0, Math.Min(1, t)); // Calculate the closest point on the edge - float closestX = edge.A.X + t * edgeVector.X; - float closestY = edge.A.Y + t * edgeVector.Y; + double closestX = edge.A.X + t * edgeVector.X; + double closestY = edge.A.Y + t * edgeVector.Y; - return new Vector2(closestX, closestY); + return new Vector2((float)closestX, (float)closestY); } private bool DoesEdgeExistInTriangles(Edge edge, List triangles) @@ -226,8 +226,8 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I private Triangle GetSuperTriangle(IReadOnlyList vertices) { - float minX = float.MaxValue, minY = float.MaxValue; - float maxX = float.MinValue, maxY = float.MinValue; + double minX = double.MaxValue, minY = double.MaxValue; + double maxX = double.MinValue, maxY = double.MinValue; foreach (Vector2 point in vertices) { @@ -237,15 +237,15 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I maxY = Math.Max(maxY, point.Y); } - float dx = maxX - minX; - float dy = maxY - minY; - float deltaMax = Math.Max(dx, dy); - float midX = (minX + maxX) / 2; - float midY = (minY + maxY) / 2; + double dx = maxX - minX; + double dy = maxY - minY; + double deltaMax = Math.Max(dx, dy); + double midX = (minX + maxX) / 2; + double midY = (minY + maxY) / 2; - Vector2 p1 = new Vector2(midX - 20 * deltaMax, midY - deltaMax); - Vector2 p2 = new Vector2(midX, midY + 20 * deltaMax); - Vector2 p3 = new Vector2(midX + 20 * deltaMax, midY - deltaMax); + Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); + Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); return new Triangle() { A = p1, B = p2, C = p3 }; } @@ -281,7 +281,7 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I // double A3 = area(x1, y1, x2, y2, x, y); /* Check if sum of A1, A2 and A3 is same as A */ - return A == A1 + A2 + A3; + return A >= A1 + A2 + A3; } private struct Edge @@ -303,16 +303,16 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I Vector2 midAB = (triangle.A + triangle.B) / 2; Vector2 midBC = (triangle.B + triangle.C) / 2; - float slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); - float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); + double slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); + double slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); // Check if the slopes are not parallel - if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) + if (Math.Abs(slopeAB - slopeBC) > double.Epsilon) { - float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); - float y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; + double x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); + double y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; - result.Center = new Vector2(x, y); + result.Center = new Vector2((float)x, (float)y); result.Radius = Vector2.Distance(result.Center, triangle.A); } else @@ -345,7 +345,7 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I { // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ // for details of below formula. - float val = (q.Y - p.Y) * (r.X - q.X) - + double val = (q.Y - p.Y) * (r.X - q.X) - (q.X - p.X) * (r.Y - q.Y); if (val == 0) return 0; // collinear diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index ad4a36b..61646fb 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -58,6 +58,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int verticesIndex = 0; verticesIndex < colliderX.Vertices.Count; verticesIndex++) { ICollider2D colliderY = colliders[colliderIY]; + bool v = colliderY.CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var _); if (!colliderY.CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var collisionInformation)) continue; @@ -109,6 +110,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D StepRigidBody(rigidX, intervalDeltaTime * (1f - t)); colliders[colliderIX].RecalculateVertices(); + verticesIndex--; } Console.WriteLine($"/////////////////////////////////////////////"); // Console.WriteLine($"Collision"); From 40a06fae4d9ed02aec3c752b498a868249269f47 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 17:04:26 +0300 Subject: [PATCH 12/81] dsasadasdasd --- Game/Physics2D/Abstract/ICollider2D.cs | 2 +- Game/Physics2D/Collider2DBehaviour.cs | 243 +++---------------------- Game/Physics2D/PhysicsEngine2D.cs | 74 -------- Game/Physics2D/PhysicsMath.cs | 210 +++++++++++++++++++++ 4 files changed, 232 insertions(+), 297 deletions(-) create mode 100644 Game/Physics2D/PhysicsMath.cs diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index f0717ee..131cac3 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -19,7 +19,7 @@ public interface ICollider2D : IBehaviour, IAssignableTransform IReadOnlyList Vertices { get; } - bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation collisionInformation); + bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation? collisionInformation); void RecalculateVertices(); } diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs index b71af97..33a2c91 100644 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ b/Game/Physics2D/Collider2DBehaviour.cs @@ -2,8 +2,11 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.CodeAnalysis; + using Microsoft.Xna.Framework; + using Pong; + using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; @@ -11,6 +14,7 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; + public class Collider2DBehaviour(IList vertices) : BehaviourOverride, ICollider2D { private List triangles = new List(32); @@ -49,19 +53,19 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I foreach (var triangle in triangles) { - if (!isInside(point, triangle)) + if (!PhysicsMath.IsInTriangle(point, triangle)) continue; OnCollision?.Invoke(this, otherCollider); - Edge main = new() { A = otherCollider.Transform.Position, B = point }; + Line main = new(otherCollider.Transform.Position, point); - foreach (var edge in GetEdges(triangle)) + foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) { - if (!DoIntersect(main, edge)) + if (!PhysicsMath.DoIntersect(main, line)) continue; - Vector2 contactPoint = ClosestPointOnEdge(point, edge); + Vector2 contactPoint = PhysicsMath.ClosestPointOnLine(point, line); Vector2 normal = contactPoint - point; if (normal.LengthSquared() < 0.001f) @@ -89,11 +93,11 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I _vertices.Add(scaledPosition + Transform.Position); } - Triangle superTriangle = GetSuperTriangle(_vertices); + Triangle superTriangle = PhysicsMath.GetSuperTriangle(_vertices); triangles.Add(superTriangle); List badTriangles = new(32); - List polygon = new(32); + List polygon = new(32); foreach (var vertex in _vertices) { @@ -102,30 +106,21 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I foreach (var triangle in triangles) { - Circle circle = GetCircumCircle(triangle); + Circle circle = PhysicsMath.GetCircumCircle(triangle); if (Vector2.DistanceSquared(circle.Center, vertex) <= circle.Radius * circle.Radius) badTriangles.Add(triangle); } foreach (var triangle in badTriangles) - foreach (var edge in GetEdges(triangle)) - { - if (DoesEdgeExistInTriangles(edge, badTriangles)) - polygon.Add(edge); - } + foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) + if (PhysicsMath.DoesLineExistInVertices(line, [triangle.A, triangle.B, triangle.C])) + polygon.Add(line); foreach (var triangle in badTriangles) triangles.Remove(triangle); - foreach (var edge in polygon) - { - triangles.Add(new() - { - A = edge.A, - B = edge.B, - C = vertex - }); - } + foreach (var line in polygon) + triangles.Add(new(line.From, line.To, vertex)); } for (int i = triangles.Count - 1; i >= 0; i--) @@ -150,15 +145,15 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I for (int i = 0; i < triangles.Count; i++) { Triangle triangle = triangles[i]; - foreach (var edge in GetEdges(triangle)) + foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) { GameObject gameObject = Game1.gameManager.InstantiateGameObject(); DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); displayableSpriteBehaviour.Color = Color.Aqua; displayableSpriteBehaviour.Origin = new(0.5f, 1f); displayableSpriteBehaviour.Assign(Game1.spriteBox); - gameObject.Transform.Position = edge.A; - Vector2 vector2 = edge.B - edge.A; + gameObject.Transform.Position = line.From; + Vector2 vector2 = line.To - line.From; gameObject.Transform.Scale = new Vector2(2f, .0f) + Vector2.UnitY * vector2.Length(); gameObject.Transform.Rotation = (float)Math.Atan2(vector2.X, vector2.Y); gameObjects.Add(gameObject); @@ -167,7 +162,7 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); displayableSpriteBehaviour.Color = Color.Crimson; displayableSpriteBehaviour.Assign(Game1.spriteBox); - gameObject.Transform.Position = edge.B; + gameObject.Transform.Position = line.To; gameObject.Transform.Scale = new Vector2(4f, 4f); gameObjects.Add(gameObject); } @@ -187,200 +182,4 @@ public class Collider2DBehaviour(IList vertices) : BehaviourOverride, I private List gameObjects = new List(32); - private Vector2 ClosestPointOnEdge(Vector2 point, Edge edge) - { - // Convert edge points to vectors - var edgeVector = new Vector2(edge.B.X - edge.A.X, edge.B.Y - edge.A.Y); - var pointVector = new Vector2(point.X - edge.A.X, point.Y - edge.A.Y); - - // Calculate the projection of pointVector onto edgeVector - double t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); - - // Clamp t to the range [0, 1] to ensure the closest point is on the edge - t = Math.Max(0, Math.Min(1, t)); - - // Calculate the closest point on the edge - double closestX = edge.A.X + t * edgeVector.X; - double closestY = edge.A.Y + t * edgeVector.Y; - - return new Vector2((float)closestX, (float)closestY); - } - - private bool DoesEdgeExistInTriangles(Edge edge, List triangles) - { - foreach (var triangle in triangles) - foreach (var edgeOther in GetEdges(triangle)) - if (edge.A == edgeOther.A && edge.B == edgeOther.B) - return true; - else if (edge.A == edgeOther.B && edge.B == edgeOther.A) - return true; - return false; - } - - private List GetEdges(Triangle triangle) - => [ - new() { A = triangle.A, B = triangle.B }, - new() { A = triangle.B, B = triangle.C }, - new() { A = triangle.C, B = triangle.A } - ]; - - private Triangle GetSuperTriangle(IReadOnlyList vertices) - { - double minX = double.MaxValue, minY = double.MaxValue; - double maxX = double.MinValue, maxY = double.MinValue; - - foreach (Vector2 point in vertices) - { - minX = Math.Min(minX, point.X); - minY = Math.Min(minY, point.Y); - maxX = Math.Max(maxX, point.X); - maxY = Math.Max(maxY, point.Y); - } - - double dx = maxX - minX; - double dy = maxY - minY; - double deltaMax = Math.Max(dx, dy); - double midX = (minX + maxX) / 2; - double midY = (minY + maxY) / 2; - - Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); - Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); - Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); - - return new Triangle() { A = p1, B = p2, C = p3 }; - } - - private struct Triangle { public Vector2 A, B, C; } - - private double GetArea(Triangle triangle) - { - return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + - triangle.B.X * (triangle.C.Y - triangle.A.Y) + - triangle.C.X * (triangle.A.Y - triangle.B.Y)) / 2.0); - } - - /* A function to check whether point P(x, y) lies - inside the triangle formed by A(x1, y1), - B(x2, y2) and C(x3, y3) */ - private bool isInside(Vector2 point, Triangle triangle) - { - double A = GetArea(triangle); - /* Calculate area of triangle ABC */ - // double A = area(x1, y1, x2, y2, x3, y3); - - double A1 = GetArea(new() { A = point, B = triangle.B, C = triangle.C }); - /* Calculate area of triangle PBC */ - // double A1 = area(x, y, x2, y2, x3, y3); - - /* Calculate area of triangle PAC */ - double A2 = GetArea(new() { A = triangle.A, B = point, C = triangle.C }); - // double A2 = area(x1, y1, x, y, x3, y3); - - /* Calculate area of triangle PAB */ - double A3 = GetArea(new() { A = triangle.A, B = triangle.B, C = point }); - // double A3 = area(x1, y1, x2, y2, x, y); - - /* Check if sum of A1, A2 and A3 is same as A */ - return A >= A1 + A2 + A3; - } - - private struct Edge - { - public Vector2 A; - public Vector2 B; - } - - private struct Circle - { - public double Radius; - public Vector2 Center; - } - - private Circle GetCircumCircle(Triangle triangle) - { - Circle result = new(); - - Vector2 midAB = (triangle.A + triangle.B) / 2; - Vector2 midBC = (triangle.B + triangle.C) / 2; - - double slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); - double slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); - - // Check if the slopes are not parallel - if (Math.Abs(slopeAB - slopeBC) > double.Epsilon) - { - double x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); - double y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; - - result.Center = new Vector2((float)x, (float)y); - result.Radius = Vector2.Distance(result.Center, triangle.A); - } - else - { - // If slopes are parallel, use the midpoints of the sides as the circumcenter - result.Center = (midAB + midBC) / 2; - result.Radius = Vector2.Distance(result.Center, triangle.A); - } - - return result; - } - - // Given three collinear points p, q, r, the function checks if - // point q lies on line segment 'pr' - private bool OnSegment(Vector2 p, Vector2 q, Vector2 r) - { - if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && - q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) - return true; - - return false; - } - - // To find orientation of ordered triplet (p, q, r). - // The function returns following values - // 0 --> p, q and r are collinear - // 1 --> Clockwise - // 2 --> Counterclockwise - private int Orientation(Vector2 p, Vector2 q, Vector2 r) - { - // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ - // for details of below formula. - double val = (q.Y - p.Y) * (r.X - q.X) - - (q.X - p.X) * (r.Y - q.Y); - - if (val == 0) return 0; // collinear - - return (val > 0) ? 1 : 2; // clock or counterclock wise - } - - // The main function that returns true if line segment 'edge1.Aedge1.B' - // and 'edge2.Aedge2.B' intersect. - private bool DoIntersect(Edge edge1, Edge edge2) - { - // Find the four orientations needed for general and - // special cases - int o1 = Orientation(edge1.A, edge1.B, edge2.A); - int o2 = Orientation(edge1.A, edge1.B, edge2.B); - int o3 = Orientation(edge2.A, edge2.B, edge1.A); - int o4 = Orientation(edge2.A, edge2.B, edge1.B); - - // General case - if (o1 != o2 && o3 != o4) - return true; - - // Special Cases - // edge1.A, edge1.B and edge2.A are collinear and edge2.A lies on segment edge1.Aedge1.B - if (o1 == 0 && OnSegment(edge1.A, edge2.A, edge1.B)) return true; - - // edge1.A, edge1.B and edge2.B are collinear and edge2.B lies on segment edge1.Aedge1.B - if (o2 == 0 && OnSegment(edge1.A, edge2.B, edge1.B)) return true; - - // edge2.A, edge2.B and edge1.A are collinear and edge1.A lies on segment edge2.Aedge2.B - if (o3 == 0 && OnSegment(edge2.A, edge1.A, edge2.B)) return true; - - // edge2.A, edge2.B and edge1.B are collinear and edge1.B lies on segment edge2.Aedge2.B - if (o4 == 0 && OnSegment(edge2.A, edge1.B, edge2.B)) return true; - - return false; // Doesn't fall in any of the above cases - } } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 61646fb..4303d8f 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -51,71 +51,6 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) collider.RecalculateVertices(); - for (int colliderIX = 0; colliderIX < colliders.Count; colliderIX++) - { - ICollider2D colliderX = colliders[colliderIX]; - for (int colliderIY = colliderIX + 1; colliderIY < colliders.Count; colliderIY++) - for (int verticesIndex = 0; verticesIndex < colliderX.Vertices.Count; verticesIndex++) - { - ICollider2D colliderY = colliders[colliderIY]; - bool v = colliderY.CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var _); - if (!colliderY.CheckCollision(colliderX.Vertices[verticesIndex], colliderX, out var collisionInformation)) - continue; - - if (colliderX.BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidX)) - { - Vector2 xVertex = colliderX.Vertices[verticesIndex]; - Vector2 edgeDirection = new Vector2(collisionInformation.Normal.Y, collisionInformation.Normal.X); - Vector2 p1 = xVertex - rigidX.Velocity * intervalDeltaTime; - float t = IntersectionParameterT(collisionInformation.ContactPosition - edgeDirection * 100f, collisionInformation.ContactPosition + edgeDirection * 100f, xVertex, p1); - Vector2 vertexNewPosition = Vector2.Lerp(xVertex, p1, t); - rigidX.Velocity = Vector2.Reflect(rigidX.Velocity, collisionInformation.Normal); - rigidX.Transform.Position -= xVertex - vertexNewPosition; - - // { - // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - // displayableSpriteBehaviour.Assign(Game1.spriteBox); - // gameObject.Transform.Position = collisionInformation.ContactPosition; - // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; - // gameObject.Transform.Rotation = (float)Math.Atan2(collisionInformation.Normal.Y, collisionInformation.Normal.X); - // } - // { - // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - // displayableSpriteBehaviour.Color = Color.Aqua; - // displayableSpriteBehaviour.Assign(Game1.spriteBox); - // gameObject.Transform.Position = collisionInformation.ContactPosition; - // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; - // gameObject.Transform.Rotation = (float)Math.Atan2(rigidX.Velocity.Y, rigidX.Velocity.X); - // } - // { - // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - // displayableSpriteBehaviour.Color = Color.Pink; - // displayableSpriteBehaviour.Assign(Game1.spriteBox); - // gameObject.Transform.Position = collisionInformation.ContactPosition; - // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; - // gameObject.Transform.Rotation = (float)Math.Atan2(edgeDirection.Y, edgeDirection.X); - // } - // { - // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - // DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - // displayableSpriteBehaviour.Color = Color.DarkGoldenrod; - // displayableSpriteBehaviour.Assign(Game1.spriteBox); - // gameObject.Transform.Position = collisionInformation.ContactPosition; - // gameObject.Transform.Scale = new Vector2(1f, .01f) * 100f; - // gameObject.Transform.Rotation = (float)Math.Atan2((xVertex - p1).Y, (xVertex - p1).X); - // } - - StepRigidBody(rigidX, intervalDeltaTime * (1f - t)); - colliders[colliderIX].RecalculateVertices(); - verticesIndex--; - } - Console.WriteLine($"/////////////////////////////////////////////"); - // Console.WriteLine($"Collision"); - } - } } } @@ -127,15 +62,6 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidBody.Transform.Position = nextPosition; } - private float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) - { - // Solve the linear interpolation equation for 't' - float t = ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / - ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); - - return t; - } - private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) { if (behaviour is not ICollider2D collider2D) diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs new file mode 100644 index 0000000..9986d33 --- /dev/null +++ b/Game/Physics2D/PhysicsMath.cs @@ -0,0 +1,210 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D; + +public record Line(Vector2 From, Vector2 To); +public record Triangle(Vector2 A, Vector2 B, Vector2 C); +public record Circle(Vector2 Center, double Radius); + +public static class PhysicsMath +{ + public static float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) + => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / + ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); + + public static float IntersectionParameterT(Line l1, Line l2) + => ((l2.From.X - l1.From.X) * (l1.To.Y - l1.From.Y) - (l2.From.Y - l1.From.Y) * (l1.To.X - l1.From.X)) / + ((l2.To.Y - l2.From.Y) * (l1.To.X - l1.From.X) - (l2.To.X - l2.From.X) * (l1.To.Y - l1.From.Y)); + + public static Vector2 GetIntersectionPoint(Line l1, Line l2) + => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); + + public static Vector2 ClosestPointOnLine(Vector2 point, Line line) + { + // Convert edge points to vectors + var edgeVector = new Vector2(line.To.X - line.From.X, line.To.Y - line.From.Y); + var pointVector = new Vector2(point.X - line.From.X, point.Y - line.From.Y); + + // Calculate the projection of pointVector onto edgeVector + double t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); + + // Clamp t to the range [0, 1] to ensure the closest point is on the edge + t = Math.Max(0, Math.Min(1, t)); + + // Calculate the closest point on the edge + double closestX = line.From.X + t * edgeVector.X; + double closestY = line.From.Y + t * edgeVector.Y; + + return new Vector2((float)closestX, (float)closestY); + } + + public static double GetArea(Triangle triangle) + { + return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + + triangle.B.X * (triangle.C.Y - triangle.A.Y) + + triangle.C.X * (triangle.A.Y - triangle.B.Y)) * .5f); + } + + public static bool IsInTriangle(Vector2 point, Triangle triangle) + { + double A = GetArea(triangle); + /* Calculate area of triangle ABC */ + // double A = area(x1, y1, x2, y2, x3, y3); + + double A1 = GetArea(new Triangle(point, triangle.B, triangle.C)); + /* Calculate area of triangle PBC */ + // double A1 = area(x, y, x2, y2, x3, y3); + + /* Calculate area of triangle PAC */ + double A2 = GetArea(new Triangle(triangle.A, point, triangle.C)); + // double A2 = area(x1, y1, x, y, x3, y3); + + /* Calculate area of triangle PAB */ + double A3 = GetArea(new Triangle(triangle.A, triangle.B, point)); + // double A3 = area(x1, y1, x2, y2, x, y); + + /* Check if sum of A1, A2 and A3 is same as A */ + return A >= A1 + A2 + A3; + } + + // Given three collinear points p, q, r, the function checks if + // point q lies on line segment 'pr' + public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r) + { + if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && + q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) + return true; + + return false; + } + + // To find orientation of ordered triplet (p, q, r). + // The function returns following values + // 0 --> p, q and r are collinear + // 1 --> Clockwise + // 2 --> Counterclockwise + public static int Orientation(Vector2 p, Vector2 q, Vector2 r) + { + // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ + // for details of below formula. + double val = (q.Y - p.Y) * (r.X - q.X) - + (q.X - p.X) * (r.Y - q.Y); + + if (val == 0) return 0; // collinear + + return (val > 0) ? 1 : 2; // clock or counterclock wise + } + + public static bool DoIntersect(Line l1, Line l2) + { + int o1 = Orientation(l1.From, l1.To, l2.From); + int o2 = Orientation(l1.From, l1.To, l2.To); + int o3 = Orientation(l2.From, l2.To, l1.From); + int o4 = Orientation(l2.From, l2.To, l1.To); + + if (o1 != o2 && o3 != o4) + return true; + + if (o1 == 0 && OnSegment(l1.From, l2.From, l1.To)) return true; + if (o2 == 0 && OnSegment(l1.From, l2.To, l1.To)) return true; + if (o3 == 0 && OnSegment(l2.From, l1.From, l2.To)) return true; + if (o4 == 0 && OnSegment(l2.From, l1.To, l2.To)) return true; + + return false; + } + + public static bool DoIntersect(Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) + { + point = null; + + bool result = DoIntersect(l1, l2); + + if (result) + point = GetIntersectionPoint(l1, l2); + + return result; + } + + public static Circle GetCircumCircle(Triangle triangle) + { + Vector2 midAB = (triangle.A + triangle.B) / 2; + Vector2 midBC = (triangle.B + triangle.C) / 2; + + double slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); + double slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); + + Vector2 center; + if (Math.Abs(slopeAB - slopeBC) > double.Epsilon) + { + double x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); + double y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; + center = new Vector2((float)x, (float)y); + } + else + center = (midAB + midBC) * .5f; + + return new(center, Vector2.Distance(center, triangle.A)); + } + + public static Triangle GetSuperTriangle(IList vertices) + { + double minX = double.MaxValue, minY = double.MaxValue; + double maxX = double.MinValue, maxY = double.MinValue; + + foreach (Vector2 point in vertices) + { + minX = Math.Min(minX, point.X); + minY = Math.Min(minY, point.Y); + maxX = Math.Max(maxX, point.X); + maxY = Math.Max(maxY, point.Y); + } + + double dx = maxX - minX; + double dy = maxY - minY; + double deltaMax = Math.Max(dx, dy); + double midX = (minX + maxX) / 2; + double midY = (minY + maxY) / 2; + + Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); + Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); + + return new Triangle(p1, p2, p3); + } + + public static List GetLines(IList vertices) + { + List lines = new List(vertices.Count - 1); + GetLines(vertices, lines); + return lines; + } + + public static void GetLines(IList vertices, IList lines) + { + lines.Clear(); + for (int i = 0; i < vertices.Count - 1; i++) + lines.Add(new(vertices[i], vertices[i + 1])); + lines.Add(new(vertices[^1], vertices[0])); + } + + public static bool DoesLineExistInVertices(Line lineToCheck, List vertices) + { + for (int i = 0; i < vertices.Count - 1; i++) + { + Vector2 vertexCurrent = vertices[i]; + Vector2 vertexNext = vertices[i]; + if (lineToCheck.From == vertexCurrent && lineToCheck.To == vertexNext) return true; + if (lineToCheck.From == vertexNext && lineToCheck.To == vertexCurrent) return true; + } + + Vector2 vertexFirst = vertices[0]; + Vector2 vertexLast = vertices[^1]; + if (lineToCheck.From == vertexFirst && lineToCheck.To == vertexLast) return true; + if (lineToCheck.From == vertexLast && lineToCheck.To == vertexFirst) return true; + return false; + } +} From a417d2d7536197872f6d5bb065843ff0d1c7c5f8 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 17:10:03 +0300 Subject: [PATCH 13/81] Removed Old Collider --- Game/Game1.cs | 11 +- Game/Physics2D/Collider2DBehaviour.cs | 185 -------------------------- 2 files changed, 3 insertions(+), 193 deletions(-) delete mode 100644 Game/Physics2D/Collider2DBehaviour.cs diff --git a/Game/Game1.cs b/Game/Game1.cs index f28e575..ab4b321 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -1,8 +1,11 @@ using System; + using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; + using Pong.Behaviours; + using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; @@ -61,7 +64,6 @@ public class Game1 : Game gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(1, 1) * 5f, new Vector2(-1, 1) * 5f, new Vector2(1, -1) * 5f, new Vector2(-1, -1) * 5f]).OffsetScale = Vector2.One * 51.2f; gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); @@ -72,7 +74,6 @@ public class Game1 : Game gameObjectLeft.BehaviourController.AddBehaviour(); gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - gameObjectLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); IGameObject gameObjectRight = gameManager.InstantiateGameObject(); @@ -82,7 +83,6 @@ public class Game1 : Game gameObjectRight.BehaviourController.AddBehaviour(); gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); - gameObjectRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); @@ -90,33 +90,28 @@ public class Game1 : Game goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaTop.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaBottom.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaRight.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaLeft.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); // goPlayAreaCenter.Transform.Position = new Vector2(100f, 100f); // goPlayAreaCenter.Transform.Scale = new Vector2(40f, 40f); // // goPlayAreaCenter.BehaviourController.AddBehaviour().Assign(spriteBox); - // goPlayAreaCenter.BehaviourController.AddBehaviour((System.Collections.Generic.IList)[new Vector2(.5f, .5f), new Vector2(-.5f, .5f), new Vector2(.5f, -.5f), new Vector2(-.5f, -.5f)]); // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour()); // TODO: use this.Content to load your game content here } diff --git a/Game/Physics2D/Collider2DBehaviour.cs b/Game/Physics2D/Collider2DBehaviour.cs deleted file mode 100644 index 33a2c91..0000000 --- a/Game/Physics2D/Collider2DBehaviour.cs +++ /dev/null @@ -1,185 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Diagnostics.CodeAnalysis; - -using Microsoft.Xna.Framework; - -using Pong; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Graphics.TwoDimensional; -using Syntriax.Engine.Physics2D.Abstract; - -namespace Syntriax.Engine.Physics2D; - - -public class Collider2DBehaviour(IList vertices) : BehaviourOverride, ICollider2D -{ - private List triangles = new List(32); - private readonly List _vertices = new List(32); - private IRigidBody2D? _rigidBody2D = null; - - public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } - public Action? OnCollision { get; set; } = null; - - - private IList verticesOriginal { get; } = vertices; - - public Vector2 OffsetPosition { get; set; } = Vector2.Zero; - public Vector2 OffsetScale { get; set; } = Vector2.One; - public float OffsetRotation { get; set; } = 0f; - - ITransform IAssignableTransform.Transform => Transform; - public IReadOnlyList Vertices => _vertices; - - public IRigidBody2D? RigidBody2D - { - get - { - if (_rigidBody2D is null) - BehaviourController.TryGetBehaviour(out _rigidBody2D); - - return _rigidBody2D; - } - } - - public bool Assign(ITransform transform) => GameObject.Assign(transform); - - public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation collisionInformation) - { - collisionInformation = new CollisionInformation(Vector2.Zero, Vector2.Zero); - - foreach (var triangle in triangles) - { - if (!PhysicsMath.IsInTriangle(point, triangle)) - continue; - - OnCollision?.Invoke(this, otherCollider); - - Line main = new(otherCollider.Transform.Position, point); - - foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) - { - if (!PhysicsMath.DoIntersect(main, line)) - continue; - - Vector2 contactPoint = PhysicsMath.ClosestPointOnLine(point, line); - - Vector2 normal = contactPoint - point; - if (normal.LengthSquared() < 0.001f) - normal = new Vector2(0f, 1f); - - normal.Normalize(); - - collisionInformation = new CollisionInformation(normal, contactPoint); - break; - } - return true; - } - - return false; - } - - public void RecalculateVertices() - { - triangles.Clear(); - - _vertices.Clear(); - foreach (var vertex in verticesOriginal) - { - Vector2 scaledPosition = new Vector2(vertex.X * Transform.Scale.X * OffsetScale.X, vertex.Y * Transform.Scale.Y * OffsetScale.Y); - _vertices.Add(scaledPosition + Transform.Position); - } - - Triangle superTriangle = PhysicsMath.GetSuperTriangle(_vertices); - triangles.Add(superTriangle); - - List badTriangles = new(32); - List polygon = new(32); - - foreach (var vertex in _vertices) - { - badTriangles.Clear(); - polygon.Clear(); - - foreach (var triangle in triangles) - { - Circle circle = PhysicsMath.GetCircumCircle(triangle); - if (Vector2.DistanceSquared(circle.Center, vertex) <= circle.Radius * circle.Radius) - badTriangles.Add(triangle); - } - - foreach (var triangle in badTriangles) - foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) - if (PhysicsMath.DoesLineExistInVertices(line, [triangle.A, triangle.B, triangle.C])) - polygon.Add(line); - - foreach (var triangle in badTriangles) - triangles.Remove(triangle); - - foreach (var line in polygon) - triangles.Add(new(line.From, line.To, vertex)); - } - - for (int i = triangles.Count - 1; i >= 0; i--) - { - Triangle triangle = triangles[i]; - if ( - triangle.A == superTriangle.A || triangle.A == superTriangle.B || triangle.A == superTriangle.C || - triangle.B == superTriangle.A || triangle.B == superTriangle.B || triangle.B == superTriangle.C || - triangle.C == superTriangle.A || triangle.C == superTriangle.B || triangle.C == superTriangle.C - ) - triangles.RemoveAt(i); - } - - for (int i = gameObjects.Count - 1; i >= 0; i--) - { - IGameObject gameObject = gameObjects[i]; - Game1.gameManager.RemoveGameObject(gameObject); - gameObjects.RemoveAt(i); - } - - - for (int i = 0; i < triangles.Count; i++) - { - Triangle triangle = triangles[i]; - foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C])) - { - GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - displayableSpriteBehaviour.Color = Color.Aqua; - displayableSpriteBehaviour.Origin = new(0.5f, 1f); - displayableSpriteBehaviour.Assign(Game1.spriteBox); - gameObject.Transform.Position = line.From; - Vector2 vector2 = line.To - line.From; - gameObject.Transform.Scale = new Vector2(2f, .0f) + Vector2.UnitY * vector2.Length(); - gameObject.Transform.Rotation = (float)Math.Atan2(vector2.X, vector2.Y); - gameObjects.Add(gameObject); - - gameObject = Game1.gameManager.InstantiateGameObject(); - displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - displayableSpriteBehaviour.Color = Color.Crimson; - displayableSpriteBehaviour.Assign(Game1.spriteBox); - gameObject.Transform.Position = line.To; - gameObject.Transform.Scale = new Vector2(4f, 4f); - gameObjects.Add(gameObject); - } - } - - foreach (var vertex in Vertices) - { - GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour(); - displayableSpriteBehaviour.Color = Color.GreenYellow; - displayableSpriteBehaviour.Assign(Game1.spriteBox); - gameObject.Transform.Position = vertex; - gameObject.Transform.Scale = new Vector2(2f, 2f); - gameObjects.Add(gameObject); - } - } - - private List gameObjects = new List(32); - -} From a05fb3ba33c03ef665c7d21e437679ef66e4f816 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 17:39:38 +0300 Subject: [PATCH 14/81] rgrae --- Game/Physics2D/Abstract/ICollider2D.cs | 14 ++----- Game/Physics2D/Collider2DAABBBehaviour.cs | 49 +++++++++++++++++++++++ Game/Physics2D/PhysicsEngine2D.cs | 5 ++- 3 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 Game/Physics2D/Collider2DAABBBehaviour.cs diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index 131cac3..6edb610 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; + using Microsoft.Xna.Framework; using Syntriax.Engine.Core.Abstract; @@ -11,15 +12,8 @@ public interface ICollider2D : IBehaviour, IAssignableTransform { IRigidBody2D? RigidBody2D { get; } - Action? OnCollision { get; set; } + Action? OnCollisionPreResolve { get; set; } - Vector2 OffsetPosition { get; set; } - Vector2 OffsetScale { get; set; } - float OffsetRotation { get; set; } - IReadOnlyList Vertices { get; } - - - bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation? collisionInformation); - - void RecalculateVertices(); + bool CheckCollision(Vector2 point, ICollider2D otherCollider); + void Recalculate(); } diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs new file mode 100644 index 0000000..cfabc2a --- /dev/null +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -0,0 +1,49 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : BehaviourOverride, ICollider2D +{ + public Vector2 LowerBound { get; } = lowerBound; + public Vector2 UpperBound { get; } = upperBound; + + private IRigidBody2D? _rigidBody2D = null; + + public IRigidBody2D? RigidBody2D + { + get + { + if (_rigidBody2D is null) + BehaviourController.TryGetBehaviour(out _rigidBody2D); + + return _rigidBody2D; + } + } + + public Action? OnCollisionPreResolve { get; set; } = null; + + public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } + ITransform IAssignableTransform.Transform => Transform; + public bool Assign(ITransform transform) => GameObject.Assign(transform); + + public bool CheckCollision(Vector2 point, ICollider2D otherCollider) + { + if (point.X >= LowerBound.X + Transform.Position.X && point.X <= UpperBound.X + Transform.Position.X && + point.Y >= LowerBound.Y + Transform.Position.Y && point.Y <= UpperBound.Y + Transform.Position.Y) + return true; + + return false; + } + + public void Recalculate() + { + throw new NotImplementedException(); + } +} diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 4303d8f..c0a4ad7 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; + using Microsoft.Xna.Framework; + using Pong; + using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; @@ -49,7 +52,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) - collider.RecalculateVertices(); + collider.Recalculate(); } } From 8a2e15e6f0c5db4c9b7f1987b31661bab39f6660 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 5 Dec 2023 17:55:38 +0300 Subject: [PATCH 15/81] asdasda --- Game/Physics2D/Collider2DAABBBehaviour.cs | 12 +++++++++--- Game/Physics2D/PhysicsEngine2D.cs | 11 ++++++++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index cfabc2a..bd1f73c 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -14,6 +14,11 @@ public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : B public Vector2 LowerBound { get; } = lowerBound; public Vector2 UpperBound { get; } = upperBound; + + private Vector2 worldLowerBound = lowerBound; + private Vector2 worldUpperBound = upperBound; + + private IRigidBody2D? _rigidBody2D = null; public IRigidBody2D? RigidBody2D @@ -35,8 +40,8 @@ public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : B public bool CheckCollision(Vector2 point, ICollider2D otherCollider) { - if (point.X >= LowerBound.X + Transform.Position.X && point.X <= UpperBound.X + Transform.Position.X && - point.Y >= LowerBound.Y + Transform.Position.Y && point.Y <= UpperBound.Y + Transform.Position.Y) + if (point.X >= worldLowerBound.X && point.X <= worldUpperBound.X && + point.Y >= worldLowerBound.Y && point.Y <= worldUpperBound.Y) return true; return false; @@ -44,6 +49,7 @@ public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : B public void Recalculate() { - throw new NotImplementedException(); + worldLowerBound = LowerBound + Transform.Position; + worldUpperBound = UpperBound + Transform.Position; } } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index c0a4ad7..59b1d93 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -45,7 +45,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D { float intervalDeltaTime = deltaTime / IterationCount; - for (int i = 0; i < IterationCount; i++) + for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++) { foreach (var rigidBody in rigidBodies) StepRigidBody(rigidBody, intervalDeltaTime); @@ -54,6 +54,15 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) collider.Recalculate(); + for (int ix = colliders.Count - 1; ix >= 0; ix--) + { + ICollider2D colliderX = colliders[ix]; + for (int iy = colliders.Count - 1; iy >= ix + 1; iy--) + { + ICollider2D colliderY = colliders[iy]; + + } + } } } From 21b7a0b2f61cdf579ba9189dc8514243c8ebf9a4 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 11:24:49 +0300 Subject: [PATCH 16/81] Updated Physics Methods --- Game/Physics2D/PhysicsMath.cs | 51 ++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 9986d33..54cf2cc 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -7,6 +7,7 @@ using Microsoft.Xna.Framework; namespace Syntriax.Engine.Physics2D; public record Line(Vector2 From, Vector2 To); +public record LineEquation(float Slope, float OffsetY); public record Triangle(Vector2 A, Vector2 B, Vector2 C); public record Circle(Vector2 Center, double Radius); @@ -16,14 +17,14 @@ public static class PhysicsMath => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); - public static float IntersectionParameterT(Line l1, Line l2) + public static float IntersectionParameterT(this Line l1, Line l2) => ((l2.From.X - l1.From.X) * (l1.To.Y - l1.From.Y) - (l2.From.Y - l1.From.Y) * (l1.To.X - l1.From.X)) / ((l2.To.Y - l2.From.Y) * (l1.To.X - l1.From.X) - (l2.To.X - l2.From.X) * (l1.To.Y - l1.From.Y)); - public static Vector2 GetIntersectionPoint(Line l1, Line l2) + public static Vector2 IntersectionPoint(this Line l1, Line l2) => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); - public static Vector2 ClosestPointOnLine(Vector2 point, Line line) + public static Vector2 ClosestPointTo(this Line line, Vector2 point) { // Convert edge points to vectors var edgeVector = new Vector2(line.To.X - line.From.X, line.To.Y - line.From.Y); @@ -42,14 +43,14 @@ public static class PhysicsMath return new Vector2((float)closestX, (float)closestY); } - public static double GetArea(Triangle triangle) + public static double GetArea(this Triangle triangle) { return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + triangle.B.X * (triangle.C.Y - triangle.A.Y) + triangle.C.X * (triangle.A.Y - triangle.B.Y)) * .5f); } - public static bool IsInTriangle(Vector2 point, Triangle triangle) + public static bool IsPointInside(this Triangle triangle, Vector2 point) { double A = GetArea(triangle); /* Calculate area of triangle ABC */ @@ -99,7 +100,7 @@ public static class PhysicsMath return (val > 0) ? 1 : 2; // clock or counterclock wise } - public static bool DoIntersect(Line l1, Line l2) + public static bool Intersects(this Line l1, Line l2) { int o1 = Orientation(l1.From, l1.To, l2.From); int o2 = Orientation(l1.From, l1.To, l2.To); @@ -117,19 +118,19 @@ public static class PhysicsMath return false; } - public static bool DoIntersect(Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) + public static bool Intersects(this Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) { point = null; - bool result = DoIntersect(l1, l2); + bool result = Intersects(l1, l2); if (result) - point = GetIntersectionPoint(l1, l2); + point = IntersectionPoint(l1, l2); return result; } - public static Circle GetCircumCircle(Triangle triangle) + public static Circle ToCircumCircle(this Triangle triangle) { Vector2 midAB = (triangle.A + triangle.B) / 2; Vector2 midBC = (triangle.B + triangle.C) / 2; @@ -150,7 +151,7 @@ public static class PhysicsMath return new(center, Vector2.Distance(center, triangle.A)); } - public static Triangle GetSuperTriangle(IList vertices) + public static Triangle ToSuperTriangle(IList vertices) { double minX = double.MaxValue, minY = double.MaxValue; double maxX = double.MinValue, maxY = double.MinValue; @@ -176,14 +177,14 @@ public static class PhysicsMath return new Triangle(p1, p2, p3); } - public static List GetLines(IList vertices) + public static List ToLines(IList vertices) { List lines = new List(vertices.Count - 1); - GetLines(vertices, lines); + ToLines(vertices, lines); return lines; } - public static void GetLines(IList vertices, IList lines) + public static void ToLines(IList vertices, IList lines) { lines.Clear(); for (int i = 0; i < vertices.Count - 1; i++) @@ -191,7 +192,7 @@ public static class PhysicsMath lines.Add(new(vertices[^1], vertices[0])); } - public static bool DoesLineExistInVertices(Line lineToCheck, List vertices) + public static bool ExistIn(Line lineToCheck, List vertices) { for (int i = 0; i < vertices.Count - 1; i++) { @@ -207,4 +208,24 @@ public static class PhysicsMath if (lineToCheck.From == vertexLast && lineToCheck.To == vertexFirst) return true; return false; } + + public static bool LaysOn(this Vector2 point, Line line) + { + LineEquation lineEquation = line.ToLineEquation(); + + // y = mx + b + float y = lineEquation.Slope * point.X + lineEquation.OffsetY; + + return y == point.Y; + } + + public static LineEquation ToLineEquation(this Line line) + { + Vector2 slopeVector = line.To - line.From; + float slope = slopeVector.Y / slopeVector.X; + + float yOffset = line.From.Y - (slope * line.From.X); + + return new LineEquation(slope, yOffset); + } } From fa7d92ce88c726c3ff35341f09e6c71cdbc5adb9 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 13:25:16 +0300 Subject: [PATCH 17/81] sdaSDA --- Game/Game1.cs | 4 + Game/Physics2D/Abstract/ICollider2D.cs | 9 +- Game/Physics2D/Collider2DAABBBehaviour.cs | 47 +++-- Game/Physics2D/PhysicsEngine2D.cs | 33 ++-- Game/Physics2D/PhysicsMath.cs | 223 +++++++++++----------- 5 files changed, 177 insertions(+), 139 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index ab4b321..dab7b50 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -90,22 +90,26 @@ public class Game1 : Game goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index 6edb610..1152632 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework; @@ -10,10 +9,12 @@ namespace Syntriax.Engine.Physics2D.Abstract; public interface ICollider2D : IBehaviour, IAssignableTransform { - IRigidBody2D? RigidBody2D { get; } - Action? OnCollisionPreResolve { get; set; } - bool CheckCollision(Vector2 point, ICollider2D otherCollider); + IRigidBody2D? RigidBody2D { get; } + + IReadOnlyList Vertices { get; } + + bool CheckCollision(Vector2 point); void Recalculate(); } diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index bd1f73c..c432ba8 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -9,17 +9,14 @@ using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; -public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : BehaviourOverride, ICollider2D +public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D { - public Vector2 LowerBound { get; } = lowerBound; - public Vector2 UpperBound { get; } = upperBound; - - - private Vector2 worldLowerBound = lowerBound; - private Vector2 worldUpperBound = upperBound; - + public AABB AABBLocal { get; set; } = null!; + public AABB AABBWorld { get; private set; } = null!; private IRigidBody2D? _rigidBody2D = null; + private List vertices = new List(4); + private IReadOnlyList? _verticesReadOnly = null; public IRigidBody2D? RigidBody2D { @@ -38,18 +35,36 @@ public class Collider2DAABBBehaviour(Vector2 lowerBound, Vector2 upperBound) : B ITransform IAssignableTransform.Transform => Transform; public bool Assign(ITransform transform) => GameObject.Assign(transform); - public bool CheckCollision(Vector2 point, ICollider2D otherCollider) - { - if (point.X >= worldLowerBound.X && point.X <= worldUpperBound.X && - point.Y >= worldLowerBound.Y && point.Y <= worldUpperBound.Y) - return true; + public IReadOnlyList Vertices { get { if (_verticesReadOnly is null) _verticesReadOnly = vertices.AsReadOnly(); return _verticesReadOnly; } } - return false; + public bool CheckCollision(Vector2 point) + { + return AABBWorld.Inside(point); } public void Recalculate() { - worldLowerBound = LowerBound + Transform.Position; - worldUpperBound = UpperBound + Transform.Position; + AABBWorld = new AABB( + AABBLocal.LowerBoundary + Transform.Position, + AABBLocal.UpperBoundary + Transform.Position + ); + + vertices.Clear(); + vertices.Add(AABBWorld.LowerBoundary); + vertices.Add(new(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); + vertices.Add(AABBWorld.UpperBoundary); + vertices.Add(new(AABBWorld.LowerBoundary.Y, AABBWorld.UpperBoundary.X)); + } + + public Collider2DAABBBehaviour(Vector2 lowerBoundary, Vector2 upperBoundary) + { + AABBLocal = new AABB(lowerBoundary, upperBoundary); + AABBWorld = new AABB(lowerBoundary, upperBoundary); + } + + public Collider2DAABBBehaviour() + { + AABBLocal = new(Vector2.Zero, Vector2.Zero); + AABBWorld = new(Vector2.Zero, Vector2.Zero); } } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 59b1d93..ddcb322 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -14,8 +14,8 @@ namespace Syntriax.Engine.Physics2D; public class PhysicsEngine2D : IPhysicsEngine2D { - private IList rigidBodies = new List(32); - private IList colliders = new List(64); + private List rigidBodies = new List(32); + private List colliders = new List(64); private int _iterationCount = 1; @@ -54,19 +54,30 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) collider.Recalculate(); - for (int ix = colliders.Count - 1; ix >= 0; ix--) - { - ICollider2D colliderX = colliders[ix]; - for (int iy = colliders.Count - 1; iy >= ix + 1; iy--) + for (int i = colliders.Count - 1; i >= 0; i--) + CheckCollisions(colliders[i], colliders, (c1, c2) => { - ICollider2D colliderY = colliders[iy]; - - } - } + if (c1.RigidBody2D is IRigidBody2D c1RigidBody) c1RigidBody.Velocity = -c1RigidBody.Velocity; + if (c2.RigidBody2D is IRigidBody2D c2RigidBody) c2RigidBody.Velocity = -c2RigidBody.Velocity; + }); } } - private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) + private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) + { + for (int i = collider2Ds.Count - 1; i >= 0; i--) + { + ICollider2D collider2DItem = collider2Ds[i]; + if (collider2DItem == collider2D) + continue; + + foreach (var vertex in collider2DItem.Vertices) + if (collider2D.CheckCollision(vertex)) + OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem); + } + } + + private void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) { Vector2 nextPosition = rigidBody.Transform.Position; nextPosition += rigidBody.Velocity * intervalDeltaTime; diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 54cf2cc..3f645f3 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -9,21 +9,11 @@ namespace Syntriax.Engine.Physics2D; public record Line(Vector2 From, Vector2 To); public record LineEquation(float Slope, float OffsetY); public record Triangle(Vector2 A, Vector2 B, Vector2 C); -public record Circle(Vector2 Center, double Radius); +public record Circle(Vector2 Position, float Radius); +public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary); public static class PhysicsMath { - public static float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) - => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / - ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); - - public static float IntersectionParameterT(this Line l1, Line l2) - => ((l2.From.X - l1.From.X) * (l1.To.Y - l1.From.Y) - (l2.From.Y - l1.From.Y) * (l1.To.X - l1.From.X)) / - ((l2.To.Y - l2.From.Y) * (l1.To.X - l1.From.X) - (l2.To.X - l2.From.X) * (l1.To.Y - l1.From.Y)); - - public static Vector2 IntersectionPoint(this Line l1, Line l2) - => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); - public static Vector2 ClosestPointTo(this Line line, Vector2 point) { // Convert edge points to vectors @@ -31,118 +21,38 @@ public static class PhysicsMath var pointVector = new Vector2(point.X - line.From.X, point.Y - line.From.Y); // Calculate the projection of pointVector onto edgeVector - double t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); + float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); // Clamp t to the range [0, 1] to ensure the closest point is on the edge t = Math.Max(0, Math.Min(1, t)); // Calculate the closest point on the edge - double closestX = line.From.X + t * edgeVector.X; - double closestY = line.From.Y + t * edgeVector.Y; + float closestX = line.From.X + t * edgeVector.X; + float closestY = line.From.Y + t * edgeVector.Y; return new Vector2((float)closestX, (float)closestY); } - public static double GetArea(this Triangle triangle) + public static float GetArea(this Triangle triangle) { return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + triangle.B.X * (triangle.C.Y - triangle.A.Y) + triangle.C.X * (triangle.A.Y - triangle.B.Y)) * .5f); } - public static bool IsPointInside(this Triangle triangle, Vector2 point) - { - double A = GetArea(triangle); - /* Calculate area of triangle ABC */ - // double A = area(x1, y1, x2, y2, x3, y3); - - double A1 = GetArea(new Triangle(point, triangle.B, triangle.C)); - /* Calculate area of triangle PBC */ - // double A1 = area(x, y, x2, y2, x3, y3); - - /* Calculate area of triangle PAC */ - double A2 = GetArea(new Triangle(triangle.A, point, triangle.C)); - // double A2 = area(x1, y1, x, y, x3, y3); - - /* Calculate area of triangle PAB */ - double A3 = GetArea(new Triangle(triangle.A, triangle.B, point)); - // double A3 = area(x1, y1, x2, y2, x, y); - - /* Check if sum of A1, A2 and A3 is same as A */ - return A >= A1 + A2 + A3; - } - - // Given three collinear points p, q, r, the function checks if - // point q lies on line segment 'pr' - public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r) - { - if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && - q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) - return true; - - return false; - } - - // To find orientation of ordered triplet (p, q, r). - // The function returns following values - // 0 --> p, q and r are collinear - // 1 --> Clockwise - // 2 --> Counterclockwise - public static int Orientation(Vector2 p, Vector2 q, Vector2 r) - { - // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ - // for details of below formula. - double val = (q.Y - p.Y) * (r.X - q.X) - - (q.X - p.X) * (r.Y - q.Y); - - if (val == 0) return 0; // collinear - - return (val > 0) ? 1 : 2; // clock or counterclock wise - } - - public static bool Intersects(this Line l1, Line l2) - { - int o1 = Orientation(l1.From, l1.To, l2.From); - int o2 = Orientation(l1.From, l1.To, l2.To); - int o3 = Orientation(l2.From, l2.To, l1.From); - int o4 = Orientation(l2.From, l2.To, l1.To); - - if (o1 != o2 && o3 != o4) - return true; - - if (o1 == 0 && OnSegment(l1.From, l2.From, l1.To)) return true; - if (o2 == 0 && OnSegment(l1.From, l2.To, l1.To)) return true; - if (o3 == 0 && OnSegment(l2.From, l1.From, l2.To)) return true; - if (o4 == 0 && OnSegment(l2.From, l1.To, l2.To)) return true; - - return false; - } - - public static bool Intersects(this Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) - { - point = null; - - bool result = Intersects(l1, l2); - - if (result) - point = IntersectionPoint(l1, l2); - - return result; - } - public static Circle ToCircumCircle(this Triangle triangle) { Vector2 midAB = (triangle.A + triangle.B) / 2; Vector2 midBC = (triangle.B + triangle.C) / 2; - double slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); - double slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); + float slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); + float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); Vector2 center; - if (Math.Abs(slopeAB - slopeBC) > double.Epsilon) + if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) { - double x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); - double y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; + float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); + float y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; center = new Vector2((float)x, (float)y); } else @@ -153,8 +63,8 @@ public static class PhysicsMath public static Triangle ToSuperTriangle(IList vertices) { - double minX = double.MaxValue, minY = double.MaxValue; - double maxX = double.MinValue, maxY = double.MinValue; + float minX = float.MaxValue, minY = float.MaxValue; + float maxX = float.MinValue, maxY = float.MinValue; foreach (Vector2 point in vertices) { @@ -164,11 +74,11 @@ public static class PhysicsMath maxY = Math.Max(maxY, point.Y); } - double dx = maxX - minX; - double dy = maxY - minY; - double deltaMax = Math.Max(dx, dy); - double midX = (minX + maxX) / 2; - double midY = (minY + maxY) / 2; + float dx = maxX - minX; + float dy = maxY - minY; + float deltaMax = Math.Max(dx, dy); + float midX = (minX + maxX) / 2; + float midY = (minY + maxY) / 2; Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); @@ -228,4 +138,101 @@ public static class PhysicsMath return new LineEquation(slope, yOffset); } + + // Given three collinear points p, q, r, the function checks if + // point q lies on line segment 'pr' + public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r) + { + if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && + q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) + return true; + + return false; + } + + // To find orientation of ordered triplet (p, q, r). + // The function returns following values + // 0 --> p, q and r are collinear + // 1 --> Clockwise + // 2 --> Counterclockwise + public static int Orientation(Vector2 p, Vector2 q, Vector2 r) + { + // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ + // for details of below formula. + float val = (q.Y - p.Y) * (r.X - q.X) - + (q.X - p.X) * (r.Y - q.Y); + + if (val == 0) return 0; // collinear + + return (val > 0) ? 1 : 2; // clock or counterclock wise + } + + public static float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) + => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / + ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); + + public static float IntersectionParameterT(this Line l0, Line l1) + => ((l1.From.X - l0.From.X) * (l0.To.Y - l0.From.Y) - (l1.From.Y - l0.From.Y) * (l0.To.X - l0.From.X)) / + ((l1.To.Y - l1.From.Y) * (l0.To.X - l0.From.X) - (l1.To.X - l1.From.X) * (l0.To.Y - l0.From.Y)); + + public static Vector2 IntersectionPoint(this Line l1, Line l2) + => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); + + public static bool Intersects(this Line l1, Line l2) + { + int o1 = Orientation(l1.From, l1.To, l2.From); + int o2 = Orientation(l1.From, l1.To, l2.To); + int o3 = Orientation(l2.From, l2.To, l1.From); + int o4 = Orientation(l2.From, l2.To, l1.To); + + if (o1 != o2 && o3 != o4) + return true; + + if (o1 == 0 && OnSegment(l1.From, l2.From, l1.To)) return true; + if (o2 == 0 && OnSegment(l1.From, l2.To, l1.To)) return true; + if (o3 == 0 && OnSegment(l2.From, l1.From, l2.To)) return true; + if (o4 == 0 && OnSegment(l2.From, l1.To, l2.To)) return true; + + return false; + } + + public static bool Intersects(this Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) + { + point = null; + + bool result = Intersects(l1, l2); + + if (result) + point = IntersectionPoint(l1, l2); + + return result; + } + + public static bool Intersects(this Circle circle, Circle circleOther) + { + float distanceSquared = (circle.Position - circleOther.Position).LengthSquared(); + float radiusSumSquared = circle.Radius * circle.Radius + circleOther.Radius * circleOther.Radius; + + return distanceSquared < radiusSumSquared; + } + + public static bool Inside(this Triangle triangle, Vector2 point) + { + float originalTriangleArea = GetArea(triangle); + + float pointTriangleArea1 = GetArea(new Triangle(point, triangle.B, triangle.C)); + float pointTriangleArea2 = GetArea(new Triangle(triangle.A, point, triangle.C)); + float pointTriangleArea3 = GetArea(new Triangle(triangle.A, triangle.B, point)); + + float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3; + + return originalTriangleArea >= pointTriangleAreasSum; + } + + public static bool Inside(this AABB aabb, Vector2 point) + => point.X >= aabb.LowerBoundary.X && point.X <= aabb.UpperBoundary.X && + point.Y >= aabb.LowerBoundary.Y && point.Y <= aabb.UpperBoundary.Y; + + public static bool Inside(this Circle circle, Vector2 point) + => (circle.Position - point).LengthSquared() <= circle.Radius * circle.Radius; } From 6ceea7d84ee7c63f12268ef2851c28a48f8ffa85 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 13:50:39 +0300 Subject: [PATCH 18/81] rewaer --- Game/Game1.cs | 15 +++++++++------ Game/Physics2D/Collider2DAABBBehaviour.cs | 4 ++-- Game/Physics2D/PhysicsMath.cs | 3 +++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index dab7b50..5242e6a 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -64,8 +64,9 @@ public class Game1 : Game gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), 500f); + gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f, Vector2.One * 512f); IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); gameObjectLeft.Name = "Left"; @@ -74,6 +75,7 @@ public class Game1 : Game gameObjectLeft.BehaviourController.AddBehaviour(); gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); IGameObject gameObjectRight = gameManager.InstantiateGameObject(); @@ -83,6 +85,7 @@ public class Game1 : Game gameObjectRight.BehaviourController.AddBehaviour(); gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); + gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); @@ -90,26 +93,26 @@ public class Game1 : Game goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); + goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); + goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); + goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One, Vector2.One); + goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); @@ -152,7 +155,7 @@ public class Game1 : Game if (Keyboard.GetState().IsKeyDown(Keys.E)) gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; - + Console.WriteLine(gameObjectBall.Transform.Position); // if (Keyboard.GetState().IsKeyDown(Keys.N)) // seconds = 39.12f; // if (Keyboard.GetState().IsKeyDown(Keys.Space)) diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index c432ba8..da7cc45 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -45,8 +45,8 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D public void Recalculate() { AABBWorld = new AABB( - AABBLocal.LowerBoundary + Transform.Position, - AABBLocal.UpperBoundary + Transform.Position + AABBLocal.LowerBoundary.Scale(Transform.Scale) + Transform.Position, + AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position ); vertices.Clear(); diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 3f645f3..273e503 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -14,6 +14,9 @@ public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary); public static class PhysicsMath { + public static Vector2 Scale(this Vector2 original, Vector2 scale) + => new Vector2(original.X * scale.X, original.Y * scale.Y); + public static Vector2 ClosestPointTo(this Line line, Vector2 point) { // Convert edge points to vectors From a7b1c7cb4c37a81ae200e0f476def2cdb01bd958 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 14:14:55 +0300 Subject: [PATCH 19/81] fDSAsdad --- Game/Game1.cs | 2 +- Game/Physics2D/Collider2DAABBBehaviour.cs | 4 ++-- Game/Physics2D/PhysicsEngine2D.cs | 29 ++++++++++++++++------- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 5242e6a..bfcb25d 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -66,7 +66,7 @@ public class Game1 : Game engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f, Vector2.One * 512f); + gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); gameObjectLeft.Name = "Left"; diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index da7cc45..6e917d7 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -51,9 +51,9 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D vertices.Clear(); vertices.Add(AABBWorld.LowerBoundary); - vertices.Add(new(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); + vertices.Add(new Vector2(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); vertices.Add(AABBWorld.UpperBoundary); - vertices.Add(new(AABBWorld.LowerBoundary.Y, AABBWorld.UpperBoundary.X)); + vertices.Add(new Vector2(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); } public Collider2DAABBBehaviour(Vector2 lowerBoundary, Vector2 upperBoundary) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index ddcb322..4caeb41 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -3,11 +3,7 @@ using System.Collections.Generic; using Microsoft.Xna.Framework; -using Pong; - -using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D.Abstract; namespace Syntriax.Engine.Physics2D; @@ -41,6 +37,8 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidBodies.Remove(rigidBody); } + // List gameObjects = new List(); + public void Step(float deltaTime) { float intervalDeltaTime = deltaTime / IterationCount; @@ -54,25 +52,38 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) collider.Recalculate(); + // foreach (var gameObject in gameObjects) + // Game1.gameManager.RemoveGameObject(gameObject); + // gameObjects.Clear(); + + // foreach (var collider in colliders) + // foreach (var vertex in collider.Vertices) + // { + // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); + // gameObject.BehaviourController.AddBehaviour().Assign(Game1.spriteBox); + // gameObject.Transform.Position = vertex; + // gameObjects.Add(gameObject); + // } + for (int i = colliders.Count - 1; i >= 0; i--) CheckCollisions(colliders[i], colliders, (c1, c2) => { - if (c1.RigidBody2D is IRigidBody2D c1RigidBody) c1RigidBody.Velocity = -c1RigidBody.Velocity; - if (c2.RigidBody2D is IRigidBody2D c2RigidBody) c2RigidBody.Velocity = -c2RigidBody.Velocity; + if (c1.RigidBody2D is IRigidBody2D c1RigidBody) { c1RigidBody.Velocity = -c1RigidBody.Velocity; StepRigidBody(c1RigidBody, intervalDeltaTime); c1.Recalculate(); } + if (c2.RigidBody2D is IRigidBody2D c2RigidBody) { c2RigidBody.Velocity = -c2RigidBody.Velocity; StepRigidBody(c2RigidBody, intervalDeltaTime); c2.Recalculate(); } }); } } private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) { - for (int i = collider2Ds.Count - 1; i >= 0; i--) + for (int i = 0; i < collider2Ds.Count; i++) { ICollider2D collider2DItem = collider2Ds[i]; if (collider2DItem == collider2D) continue; - foreach (var vertex in collider2DItem.Vertices) - if (collider2D.CheckCollision(vertex)) + for (int y = 0; y < collider2DItem.Vertices.Count; y++) + if (collider2D.CheckCollision(collider2DItem.Vertices[y])) OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem); } } From 9a92bf8ca652209c8e1868231834d45afaa1bfbb Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 15:56:46 +0300 Subject: [PATCH 20/81] asdfsadfafasfdasf --- Game/Game1.cs | 3 +- Game/Physics2D/Abstract/ICollider2D.cs | 2 +- Game/Physics2D/Collider2DAABBBehaviour.cs | 16 +++--- Game/Physics2D/PhysicsEngine2D.cs | 61 ++++++++++++++++++++--- Game/Physics2D/PhysicsMath.cs | 47 +++++++++++++---- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index bfcb25d..0a07534 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -155,7 +155,6 @@ public class Game1 : Game if (Keyboard.GetState().IsKeyDown(Keys.E)) gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; - Console.WriteLine(gameObjectBall.Transform.Position); // if (Keyboard.GetState().IsKeyDown(Keys.N)) // seconds = 39.12f; // if (Keyboard.GetState().IsKeyDown(Keys.Space)) @@ -174,7 +173,7 @@ public class Game1 : Game while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) { - Console.WriteLine($"Physics Timer: {physicsTimer}"); + // Console.WriteLine($"Physics Timer: {physicsTimer}"); physicsTimer += 0.01f; engine.Step(.01f); } diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index 1152632..64eba9b 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -13,7 +13,7 @@ public interface ICollider2D : IBehaviour, IAssignableTransform IRigidBody2D? RigidBody2D { get; } - IReadOnlyList Vertices { get; } + IList Vertices { get; } bool CheckCollision(Vector2 point); void Recalculate(); diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index 6e917d7..d1b8fce 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -15,8 +15,7 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D public AABB AABBWorld { get; private set; } = null!; private IRigidBody2D? _rigidBody2D = null; - private List vertices = new List(4); - private IReadOnlyList? _verticesReadOnly = null; + private List _vertices = new List(4); public IRigidBody2D? RigidBody2D { @@ -35,7 +34,7 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D ITransform IAssignableTransform.Transform => Transform; public bool Assign(ITransform transform) => GameObject.Assign(transform); - public IReadOnlyList Vertices { get { if (_verticesReadOnly is null) _verticesReadOnly = vertices.AsReadOnly(); return _verticesReadOnly; } } + public IList Vertices => _vertices; public bool CheckCollision(Vector2 point) { @@ -49,13 +48,12 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position ); - vertices.Clear(); - vertices.Add(AABBWorld.LowerBoundary); - vertices.Add(new Vector2(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); - vertices.Add(AABBWorld.UpperBoundary); - vertices.Add(new Vector2(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); + Vertices.Clear(); + Vertices.Add(AABBWorld.LowerBoundary); + Vertices.Add(new Vector2(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); + Vertices.Add(AABBWorld.UpperBoundary); + Vertices.Add(new Vector2(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); } - public Collider2DAABBBehaviour(Vector2 lowerBoundary, Vector2 upperBoundary) { AABBLocal = new AABB(lowerBoundary, upperBoundary); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 4caeb41..7803293 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -38,6 +38,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D } // List gameObjects = new List(); + private List lines = new List(32); public void Step(float deltaTime) { @@ -66,15 +67,55 @@ public class PhysicsEngine2D : IPhysicsEngine2D // } for (int i = colliders.Count - 1; i >= 0; i--) - CheckCollisions(colliders[i], colliders, (c1, c2) => + CheckCollisions(colliders[i], colliders, (c1, c2, v) => { - if (c1.RigidBody2D is IRigidBody2D c1RigidBody) { c1RigidBody.Velocity = -c1RigidBody.Velocity; StepRigidBody(c1RigidBody, intervalDeltaTime); c1.Recalculate(); } - if (c2.RigidBody2D is IRigidBody2D c2RigidBody) { c2RigidBody.Velocity = -c2RigidBody.Velocity; StepRigidBody(c2RigidBody, intervalDeltaTime); c2.Recalculate(); } + NewMethod(c1, c2, v, intervalDeltaTime); + NewMethod(c2, c1, v, intervalDeltaTime); + + // if (c2.RigidBody2D is IRigidBody2D) + // { + // c2.RigidBody2D.Velocity = -c2.RigidBody2D.Velocity; + // StepRigidBody(c2.RigidBody2D, intervalDeltaTime); + // } + + c1.Recalculate(); + c2.Recalculate(); }); } } - private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) + private void NewMethod(ICollider2D c1, ICollider2D c2, Vector2 vertex, float intervalDeltaTime) + { + if (c1.RigidBody2D is not IRigidBody2D) + return; + + Line vertexTrajectory = new Line(vertex, vertex - c1.RigidBody2D.Velocity); + if (vertexTrajectory.LengthSquared <= 0.001f) + return; + + c2.Vertices.ToLines(lines); + + Vector2 normal = Vector2.UnitY; + float t = 0f; + + foreach (var line in lines) + { + if (!vertexTrajectory.Intersects(line, out Vector2? intersectionPoint) || intersectionPoint is not null) + continue; + + t = vertexTrajectory.GetT(vertex); + Vector2 lineDirection = line.Direction; + normal = new(lineDirection.Y, lineDirection.X); + break; + } + + StepRigidBody(c1.RigidBody2D, -t); + + c1.RigidBody2D.Velocity = Vector2.Reflect(c1.RigidBody2D.Velocity, normal); + StepRigidBody(c1.RigidBody2D, intervalDeltaTime - t); + } + + private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) { for (int i = 0; i < collider2Ds.Count; i++) { @@ -82,9 +123,15 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (collider2DItem == collider2D) continue; - for (int y = 0; y < collider2DItem.Vertices.Count; y++) - if (collider2D.CheckCollision(collider2DItem.Vertices[y])) - OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem); + for (int y = 0; y < collider2D.Vertices.Count; y++) + { + Vector2 vertex = collider2D.Vertices[y]; + if (collider2D.CheckCollision(vertex)) + { + OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem, vertex); + y--; // Recheck current vertex + } + } } } diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 273e503..052cdb1 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -6,7 +6,13 @@ using Microsoft.Xna.Framework; namespace Syntriax.Engine.Physics2D; -public record Line(Vector2 From, Vector2 To); +public record Line(Vector2 From, Vector2 To) +{ + public Vector2 Direction => Vector2.Normalize(To - From); + public float Length => (From - To).Length(); + public float LengthSquared => (From - To).LengthSquared(); +} + public record LineEquation(float Slope, float OffsetY); public record Triangle(Vector2 A, Vector2 B, Vector2 C); public record Circle(Vector2 Position, float Radius); @@ -90,14 +96,14 @@ public static class PhysicsMath return new Triangle(p1, p2, p3); } - public static List ToLines(IList vertices) + public static IList ToLines(this IList vertices) { List lines = new List(vertices.Count - 1); ToLines(vertices, lines); return lines; } - public static void ToLines(IList vertices, IList lines) + public static void ToLines(this IList vertices, IList lines) { lines.Clear(); for (int i = 0; i < vertices.Count - 1; i++) @@ -123,14 +129,7 @@ public static class PhysicsMath } public static bool LaysOn(this Vector2 point, Line line) - { - LineEquation lineEquation = line.ToLineEquation(); - - // y = mx + b - float y = lineEquation.Slope * point.X + lineEquation.OffsetY; - - return y == point.Y; - } + => line.Resolve(point.X) == point; public static LineEquation ToLineEquation(this Line line) { @@ -178,6 +177,32 @@ public static class PhysicsMath => ((l1.From.X - l0.From.X) * (l0.To.Y - l0.From.Y) - (l1.From.Y - l0.From.Y) * (l0.To.X - l0.From.X)) / ((l1.To.Y - l1.From.Y) * (l0.To.X - l0.From.X) - (l1.To.X - l1.From.X) * (l0.To.Y - l0.From.Y)); + public static float GetT(this Line line, Vector2 point) + { + if (!point.LaysOn(line)) + throw new Exception("Point does not lay on Line"); + + float fromX = MathF.Abs(line.From.X); + float toX = MathF.Abs(line.To.X); + float pointX = MathF.Abs(point.X); + + float min = MathF.Min(fromX, toX); + float max = MathF.Max(fromX, toX) - min; + + pointX -= min; + + return pointX / max; + } + + public static Vector2 Resolve(this Line line, float x) + { + LineEquation lineEquation = line.ToLineEquation(); + + // y = mx + b + float y = lineEquation.Slope * x + lineEquation.OffsetY; + return new Vector2(x, y); + } + public static Vector2 IntersectionPoint(this Line l1, Line l2) => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); From 8f3573100a56b2813bcad3d87ab100eae38f7968 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 16:51:27 +0300 Subject: [PATCH 21/81] Works --- Game/Physics2D/PhysicsEngine2D.cs | 19 ++++++++++--------- Game/Physics2D/PhysicsMath.cs | 26 +++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 7803293..71a13a9 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -69,6 +69,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int i = colliders.Count - 1; i >= 0; i--) CheckCollisions(colliders[i], colliders, (c1, c2, v) => { + // Console.WriteLine($"c1: {c1.BehaviourController.GameObject.Name}, c2: {c2.BehaviourController.GameObject.Name}"); NewMethod(c1, c2, v, intervalDeltaTime); NewMethod(c2, c1, v, intervalDeltaTime); @@ -89,7 +90,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (c1.RigidBody2D is not IRigidBody2D) return; - Line vertexTrajectory = new Line(vertex, vertex - c1.RigidBody2D.Velocity); + Line vertexTrajectory = new Line(vertex, vertex - c1.RigidBody2D.Velocity * intervalDeltaTime); if (vertexTrajectory.LengthSquared <= 0.001f) return; @@ -100,19 +101,22 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var line in lines) { - if (!vertexTrajectory.Intersects(line, out Vector2? intersectionPoint) || intersectionPoint is not null) + if (!vertexTrajectory.Intersects(line, out Vector2? intersectionPoint)) continue; - t = vertexTrajectory.GetT(vertex); + if (intersectionPoint is not Vector2 ip) + continue; + + t = vertexTrajectory.GetT(ip); Vector2 lineDirection = line.Direction; normal = new(lineDirection.Y, lineDirection.X); break; } - StepRigidBody(c1.RigidBody2D, -t); + StepRigidBody(c1.RigidBody2D, -t * intervalDeltaTime); c1.RigidBody2D.Velocity = Vector2.Reflect(c1.RigidBody2D.Velocity, normal); - StepRigidBody(c1.RigidBody2D, intervalDeltaTime - t); + StepRigidBody(c1.RigidBody2D, intervalDeltaTime - t * intervalDeltaTime); } private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) @@ -126,11 +130,8 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int y = 0; y < collider2D.Vertices.Count; y++) { Vector2 vertex = collider2D.Vertices[y]; - if (collider2D.CheckCollision(vertex)) - { + if (collider2DItem.CheckCollision(vertex)) OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem, vertex); - y--; // Recheck current vertex - } } } } diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 052cdb1..474ab0c 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -129,7 +129,7 @@ public static class PhysicsMath } public static bool LaysOn(this Vector2 point, Line line) - => line.Resolve(point.X) == point; + => ApproximatelyEqualEpsilon(line.Resolve(point.X), point, float.Epsilon); public static LineEquation ToLineEquation(this Line line) { @@ -179,8 +179,8 @@ public static class PhysicsMath public static float GetT(this Line line, Vector2 point) { - if (!point.LaysOn(line)) - throw new Exception("Point does not lay on Line"); + // if (!point.LaysOn(line)) + // throw new Exception("Point does not lay on Line"); float fromX = MathF.Abs(line.From.X); float toX = MathF.Abs(line.To.X); @@ -263,4 +263,24 @@ public static class PhysicsMath public static bool Inside(this Circle circle, Vector2 point) => (circle.Position - point).LengthSquared() <= circle.Radius * circle.Radius; + + public static bool ApproximatelyEqualEpsilon(float a, float b, float epsilon) + { + if (a == b) + return true; + + const float floatNormal = (1 << 23) * float.Epsilon; + float absA = Math.Abs(a); + float absB = Math.Abs(b); + float diff = Math.Abs(a - b); + + if (a == 0.0f || b == 0.0f || diff < floatNormal) + return diff < (epsilon * floatNormal); + + return diff / Math.Min((absA + absB), float.MaxValue) < epsilon; + } + public static bool ApproximatelyEqualEpsilon(Vector2 a, Vector2 b, float epsilon) + { + return ApproximatelyEqualEpsilon(a.X, b.X, epsilon) && ApproximatelyEqualEpsilon(a.Y, b.Y, epsilon); + } } From 73c939805f8c3a6e24fc6714782f4114ac68ddcc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 16:52:48 +0300 Subject: [PATCH 22/81] Cleanup --- Game/Physics2D/PhysicsEngine2D.cs | 33 ++++++------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 71a13a9..1b356ff 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -37,7 +37,6 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidBodies.Remove(rigidBody); } - // List gameObjects = new List(); private List lines = new List(32); public void Step(float deltaTime) @@ -53,39 +52,19 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var collider in colliders) collider.Recalculate(); - // foreach (var gameObject in gameObjects) - // Game1.gameManager.RemoveGameObject(gameObject); - // gameObjects.Clear(); - - // foreach (var collider in colliders) - // foreach (var vertex in collider.Vertices) - // { - // GameObject gameObject = Game1.gameManager.InstantiateGameObject(); - // gameObject.BehaviourController.AddBehaviour().Assign(Game1.spriteBox); - // gameObject.Transform.Position = vertex; - // gameObjects.Add(gameObject); - // } - for (int i = colliders.Count - 1; i >= 0; i--) - CheckCollisions(colliders[i], colliders, (c1, c2, v) => + CheckCollisions(colliders[i], colliders, (collider1, collider2, collisionVertex) => { - // Console.WriteLine($"c1: {c1.BehaviourController.GameObject.Name}, c2: {c2.BehaviourController.GameObject.Name}"); - NewMethod(c1, c2, v, intervalDeltaTime); - NewMethod(c2, c1, v, intervalDeltaTime); + ResolveCollision(collider1, collider2, collisionVertex, intervalDeltaTime); + ResolveCollision(collider2, collider1, collisionVertex, intervalDeltaTime); - // if (c2.RigidBody2D is IRigidBody2D) - // { - // c2.RigidBody2D.Velocity = -c2.RigidBody2D.Velocity; - // StepRigidBody(c2.RigidBody2D, intervalDeltaTime); - // } - - c1.Recalculate(); - c2.Recalculate(); + collider1.Recalculate(); + collider2.Recalculate(); }); } } - private void NewMethod(ICollider2D c1, ICollider2D c2, Vector2 vertex, float intervalDeltaTime) + private void ResolveCollision(ICollider2D c1, ICollider2D c2, Vector2 vertex, float intervalDeltaTime) { if (c1.RigidBody2D is not IRigidBody2D) return; From fd8964e58b45000a6b9be0c6dce0aff4972b5fe5 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 17:36:56 +0300 Subject: [PATCH 23/81] agtawtg --- Game/Game1.cs | 64 +++++++++++++++++++++---------- Game/Physics2D/PhysicsEngine2D.cs | 25 ++++++++---- 2 files changed, 61 insertions(+), 28 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 0a07534..ce41b07 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -155,28 +155,52 @@ public class Game1 : Game if (Keyboard.GetState().IsKeyDown(Keys.E)) gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; - // if (Keyboard.GetState().IsKeyDown(Keys.N)) - // seconds = 39.12f; - // if (Keyboard.GetState().IsKeyDown(Keys.Space)) - // seconds += gameTime.ElapsedGameTime.Milliseconds * .005f; - // if (Keyboard.GetState().IsKeyDown(Keys.B)) - // { - // seconds -= gameTime.ElapsedGameTime.Milliseconds * .005f; - // while (physicsTimer - 0.01f > seconds) - // { - // Console.WriteLine($"Physics Timer: {physicsTimer}"); - // physicsTimer -= 0.01f; - // engine.Step(-.01f); - // } - // } - - - while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) + if (Keyboard.GetState().IsKeyDown(Keys.N)) { - // Console.WriteLine($"Physics Timer: {physicsTimer}"); - physicsTimer += 0.01f; - engine.Step(.01f); + seconds = 70f; + while (physicsTimer + 0.01f < seconds) + { + physicsTimer += 0.01f; + engine.Step(.01f); + } } + if (Keyboard.GetState().IsKeyDown(Keys.M)) + { + seconds = 0f; + while (physicsTimer - 0.01f > seconds) + { + physicsTimer -= 0.01f; + engine.Step(-.01f); + } + } + if (Keyboard.GetState().IsKeyDown(Keys.Space)) + { + seconds += gameTime.ElapsedGameTime.Milliseconds * .0025f; + while (physicsTimer + 0.01f < seconds) + { + Console.WriteLine($"Physics Timer: {physicsTimer}"); + physicsTimer += 0.01f; + engine.Step(.01f); + } + } + if (Keyboard.GetState().IsKeyDown(Keys.B)) + { + seconds -= gameTime.ElapsedGameTime.Milliseconds * .0025f; + while (physicsTimer - 0.01f > seconds) + { + Console.WriteLine($"Physics Timer: {physicsTimer}"); + physicsTimer -= 0.01f; + engine.Step(-.01f); + } + } + + + // while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) + // { + // Console.WriteLine($"Physics Timer: {physicsTimer}"); + // physicsTimer += 0.01f; + // engine.Step(.01f); + // } gameManager.Update(gameTime); base.Update(gameTime); } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 1b356ff..9d94851 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -56,10 +56,10 @@ public class PhysicsEngine2D : IPhysicsEngine2D CheckCollisions(colliders[i], colliders, (collider1, collider2, collisionVertex) => { ResolveCollision(collider1, collider2, collisionVertex, intervalDeltaTime); - ResolveCollision(collider2, collider1, collisionVertex, intervalDeltaTime); + // ResolveCollision(collider2, collider1, collisionVertex, intervalDeltaTime); - collider1.Recalculate(); - collider2.Recalculate(); + // collider1.Recalculate(); + // collider2.Recalculate(); }); } } @@ -76,7 +76,8 @@ public class PhysicsEngine2D : IPhysicsEngine2D c2.Vertices.ToLines(lines); Vector2 normal = Vector2.UnitY; - float t = 0f; + float t = 1f; + bool hasIntersectedWithLines = false; foreach (var line in lines) { @@ -86,16 +87,24 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (intersectionPoint is not Vector2 ip) continue; - t = vertexTrajectory.GetT(ip); + float tTemp = vertexTrajectory.GetT(ip); + if (tTemp > t) // React to the earliest collision value + continue; + + t = tTemp; Vector2 lineDirection = line.Direction; normal = new(lineDirection.Y, lineDirection.X); - break; + hasIntersectedWithLines = true; } - StepRigidBody(c1.RigidBody2D, -t * intervalDeltaTime); + if (!hasIntersectedWithLines) + return; + + float rewindInterval = t * intervalDeltaTime; + StepRigidBody(c1.RigidBody2D, -rewindInterval); c1.RigidBody2D.Velocity = Vector2.Reflect(c1.RigidBody2D.Velocity, normal); - StepRigidBody(c1.RigidBody2D, intervalDeltaTime - t * intervalDeltaTime); + StepRigidBody(c1.RigidBody2D, rewindInterval); } private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) From 94897a06a3e7181bcb3a1254631abf49d6ec0955 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 17:39:21 +0300 Subject: [PATCH 24/81] asddad --- Game/Game1.cs | 2 +- Game/Physics2D/PhysicsEngine2D.cs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index ce41b07..8a5ed29 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -46,7 +46,7 @@ public class Game1 : Game protected override void LoadContent() { - engine = new PhysicsEngine2D(); + engine = new PhysicsEngine2D() { IterationCount = 100 }; _spriteBatch = new SpriteBatch(GraphicsDevice); spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 9d94851..49f9fbb 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -54,13 +54,8 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int i = colliders.Count - 1; i >= 0; i--) CheckCollisions(colliders[i], colliders, (collider1, collider2, collisionVertex) => - { - ResolveCollision(collider1, collider2, collisionVertex, intervalDeltaTime); - // ResolveCollision(collider2, collider1, collisionVertex, intervalDeltaTime); - - // collider1.Recalculate(); - // collider2.Recalculate(); - }); + ResolveCollision(collider1, collider2, collisionVertex, intervalDeltaTime) + ); } } From 03ba4878c09c2e4d6569936378d7ae7c1b5645c5 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 17:45:00 +0300 Subject: [PATCH 25/81] vfgsrvr --- Game/Game1.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 8a5ed29..a61bbf0 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -46,7 +46,7 @@ public class Game1 : Game protected override void LoadContent() { - engine = new PhysicsEngine2D() { IterationCount = 100 }; + engine = new PhysicsEngine2D(); _spriteBatch = new SpriteBatch(GraphicsDevice); spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; @@ -67,6 +67,14 @@ public class Game1 : Game gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); + gameObjectBall = gameManager.InstantiateGameObject(); + gameObjectBall.Name = "Ball"; + gameObjectBall.Transform.Position = Vector2.UnitY * 30f; + gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); + gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); + gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); gameObjectLeft.Name = "Left"; @@ -175,7 +183,7 @@ public class Game1 : Game } if (Keyboard.GetState().IsKeyDown(Keys.Space)) { - seconds += gameTime.ElapsedGameTime.Milliseconds * .0025f; + seconds += gameTime.ElapsedGameTime.Milliseconds * .005f; while (physicsTimer + 0.01f < seconds) { Console.WriteLine($"Physics Timer: {physicsTimer}"); @@ -185,7 +193,7 @@ public class Game1 : Game } if (Keyboard.GetState().IsKeyDown(Keys.B)) { - seconds -= gameTime.ElapsedGameTime.Milliseconds * .0025f; + seconds -= gameTime.ElapsedGameTime.Milliseconds * .005f; while (physicsTimer - 0.01f > seconds) { Console.WriteLine($"Physics Timer: {physicsTimer}"); From add4783c739ab3f9bf60436a56e6fd10ffa7af38 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 17:47:38 +0300 Subject: [PATCH 26/81] umujhhj --- Game/Game1.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index a61bbf0..ffa4763 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -68,13 +68,13 @@ public class Game1 : Game gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); gameObjectBall = gameManager.InstantiateGameObject(); - gameObjectBall.Name = "Ball"; - gameObjectBall.Transform.Position = Vector2.UnitY * 30f; - gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); - engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); - gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); + // gameObjectBall.Name = "Ball"; + // gameObjectBall.Transform.Position = Vector2.UnitY * 30f; + // gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + // engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); + // gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); + // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + // gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); gameObjectLeft.Name = "Left"; From 0fd1ebe726d45621a4afca60e98509fcd3d23c58 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 6 Dec 2023 17:55:48 +0300 Subject: [PATCH 27/81] trestset --- Game/Game1.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index ffa4763..ceef5ae 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -1,5 +1,5 @@ using System; - +using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -67,7 +67,7 @@ public class Game1 : Game gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); - gameObjectBall = gameManager.InstantiateGameObject(); + // gameObjectBall = gameManager.InstantiateGameObject(); // gameObjectBall.Name = "Ball"; // gameObjectBall.Transform.Position = Vector2.UnitY * 30f; // gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); @@ -170,6 +170,7 @@ public class Game1 : Game { physicsTimer += 0.01f; engine.Step(.01f); + Console.WriteLine($"{physicsTimer} -> {gameObjectBall.Transform.Position}"); } } if (Keyboard.GetState().IsKeyDown(Keys.M)) @@ -179,6 +180,7 @@ public class Game1 : Game { physicsTimer -= 0.01f; engine.Step(-.01f); + Console.WriteLine($"{physicsTimer} -> {gameObjectBall.Transform.Position}"); } } if (Keyboard.GetState().IsKeyDown(Keys.Space)) From 6183d2225f9f4ecc3d0f4ce9831769e52e352598 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 7 Dec 2023 10:55:49 +0300 Subject: [PATCH 28/81] Refactor --- Game/Physics2D/Collider2DAABBBehaviour.cs | 3 +- Game/Physics2D/PhysicsEngine2D.cs | 1 + Game/Physics2D/PhysicsMath.cs | 197 ++-------------------- Game/Physics2D/Primitives/AABB.cs | 10 ++ Game/Physics2D/Primitives/Circle.cs | 16 ++ Game/Physics2D/Primitives/Line.cs | 121 +++++++++++++ Game/Physics2D/Primitives/LineEquation.cs | 6 + Game/Physics2D/Primitives/Shape.cs | 56 ++++++ Game/Physics2D/Primitives/Triangle.cs | 51 ++++++ 9 files changed, 276 insertions(+), 185 deletions(-) create mode 100644 Game/Physics2D/Primitives/AABB.cs create mode 100644 Game/Physics2D/Primitives/Circle.cs create mode 100644 Game/Physics2D/Primitives/Line.cs create mode 100644 Game/Physics2D/Primitives/LineEquation.cs create mode 100644 Game/Physics2D/Primitives/Shape.cs create mode 100644 Game/Physics2D/Primitives/Triangle.cs diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index d1b8fce..ccb59d2 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -6,6 +6,7 @@ using Microsoft.Xna.Framework; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; +using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; @@ -38,7 +39,7 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D public bool CheckCollision(Vector2 point) { - return AABBWorld.Inside(point); + return AABBWorld.Overlaps(point); } public void Recalculate() diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 49f9fbb..029686f 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -5,6 +5,7 @@ using Microsoft.Xna.Framework; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; +using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 474ab0c..3874330 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -1,76 +1,18 @@ using System; using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; using Microsoft.Xna.Framework; +using Syntriax.Engine.Physics2D.Primitives; + namespace Syntriax.Engine.Physics2D; -public record Line(Vector2 From, Vector2 To) -{ - public Vector2 Direction => Vector2.Normalize(To - From); - public float Length => (From - To).Length(); - public float LengthSquared => (From - To).LengthSquared(); -} - -public record LineEquation(float Slope, float OffsetY); -public record Triangle(Vector2 A, Vector2 B, Vector2 C); -public record Circle(Vector2 Position, float Radius); -public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary); - public static class PhysicsMath { public static Vector2 Scale(this Vector2 original, Vector2 scale) => new Vector2(original.X * scale.X, original.Y * scale.Y); - public static Vector2 ClosestPointTo(this Line line, Vector2 point) - { - // Convert edge points to vectors - var edgeVector = new Vector2(line.To.X - line.From.X, line.To.Y - line.From.Y); - var pointVector = new Vector2(point.X - line.From.X, point.Y - line.From.Y); - - // Calculate the projection of pointVector onto edgeVector - float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); - - // Clamp t to the range [0, 1] to ensure the closest point is on the edge - t = Math.Max(0, Math.Min(1, t)); - - // Calculate the closest point on the edge - float closestX = line.From.X + t * edgeVector.X; - float closestY = line.From.Y + t * edgeVector.Y; - - return new Vector2((float)closestX, (float)closestY); - } - - public static float GetArea(this Triangle triangle) - { - return Math.Abs((triangle.A.X * (triangle.B.Y - triangle.C.Y) + - triangle.B.X * (triangle.C.Y - triangle.A.Y) + - triangle.C.X * (triangle.A.Y - triangle.B.Y)) * .5f); - } - - public static Circle ToCircumCircle(this Triangle triangle) - { - Vector2 midAB = (triangle.A + triangle.B) / 2; - Vector2 midBC = (triangle.B + triangle.C) / 2; - - float slopeAB = (triangle.B.Y - triangle.A.Y) / (triangle.B.X - triangle.A.X); - float slopeBC = (triangle.C.Y - triangle.B.Y) / (triangle.C.X - triangle.B.X); - - Vector2 center; - if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) - { - float x = (slopeAB * slopeBC * (triangle.A.Y - triangle.C.Y) + slopeBC * (triangle.A.X + triangle.B.X) - slopeAB * (triangle.B.X + triangle.C.X)) / (2 * (slopeBC - slopeAB)); - float y = -(x - (triangle.A.X + triangle.B.X) / 2) / slopeAB + (triangle.A.Y + triangle.B.Y) / 2; - center = new Vector2((float)x, (float)y); - } - else - center = (midAB + midBC) * .5f; - - return new(center, Vector2.Distance(center, triangle.A)); - } - - public static Triangle ToSuperTriangle(IList vertices) + public static Triangle ToSuperTriangle(this IList vertices) { float minX = float.MaxValue, minY = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue; @@ -111,35 +53,9 @@ public static class PhysicsMath lines.Add(new(vertices[^1], vertices[0])); } - public static bool ExistIn(Line lineToCheck, List vertices) - { - for (int i = 0; i < vertices.Count - 1; i++) - { - Vector2 vertexCurrent = vertices[i]; - Vector2 vertexNext = vertices[i]; - if (lineToCheck.From == vertexCurrent && lineToCheck.To == vertexNext) return true; - if (lineToCheck.From == vertexNext && lineToCheck.To == vertexCurrent) return true; - } - - Vector2 vertexFirst = vertices[0]; - Vector2 vertexLast = vertices[^1]; - if (lineToCheck.From == vertexFirst && lineToCheck.To == vertexLast) return true; - if (lineToCheck.From == vertexLast && lineToCheck.To == vertexFirst) return true; - return false; - } - public static bool LaysOn(this Vector2 point, Line line) - => ApproximatelyEqualEpsilon(line.Resolve(point.X), point, float.Epsilon); + => line.Resolve(point.X).ApproximatelyEquals(point); - public static LineEquation ToLineEquation(this Line line) - { - Vector2 slopeVector = line.To - line.From; - float slope = slopeVector.Y / slopeVector.X; - - float yOffset = line.From.Y - (slope * line.From.X); - - return new LineEquation(slope, yOffset); - } // Given three collinear points p, q, r, the function checks if // point q lies on line segment 'pr' @@ -173,98 +89,10 @@ public static class PhysicsMath => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); - public static float IntersectionParameterT(this Line l0, Line l1) - => ((l1.From.X - l0.From.X) * (l0.To.Y - l0.From.Y) - (l1.From.Y - l0.From.Y) * (l0.To.X - l0.From.X)) / - ((l1.To.Y - l1.From.Y) * (l0.To.X - l0.From.X) - (l1.To.X - l1.From.X) * (l0.To.Y - l0.From.Y)); - public static float GetT(this Line line, Vector2 point) - { - // if (!point.LaysOn(line)) - // throw new Exception("Point does not lay on Line"); - - float fromX = MathF.Abs(line.From.X); - float toX = MathF.Abs(line.To.X); - float pointX = MathF.Abs(point.X); - - float min = MathF.Min(fromX, toX); - float max = MathF.Max(fromX, toX) - min; - - pointX -= min; - - return pointX / max; - } - - public static Vector2 Resolve(this Line line, float x) - { - LineEquation lineEquation = line.ToLineEquation(); - - // y = mx + b - float y = lineEquation.Slope * x + lineEquation.OffsetY; - return new Vector2(x, y); - } - - public static Vector2 IntersectionPoint(this Line l1, Line l2) - => Vector2.Lerp(l1.From, l1.To, IntersectionParameterT(l1, l2)); - - public static bool Intersects(this Line l1, Line l2) - { - int o1 = Orientation(l1.From, l1.To, l2.From); - int o2 = Orientation(l1.From, l1.To, l2.To); - int o3 = Orientation(l2.From, l2.To, l1.From); - int o4 = Orientation(l2.From, l2.To, l1.To); - - if (o1 != o2 && o3 != o4) - return true; - - if (o1 == 0 && OnSegment(l1.From, l2.From, l1.To)) return true; - if (o2 == 0 && OnSegment(l1.From, l2.To, l1.To)) return true; - if (o3 == 0 && OnSegment(l2.From, l1.From, l2.To)) return true; - if (o4 == 0 && OnSegment(l2.From, l1.To, l2.To)) return true; - - return false; - } - - public static bool Intersects(this Line l1, Line l2, [NotNullWhen(returnValue: true)] out Vector2? point) - { - point = null; - - bool result = Intersects(l1, l2); - - if (result) - point = IntersectionPoint(l1, l2); - - return result; - } - - public static bool Intersects(this Circle circle, Circle circleOther) - { - float distanceSquared = (circle.Position - circleOther.Position).LengthSquared(); - float radiusSumSquared = circle.Radius * circle.Radius + circleOther.Radius * circleOther.Radius; - - return distanceSquared < radiusSumSquared; - } - - public static bool Inside(this Triangle triangle, Vector2 point) - { - float originalTriangleArea = GetArea(triangle); - - float pointTriangleArea1 = GetArea(new Triangle(point, triangle.B, triangle.C)); - float pointTriangleArea2 = GetArea(new Triangle(triangle.A, point, triangle.C)); - float pointTriangleArea3 = GetArea(new Triangle(triangle.A, triangle.B, point)); - - float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3; - - return originalTriangleArea >= pointTriangleAreasSum; - } - - public static bool Inside(this AABB aabb, Vector2 point) - => point.X >= aabb.LowerBoundary.X && point.X <= aabb.UpperBoundary.X && - point.Y >= aabb.LowerBoundary.Y && point.Y <= aabb.UpperBoundary.Y; - - public static bool Inside(this Circle circle, Vector2 point) - => (circle.Position - point).LengthSquared() <= circle.Radius * circle.Radius; - - public static bool ApproximatelyEqualEpsilon(float a, float b, float epsilon) + public static bool ApproximatelyEquals(this float a, float b) + => ApproximatelyEqualsEpsilon(a, b, float.Epsilon); + public static bool ApproximatelyEqualsEpsilon(this float a, float b, float epsilon) { if (a == b) return true; @@ -277,10 +105,11 @@ public static class PhysicsMath if (a == 0.0f || b == 0.0f || diff < floatNormal) return diff < (epsilon * floatNormal); - return diff / Math.Min((absA + absB), float.MaxValue) < epsilon; - } - public static bool ApproximatelyEqualEpsilon(Vector2 a, Vector2 b, float epsilon) - { - return ApproximatelyEqualEpsilon(a.X, b.X, epsilon) && ApproximatelyEqualEpsilon(a.Y, b.Y, epsilon); + return diff / Math.Min(absA + absB, float.MaxValue) < epsilon; } + + public static bool ApproximatelyEquals(this Vector2 a, Vector2 b) + => ApproximatelyEqualEpsilon(a, b, float.Epsilon); + public static bool ApproximatelyEqualEpsilon(this Vector2 a, Vector2 b, float epsilon) + => ApproximatelyEqualsEpsilon(a.X, b.X, epsilon) && ApproximatelyEqualsEpsilon(a.Y, b.Y, epsilon); } diff --git a/Game/Physics2D/Primitives/AABB.cs b/Game/Physics2D/Primitives/AABB.cs new file mode 100644 index 0000000..94a4a65 --- /dev/null +++ b/Game/Physics2D/Primitives/AABB.cs @@ -0,0 +1,10 @@ +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary) +{ + public bool Overlaps(Vector2 point) + => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X && + point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y; +} diff --git a/Game/Physics2D/Primitives/Circle.cs b/Game/Physics2D/Primitives/Circle.cs new file mode 100644 index 0000000..734119e --- /dev/null +++ b/Game/Physics2D/Primitives/Circle.cs @@ -0,0 +1,16 @@ +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Circle(Vector2 Position, float Radius) +{ + public bool Intersects(Circle circleOther) + { + float distanceSquared = (Position - circleOther.Position).LengthSquared(); + float radiusSumSquared = Radius * Radius + circleOther.Radius * circleOther.Radius; + + return distanceSquared < radiusSumSquared; + } + + public bool Overlaps(Vector2 point) => (Position - point).LengthSquared() <= Radius * Radius; +} diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs new file mode 100644 index 0000000..483c9ad --- /dev/null +++ b/Game/Physics2D/Primitives/Line.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Line(Vector2 From, Vector2 To) +{ + public Vector2 Direction => Vector2.Normalize(To - From); + public float Length => (From - To).Length(); + public float LengthSquared => (From - To).LengthSquared(); + + public LineEquation LineEquation + { + get + { + Vector2 slopeVector = To - From; + float slope = slopeVector.Y / slopeVector.X; + + float yOffset = From.Y - (slope * From.X); + + return new LineEquation(slope, yOffset); + } + } + + public bool Intersects(Vector2 point) + => Resolve(point.X).ApproximatelyEquals(point); + + public float GetT(Vector2 point) + { + float fromX = MathF.Abs(From.X); + float toX = MathF.Abs(To.X); + float pointX = MathF.Abs(point.X); + + float min = MathF.Min(fromX, toX); + float max = MathF.Max(fromX, toX) - min; + + pointX -= min; + + return pointX / max; + } + + public bool Exist(List vertices) + { + for (int i = 0; i < vertices.Count - 1; i++) + { + Vector2 vertexCurrent = vertices[i]; + Vector2 vertexNext = vertices[i]; + if (From == vertexCurrent && To == vertexNext) return true; + if (From == vertexNext && To == vertexCurrent) return true; + } + + Vector2 vertexFirst = vertices[0]; + Vector2 vertexLast = vertices[^1]; + if (From == vertexFirst && To == vertexLast) return true; + if (From == vertexLast && To == vertexFirst) return true; + return false; + } + + public float IntersectionParameterT(Line other) + => ((other.From.X - From.X) * (To.Y - From.Y) - (other.From.Y - From.Y) * (To.X - From.X)) / + ((other.To.Y - other.From.Y) * (To.X - From.X) - (other.To.X - other.From.X) * (To.Y - From.Y)); + + + public Vector2 Resolve(float x) + => new Vector2(x, LineEquation.Resolve(x)); + + public Vector2 ClosestPointTo(Vector2 point) + { + // Convert edge points to vectors + var edgeVector = new Vector2(To.X - From.X, To.Y - From.Y); + var pointVector = new Vector2(point.X - From.X, point.Y - From.Y); + + // Calculate the projection of pointVector onto edgeVector + float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); + + // Clamp t to the range [0, 1] to ensure the closest point is on the edge + t = Math.Max(0, Math.Min(1, t)); + + // Calculate the closest point on the edge + float closestX = From.X + t * edgeVector.X; + float closestY = From.Y + t * edgeVector.Y; + + return new Vector2((float)closestX, (float)closestY); + } + + public Vector2 IntersectionPoint(Line other) + => Vector2.Lerp(From, To, IntersectionParameterT(other)); + + public bool Intersects(Line other) + { + int o1 = PhysicsMath.Orientation(From, To, other.From); + int o2 = PhysicsMath.Orientation(From, To, other.To); + int o3 = PhysicsMath.Orientation(other.From, other.To, From); + int o4 = PhysicsMath.Orientation(other.From, other.To, To); + + if (o1 != o2 && o3 != o4) + return true; + + if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true; + if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true; + if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true; + if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true; + + return false; + } + + public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2? point) + { + point = null; + + bool result = Intersects(other); + + if (result) + point = IntersectionPoint(other); + + return result; + } +} diff --git a/Game/Physics2D/Primitives/LineEquation.cs b/Game/Physics2D/Primitives/LineEquation.cs new file mode 100644 index 0000000..a85596c --- /dev/null +++ b/Game/Physics2D/Primitives/LineEquation.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Physics2D.Primitives; + +public record LineEquation(float Slope, float OffsetY) +{ + public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b +} diff --git a/Game/Physics2D/Primitives/Shape.cs b/Game/Physics2D/Primitives/Shape.cs new file mode 100644 index 0000000..8f827ce --- /dev/null +++ b/Game/Physics2D/Primitives/Shape.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Shape(IList Vertices) +{ + public Triangle SuperTriangle + { + get + { + float minX = float.MaxValue, minY = float.MaxValue; + float maxX = float.MinValue, maxY = float.MinValue; + + foreach (Vector2 point in Vertices) + { + minX = Math.Min(minX, point.X); + minY = Math.Min(minY, point.Y); + maxX = Math.Max(maxX, point.X); + maxY = Math.Max(maxY, point.Y); + } + + float dx = maxX - minX; + float dy = maxY - minY; + float deltaMax = Math.Max(dx, dy); + float midX = (minX + maxX) / 2; + float midY = (minY + maxY) / 2; + + Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); + Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); + + return new Triangle(p1, p2, p3); + } + } + + public IList Lines + { + get + { + List lines = new List(Vertices.Count - 1); + GetLinesNonAlloc(lines); + return lines; + } + } + + public void GetLinesNonAlloc(IList lines) + { + lines.Clear(); + for (int i = 0; i < Vertices.Count - 1; i++) + lines.Add(new(Vertices[i], Vertices[i + 1])); + lines.Add(new(Vertices[^1], Vertices[0])); + } +} diff --git a/Game/Physics2D/Primitives/Triangle.cs b/Game/Physics2D/Primitives/Triangle.cs new file mode 100644 index 0000000..9d610ab --- /dev/null +++ b/Game/Physics2D/Primitives/Triangle.cs @@ -0,0 +1,51 @@ +using System; + +using Microsoft.Xna.Framework; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Triangle(Vector2 A, Vector2 B, Vector2 C) +{ + public float Area => Math.Abs(( + A.X * (B.Y - C.Y) + + B.X * (C.Y - A.Y) + + C.X * (A.Y - B.Y) + ) * .5f); + + public Circle CircumCircle + { + get + { + Vector2 midAB = (A + B) / 2; + Vector2 midBC = (B + C) / 2; + + float slopeAB = (B.Y - A.Y) / (B.X - A.X); + float slopeBC = (C.Y - B.Y) / (C.X - B.X); + + Vector2 center; + if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) + { + float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB)); + float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2; + center = new Vector2((float)x, (float)y); + } + else + center = (midAB + midBC) * .5f; + + return new(center, Vector2.Distance(center, A)); + } + } + + public bool Overlaps(Vector2 point) + { + float originalTriangleArea = Area; + + float pointTriangleArea1 = new Triangle(point, B, C).Area; + float pointTriangleArea2 = new Triangle(A, point, C).Area; + float pointTriangleArea3 = new Triangle(A, B, point).Area; + + float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3; + + return originalTriangleArea >= pointTriangleAreasSum; + } +} From 2e723477218a85dc4a7bd25b783271711fb28f93 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 7 Dec 2023 11:14:18 +0300 Subject: [PATCH 29/81] Refactor 2 --- Game/Physics2D/PhysicsMath.cs | 13 ++++++------- Game/Physics2D/Primitives/AABB.cs | 7 +++++++ Game/Physics2D/Primitives/Circle.cs | 8 +++++--- Game/Physics2D/Primitives/Line.cs | 3 +++ Game/Physics2D/Primitives/LineEquation.cs | 2 ++ Game/Physics2D/Primitives/Shape.cs | 14 +++++++++++++- Game/Physics2D/Primitives/Triangle.cs | 7 +++++-- 7 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index 3874330..b22d844 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -91,8 +91,12 @@ public static class PhysicsMath public static bool ApproximatelyEquals(this float a, float b) - => ApproximatelyEqualsEpsilon(a, b, float.Epsilon); - public static bool ApproximatelyEqualsEpsilon(this float a, float b, float epsilon) + => ApproximatelyEquals(a, b, float.Epsilon); + public static bool ApproximatelyEquals(this Vector2 a, Vector2 b) + => ApproximatelyEquals(a, b, float.Epsilon); + public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon) + => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon); + public static bool ApproximatelyEquals(this float a, float b, float epsilon) { if (a == b) return true; @@ -107,9 +111,4 @@ public static class PhysicsMath return diff / Math.Min(absA + absB, float.MaxValue) < epsilon; } - - public static bool ApproximatelyEquals(this Vector2 a, Vector2 b) - => ApproximatelyEqualEpsilon(a, b, float.Epsilon); - public static bool ApproximatelyEqualEpsilon(this Vector2 a, Vector2 b, float epsilon) - => ApproximatelyEqualsEpsilon(a.X, b.X, epsilon) && ApproximatelyEqualsEpsilon(a.Y, b.Y, epsilon); } diff --git a/Game/Physics2D/Primitives/AABB.cs b/Game/Physics2D/Primitives/AABB.cs index 94a4a65..e6d3c28 100644 --- a/Game/Physics2D/Primitives/AABB.cs +++ b/Game/Physics2D/Primitives/AABB.cs @@ -7,4 +7,11 @@ public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary) public bool Overlaps(Vector2 point) => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X && point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y; + + public bool Overlaps(AABB other) + => LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X && + LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y; + + public bool ApproximatelyEquals(AABB other) + => LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary); } diff --git a/Game/Physics2D/Primitives/Circle.cs b/Game/Physics2D/Primitives/Circle.cs index 734119e..386e651 100644 --- a/Game/Physics2D/Primitives/Circle.cs +++ b/Game/Physics2D/Primitives/Circle.cs @@ -4,13 +4,15 @@ namespace Syntriax.Engine.Physics2D.Primitives; public record Circle(Vector2 Position, float Radius) { - public bool Intersects(Circle circleOther) + public bool Intersects(Circle other) { - float distanceSquared = (Position - circleOther.Position).LengthSquared(); - float radiusSumSquared = Radius * Radius + circleOther.Radius * circleOther.Radius; + float distanceSquared = (Position - other.Position).LengthSquared(); + float radiusSumSquared = Radius * Radius + other.Radius * other.Radius; return distanceSquared < radiusSumSquared; } public bool Overlaps(Vector2 point) => (Position - point).LengthSquared() <= Radius * Radius; + public bool ApproximatelyEquals(Circle other) + => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius); } diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs index 483c9ad..5553497 100644 --- a/Game/Physics2D/Primitives/Line.cs +++ b/Game/Physics2D/Primitives/Line.cs @@ -118,4 +118,7 @@ public record Line(Vector2 From, Vector2 To) return result; } + + public bool ApproximatelyEquals(Line other) + => From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To); } diff --git a/Game/Physics2D/Primitives/LineEquation.cs b/Game/Physics2D/Primitives/LineEquation.cs index a85596c..a60977b 100644 --- a/Game/Physics2D/Primitives/LineEquation.cs +++ b/Game/Physics2D/Primitives/LineEquation.cs @@ -3,4 +3,6 @@ namespace Syntriax.Engine.Physics2D.Primitives; public record LineEquation(float Slope, float OffsetY) { public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b + public bool ApproximatelyEquals(LineEquation other) + => Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY); } diff --git a/Game/Physics2D/Primitives/Shape.cs b/Game/Physics2D/Primitives/Shape.cs index 8f827ce..bedc743 100644 --- a/Game/Physics2D/Primitives/Shape.cs +++ b/Game/Physics2D/Primitives/Shape.cs @@ -36,7 +36,7 @@ public record Shape(IList Vertices) } } - public IList Lines + public List Lines { get { @@ -53,4 +53,16 @@ public record Shape(IList Vertices) lines.Add(new(Vertices[i], Vertices[i + 1])); lines.Add(new(Vertices[^1], Vertices[0])); } + + public bool ApproximatelyEquals(Shape other) + { + if (Vertices.Count != other.Vertices.Count) + return false; + + for (int i = 0; i < Vertices.Count; i++) + if (!Vertices[i].ApproximatelyEquals(other.Vertices[i])) + return false; + + return true; + } } diff --git a/Game/Physics2D/Primitives/Triangle.cs b/Game/Physics2D/Primitives/Triangle.cs index 9d610ab..6417951 100644 --- a/Game/Physics2D/Primitives/Triangle.cs +++ b/Game/Physics2D/Primitives/Triangle.cs @@ -27,7 +27,7 @@ public record Triangle(Vector2 A, Vector2 B, Vector2 C) { float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB)); float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2; - center = new Vector2((float)x, (float)y); + center = new Vector2(x, y); } else center = (midAB + midBC) * .5f; @@ -46,6 +46,9 @@ public record Triangle(Vector2 A, Vector2 B, Vector2 C) float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3; - return originalTriangleArea >= pointTriangleAreasSum; + return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f); } + + public bool ApproximatelyEquals(Triangle other) + => A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C); } From dd9950d6c5236ad2d9f7952421bb507cd898a76c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 18 Dec 2023 22:49:26 +0300 Subject: [PATCH 30/81] Hey this actually is deterministic atm --- Game/Game1.cs | 39 ++++++++++++++++--------------- Game/Physics2D/PhysicsEngine2D.cs | 10 ++++++-- Game/Physics2D/Primitives/Line.cs | 28 +++++++++++++++++++--- 3 files changed, 53 insertions(+), 24 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index ceef5ae..7fa96c7 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -11,6 +11,7 @@ using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Input; using Syntriax.Engine.Physics2D; +using Syntriax.Engine.Physics2D.Primitives; namespace Pong; @@ -64,7 +65,7 @@ public class Game1 : Game gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); + gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), 500f); gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); // gameObjectBall = gameManager.InstantiateGameObject(); @@ -76,25 +77,25 @@ public class Game1 : Game // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); // gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); - IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); - gameObjectLeft.Name = "Left"; - gameObjectLeft.Transform.Position = new Vector2(-452, 0f); - gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); - gameObjectLeft.BehaviourController.AddBehaviour(); - gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); - engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); + // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); + // gameObjectLeft.Name = "Left"; + // gameObjectLeft.Transform.Position = new Vector2(-452, 0f); + // gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); + // gameObjectLeft.BehaviourController.AddBehaviour(); + // gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + // gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + // gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + // engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); - IGameObject gameObjectRight = gameManager.InstantiateGameObject(); - gameObjectRight.Name = "Right"; - gameObjectRight.Transform.Position = new Vector2(452, 0f); - gameObjectRight.Transform.Scale = new Vector2(10f, 40f); - gameObjectRight.BehaviourController.AddBehaviour(); - gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); - gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); - gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); - engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); + // IGameObject gameObjectRight = gameManager.InstantiateGameObject(); + // gameObjectRight.Name = "Right"; + // gameObjectRight.Transform.Position = new Vector2(452, 0f); + // gameObjectRight.Transform.Scale = new Vector2(10f, 40f); + // gameObjectRight.BehaviourController.AddBehaviour(); + // gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); + // gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); + // gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + // engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 029686f..e1acfb6 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -65,7 +65,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (c1.RigidBody2D is not IRigidBody2D) return; - Line vertexTrajectory = new Line(vertex, vertex - c1.RigidBody2D.Velocity * intervalDeltaTime); + Line vertexTrajectory = new Line(vertex - c1.RigidBody2D.Velocity * intervalDeltaTime, vertex); if (vertexTrajectory.LengthSquared <= 0.001f) return; @@ -96,7 +96,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D if (!hasIntersectedWithLines) return; - float rewindInterval = t * intervalDeltaTime; + float rewindInterval = intervalDeltaTime - t * intervalDeltaTime; StepRigidBody(c1.RigidBody2D, -rewindInterval); c1.RigidBody2D.Velocity = Vector2.Reflect(c1.RigidBody2D.Velocity, normal); @@ -115,7 +115,13 @@ public class PhysicsEngine2D : IPhysicsEngine2D { Vector2 vertex = collider2D.Vertices[y]; if (collider2DItem.CheckCollision(vertex)) + { OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem, vertex); + OnCollisionDetectedAction?.Invoke(collider2DItem, collider2D, vertex); + collider2D.Recalculate(); + collider2DItem.Recalculate(); + y--; + } } } } diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs index 5553497..02cc06f 100644 --- a/Game/Physics2D/Primitives/Line.cs +++ b/Game/Physics2D/Primitives/Line.cs @@ -8,6 +8,7 @@ namespace Syntriax.Engine.Physics2D.Primitives; public record Line(Vector2 From, Vector2 To) { + public Line Reversed => new(To, From); public Vector2 Direction => Vector2.Normalize(To - From); public float Length => (From - To).Length(); public float LengthSquared => (From - To).LengthSquared(); @@ -39,7 +40,15 @@ public record Line(Vector2 From, Vector2 To) pointX -= min; - return pointX / max; + float t = pointX / max; + + // FIXME + // I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line + // Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason + // too unmotivated to find a solution. Future me, find a better way if possible, please. + if (!Lerp(t).ApproximatelyEquals(point)) + return 1f - t; + return t; } public bool Exist(List vertices) @@ -60,9 +69,22 @@ public record Line(Vector2 From, Vector2 To) } public float IntersectionParameterT(Line other) - => ((other.From.X - From.X) * (To.Y - From.Y) - (other.From.Y - From.Y) * (To.X - From.X)) / - ((other.To.Y - other.From.Y) * (To.X - From.X) - (other.To.X - other.From.X) * (To.Y - From.Y)); + { + float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X); + float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X); + // Lines are parallel + if (denominator == 0) + return float.NaN; + + return numerator / denominator; + } + + public Vector2 Lerp(float t) + => new Vector2( + From.X + (To.X - From.X) * t, + From.Y + (To.Y - From.Y) * t + ); public Vector2 Resolve(float x) => new Vector2(x, LineEquation.Resolve(x)); From 0e922bb600597a6e319f5126a05bc754fbce9c2c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 11:21:27 +0300 Subject: [PATCH 31/81] refactor: Removed Unnecessary Lines --- Game/.vscode/settings.json | 7 +++++++ Game/Game1.cs | 11 ++++------- 2 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 Game/.vscode/settings.json diff --git a/Game/.vscode/settings.json b/Game/.vscode/settings.json new file mode 100644 index 0000000..f39a2ca --- /dev/null +++ b/Game/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "AABB", + "DAABB", + "Syntriax" + ] +} diff --git a/Game/Game1.cs b/Game/Game1.cs index 7fa96c7..a1797ca 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -1,5 +1,5 @@ using System; -using System.Collections.Generic; + using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -9,7 +9,6 @@ using Pong.Behaviours; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Graphics.TwoDimensional; -using Syntriax.Engine.Input; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D.Primitives; @@ -25,6 +24,8 @@ public class Game1 : Game public Game1() { + engine = new PhysicsEngine2D(); + _graphics = new GraphicsDeviceManager(this) { PreferredBackBufferWidth = 1024, @@ -47,7 +48,6 @@ public class Game1 : Game protected override void LoadContent() { - engine = new PhysicsEngine2D(); _spriteBatch = new SpriteBatch(GraphicsDevice); spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; @@ -60,7 +60,7 @@ public class Game1 : Game gameManager.Camera = gameObjectCamera.BehaviourController.AddBehaviour(); gameManager.Camera.Viewport = GraphicsDevice.Viewport; - gameObjectBall = gameManager.InstantiateGameObject(); + GameObject gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; gameObjectBall.Transform.Position = Vector2.Zero; gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); @@ -171,7 +171,6 @@ public class Game1 : Game { physicsTimer += 0.01f; engine.Step(.01f); - Console.WriteLine($"{physicsTimer} -> {gameObjectBall.Transform.Position}"); } } if (Keyboard.GetState().IsKeyDown(Keys.M)) @@ -181,7 +180,6 @@ public class Game1 : Game { physicsTimer -= 0.01f; engine.Step(-.01f); - Console.WriteLine($"{physicsTimer} -> {gameObjectBall.Transform.Position}"); } } if (Keyboard.GetState().IsKeyDown(Keys.Space)) @@ -217,7 +215,6 @@ public class Game1 : Game } static float physicsTimer = 0f; static float seconds = 0f; - private GameObject gameObjectBall; protected override void Draw(GameTime gameTime) { From c24f71c4af7a0973024c29ca4d8e85872fd4d560 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:28:43 +0300 Subject: [PATCH 32/81] feat: Basic Math Class --- Game/Physics2D/Primitives/Math.cs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Game/Physics2D/Primitives/Math.cs diff --git a/Game/Physics2D/Primitives/Math.cs b/Game/Physics2D/Primitives/Math.cs new file mode 100644 index 0000000..86ae4c9 --- /dev/null +++ b/Game/Physics2D/Primitives/Math.cs @@ -0,0 +1,7 @@ +namespace Syntriax.Engine.Physics2D.Primitives; + +public static class Math +{ + public const float RadianToDegree = 57.29577866666166f; + public const float DegreeToRadian = 0.01745329277777778f; +} From ea92bc8c07a33f5cd467159250bb684ae4fbbfa2 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:29:25 +0300 Subject: [PATCH 33/81] feat: Point2D Record --- Game/Physics2D/Primitives/Point2D.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Game/Physics2D/Primitives/Point2D.cs diff --git a/Game/Physics2D/Primitives/Point2D.cs b/Game/Physics2D/Primitives/Point2D.cs new file mode 100644 index 0000000..d344a34 --- /dev/null +++ b/Game/Physics2D/Primitives/Point2D.cs @@ -0,0 +1,19 @@ +using System; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Point2D(float X, float Y) +{ + public static Point2D operator +(Point2D left, Point2D right) => new(left.X + right.X, left.Y + right.Y); + public static Point2D operator -(Point2D left, Point2D right) => new(left.X - right.X, left.Y - right.Y); + public static Point2D operator *(Point2D point, float value) => new(point.X * value, point.Y * value); + public static Point2D operator /(Point2D point, float value) => new(point.X / value, point.Y / value); + + public static float Length(Point2D point) => MathF.Sqrt(LengthSqr(point)); + public static float LengthSqr(Point2D point) => point.X * point.X + point.Y * point.Y; + + public static Point2D Normalize(Point2D point) => point / Length(point); + public static float Cross(Point2D left, Point2D right) => left.X * right.Y - left.Y * right.X; + public static float Angle(Point2D left, Point2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); + public static float Dot(Point2D left, Point2D right) => left.X * right.X + left.Y * right.Y; +} From e8d0ff030adc51fb379ebaf451ab4e6c821c6527 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:30:08 +0300 Subject: [PATCH 34/81] refactor: Renamed Point2D to Vector2D --- Game/Physics2D/Primitives/Point2D.cs | 19 ------------------- Game/Physics2D/Primitives/Vector2D.cs | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) delete mode 100644 Game/Physics2D/Primitives/Point2D.cs create mode 100644 Game/Physics2D/Primitives/Vector2D.cs diff --git a/Game/Physics2D/Primitives/Point2D.cs b/Game/Physics2D/Primitives/Point2D.cs deleted file mode 100644 index d344a34..0000000 --- a/Game/Physics2D/Primitives/Point2D.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record Point2D(float X, float Y) -{ - public static Point2D operator +(Point2D left, Point2D right) => new(left.X + right.X, left.Y + right.Y); - public static Point2D operator -(Point2D left, Point2D right) => new(left.X - right.X, left.Y - right.Y); - public static Point2D operator *(Point2D point, float value) => new(point.X * value, point.Y * value); - public static Point2D operator /(Point2D point, float value) => new(point.X / value, point.Y / value); - - public static float Length(Point2D point) => MathF.Sqrt(LengthSqr(point)); - public static float LengthSqr(Point2D point) => point.X * point.X + point.Y * point.Y; - - public static Point2D Normalize(Point2D point) => point / Length(point); - public static float Cross(Point2D left, Point2D right) => left.X * right.Y - left.Y * right.X; - public static float Angle(Point2D left, Point2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); - public static float Dot(Point2D left, Point2D right) => left.X * right.X + left.Y * right.Y; -} diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs new file mode 100644 index 0000000..ece82f3 --- /dev/null +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -0,0 +1,19 @@ +using System; + +namespace Syntriax.Engine.Physics2D.Primitives; + +public record Vector2D(float X, float Y) +{ + public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); + public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); + public static Vector2D operator *(Vector2D point, float value) => new(point.X * value, point.Y * value); + public static Vector2D operator /(Vector2D point, float value) => new(point.X / value, point.Y / value); + + public static float Length(Vector2D point) => MathF.Sqrt(LengthSqr(point)); + public static float LengthSqr(Vector2D point) => point.X * point.X + point.Y * point.Y; + + public static Vector2D Normalize(Vector2D point) => point / Length(point); + public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; + public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); + public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; +} From 225e65fa90a50aff45c97d02854551b3aef50f29 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:40:32 +0300 Subject: [PATCH 35/81] feat: Vector2DExtensions --- Game/Physics2D/Primitives/Vector2DExtensions.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 Game/Physics2D/Primitives/Vector2DExtensions.cs diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs new file mode 100644 index 0000000..c9dae37 --- /dev/null +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -0,0 +1,13 @@ +namespace Syntriax.Engine.Physics2D.Primitives; + +public static class Vector2DExtensions +{ + public static float Length(this Vector2D point) => Vector2D.Length(point); + public static float LengthSqr(this Vector2D point) => Vector2D.LengthSqr(point); + + public static Vector2D Normalize(this Vector2D point) => Vector2D.Normalize(point); + + public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); + public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); + public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); +} From 40e73f6b8e4e2f3c7fd9cde2dcdad0ac4d426c28 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:41:48 +0300 Subject: [PATCH 36/81] feat: FromTo Method for Vector2D --- Game/Physics2D/Primitives/Vector2D.cs | 2 ++ Game/Physics2D/Primitives/Vector2DExtensions.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index ece82f3..b10fad9 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -13,6 +13,8 @@ public record Vector2D(float X, float Y) public static float LengthSqr(Vector2D point) => point.X * point.X + point.Y * point.Y; public static Vector2D Normalize(Vector2D point) => point / Length(point); + public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; + public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index c9dae37..9620c64 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -6,6 +6,7 @@ public static class Vector2DExtensions public static float LengthSqr(this Vector2D point) => Vector2D.LengthSqr(point); public static Vector2D Normalize(this Vector2D point) => Vector2D.Normalize(point); + public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); From a3860ddd22a7cd26f460394dc99e6a89f97bfdbc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:43:06 +0300 Subject: [PATCH 37/81] refactor: Vector2D.LengthSqr to LengthSquared --- Game/Physics2D/Primitives/Vector2D.cs | 4 ++-- Game/Physics2D/Primitives/Vector2DExtensions.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index b10fad9..186fdaa 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -9,8 +9,8 @@ public record Vector2D(float X, float Y) public static Vector2D operator *(Vector2D point, float value) => new(point.X * value, point.Y * value); public static Vector2D operator /(Vector2D point, float value) => new(point.X / value, point.Y / value); - public static float Length(Vector2D point) => MathF.Sqrt(LengthSqr(point)); - public static float LengthSqr(Vector2D point) => point.X * point.X + point.Y * point.Y; + public static float Length(Vector2D point) => MathF.Sqrt(LengthSquared(point)); + public static float LengthSquared(Vector2D point) => point.X * point.X + point.Y * point.Y; public static Vector2D Normalize(Vector2D point) => point / Length(point); public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index 9620c64..97389df 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -3,7 +3,7 @@ namespace Syntriax.Engine.Physics2D.Primitives; public static class Vector2DExtensions { public static float Length(this Vector2D point) => Vector2D.Length(point); - public static float LengthSqr(this Vector2D point) => Vector2D.LengthSqr(point); + public static float LengthSquared(this Vector2D point) => Vector2D.LengthSquared(point); public static Vector2D Normalize(this Vector2D point) => Vector2D.Normalize(point); public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); From db9e7dc09efc06bc44762dd00df6dd70b497b1bc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:48:12 +0300 Subject: [PATCH 38/81] feat: Vector2D.Distance Method --- Game/Physics2D/Primitives/Vector2D.cs | 2 ++ Game/Physics2D/Primitives/Vector2DExtensions.cs | 1 + 2 files changed, 3 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 186fdaa..565140a 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -12,6 +12,8 @@ public record Vector2D(float X, float Y) public static float Length(Vector2D point) => MathF.Sqrt(LengthSquared(point)); public static float LengthSquared(Vector2D point) => point.X * point.X + point.Y * point.Y; + public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); + public static Vector2D Normalize(Vector2D point) => point / Length(point); public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index 97389df..0d2e733 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -4,6 +4,7 @@ public static class Vector2DExtensions { public static float Length(this Vector2D point) => Vector2D.Length(point); public static float LengthSquared(this Vector2D point) => Vector2D.LengthSquared(point); + public static float Distance(this Vector2D from, Vector2D to) => Vector2D.LengthSquared(point); public static Vector2D Normalize(this Vector2D point) => Vector2D.Normalize(point); public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); From 063473e0b57bd803bee78047ad3aae0b3c4855ee Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:49:31 +0300 Subject: [PATCH 39/81] style: Renamed Parameters point to vector --- Game/Physics2D/Primitives/Vector2D.cs | 10 +++++----- Game/Physics2D/Primitives/Vector2DExtensions.cs | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 565140a..cfb4206 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -6,15 +6,15 @@ public record Vector2D(float X, float Y) { public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); - public static Vector2D operator *(Vector2D point, float value) => new(point.X * value, point.Y * value); - public static Vector2D operator /(Vector2D point, float value) => new(point.X / value, point.Y / value); + public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); + public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value); - public static float Length(Vector2D point) => MathF.Sqrt(LengthSquared(point)); - public static float LengthSquared(Vector2D point) => point.X * point.X + point.Y * point.Y; + public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector)); + public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y; public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); - public static Vector2D Normalize(Vector2D point) => point / Length(point); + public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index 0d2e733..f019f1e 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -2,11 +2,11 @@ namespace Syntriax.Engine.Physics2D.Primitives; public static class Vector2DExtensions { - public static float Length(this Vector2D point) => Vector2D.Length(point); - public static float LengthSquared(this Vector2D point) => Vector2D.LengthSquared(point); - public static float Distance(this Vector2D from, Vector2D to) => Vector2D.LengthSquared(point); + public static float Length(this Vector2D vector) => Vector2D.Length(vector); + public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); + public static float Distance(this Vector2D from, Vector2D to) => Vector2D.LengthSquared(vector); - public static Vector2D Normalize(this Vector2D point) => Vector2D.Normalize(point); + public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); From 661f2027ce106f8851b5cce63e4b9f4ad8224aac Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:53:22 +0300 Subject: [PATCH 40/81] feat: Vector2D.Scale Method --- Game/Physics2D/Primitives/Vector2D.cs | 1 + Game/Physics2D/Primitives/Vector2DExtensions.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index cfb4206..18d77cf 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -16,6 +16,7 @@ public record Vector2D(float X, float Y) public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; + public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index f019f1e..c5266be 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -4,10 +4,11 @@ public static class Vector2DExtensions { public static float Length(this Vector2D vector) => Vector2D.Length(vector); public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); - public static float Distance(this Vector2D from, Vector2D to) => Vector2D.LengthSquared(vector); + public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); + public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.FromTo(vector, scale); public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); From fd3d1c2e38ed7775326a8b228312ab2111b59531 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 12:55:20 +0300 Subject: [PATCH 41/81] feat: Vector2D Default Directions --- Game/Physics2D/Primitives/Vector2D.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 18d77cf..6ce4f3a 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -4,6 +4,12 @@ namespace Syntriax.Engine.Physics2D.Primitives; public record Vector2D(float X, float Y) { + public readonly static Vector2D Up = new(0f, 1f); + public readonly static Vector2D Down = new(0f, -1f); + public readonly static Vector2D Left = new(-1f, 0f); + public readonly static Vector2D Right = new(1f, 0f); + public readonly static Vector2D One = new(1f, 1f); + public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); From db8fe4984850efcf5c65a1fdc19b66a6fba113f0 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:34:13 +0300 Subject: [PATCH 42/81] fix: Forgotten Operator Overload for Multiplication --- Game/Physics2D/Primitives/Vector2D.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 6ce4f3a..ce8d62a 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -13,6 +13,7 @@ public record Vector2D(float X, float Y) public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); + public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value); public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value); public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector)); From a03470d043c78626726444fd3649baa19d1588ee Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:35:54 +0300 Subject: [PATCH 43/81] feat: - Operation Override --- Game/Physics2D/Primitives/Vector2D.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index ce8d62a..a1b80c7 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -10,6 +10,7 @@ public record Vector2D(float X, float Y) public readonly static Vector2D Right = new(1f, 0f); public readonly static Vector2D One = new(1f, 1f); + public static Vector2D operator -(Vector2D vector) => new(0f - vector.X, 0f - vector.Y); public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); From 0519adfcce8ae32a4ebd1f59571c41ef962940fc Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:40:24 +0300 Subject: [PATCH 44/81] feat: Vector2D.Reflect --- Game/Physics2D/Primitives/Vector2D.cs | 1 + Game/Physics2D/Primitives/Vector2DExtensions.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index a1b80c7..a1e3b34 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -23,6 +23,7 @@ public record Vector2D(float X, float Y) public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); + public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal; public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index c5266be..8a7cd02 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -6,6 +6,7 @@ public static class Vector2DExtensions public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); + public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal); public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.FromTo(vector, scale); From 8af2379afa33cde124237c7e28039e21105c4346 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:46:51 +0300 Subject: [PATCH 45/81] fix: Build Errors --- Game/Physics2D/PhysicsMath.cs | 22 +++++++++++----------- Game/Physics2D/Primitives/Line.cs | 2 +- Game/Physics2D/Primitives/Shape.cs | 10 +++++----- Game/Physics2D/Primitives/Triangle.cs | 4 ++-- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index b22d844..a19f014 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -19,15 +19,15 @@ public static class PhysicsMath foreach (Vector2 point in vertices) { - minX = Math.Min(minX, point.X); - minY = Math.Min(minY, point.Y); - maxX = Math.Max(maxX, point.X); - maxY = Math.Max(maxY, point.Y); + minX = MathF.Min(minX, point.X); + minY = MathF.Min(minY, point.Y); + maxX = MathF.Max(maxX, point.X); + maxY = MathF.Max(maxY, point.Y); } float dx = maxX - minX; float dy = maxY - minY; - float deltaMax = Math.Max(dx, dy); + float deltaMax = MathF.Max(dx, dy); float midX = (minX + maxX) / 2; float midY = (minY + maxY) / 2; @@ -61,8 +61,8 @@ public static class PhysicsMath // point q lies on line segment 'pr' public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r) { - if (q.X <= Math.Max(p.X, r.X) && q.X >= Math.Min(p.X, r.X) && - q.Y <= Math.Max(p.Y, r.Y) && q.Y >= Math.Min(p.Y, r.Y)) + if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) && + q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y)) return true; return false; @@ -102,13 +102,13 @@ public static class PhysicsMath return true; const float floatNormal = (1 << 23) * float.Epsilon; - float absA = Math.Abs(a); - float absB = Math.Abs(b); - float diff = Math.Abs(a - b); + float absA = MathF.Abs(a); + float absB = MathF.Abs(b); + float diff = MathF.Abs(a - b); if (a == 0.0f || b == 0.0f || diff < floatNormal) return diff < (epsilon * floatNormal); - return diff / Math.Min(absA + absB, float.MaxValue) < epsilon; + return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon; } } diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs index 02cc06f..4b61625 100644 --- a/Game/Physics2D/Primitives/Line.cs +++ b/Game/Physics2D/Primitives/Line.cs @@ -99,7 +99,7 @@ public record Line(Vector2 From, Vector2 To) float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); // Clamp t to the range [0, 1] to ensure the closest point is on the edge - t = Math.Max(0, Math.Min(1, t)); + t = MathF.Max(0, MathF.Min(1, t)); // Calculate the closest point on the edge float closestX = From.X + t * edgeVector.X; diff --git a/Game/Physics2D/Primitives/Shape.cs b/Game/Physics2D/Primitives/Shape.cs index bedc743..f5fa09b 100644 --- a/Game/Physics2D/Primitives/Shape.cs +++ b/Game/Physics2D/Primitives/Shape.cs @@ -16,15 +16,15 @@ public record Shape(IList Vertices) foreach (Vector2 point in Vertices) { - minX = Math.Min(minX, point.X); - minY = Math.Min(minY, point.Y); - maxX = Math.Max(maxX, point.X); - maxY = Math.Max(maxY, point.Y); + minX = MathF.Min(minX, point.X); + minY = MathF.Min(minY, point.Y); + maxX = MathF.Max(maxX, point.X); + maxY = MathF.Max(maxY, point.Y); } float dx = maxX - minX; float dy = maxY - minY; - float deltaMax = Math.Max(dx, dy); + float deltaMax = MathF.Max(dx, dy); float midX = (minX + maxX) / 2; float midY = (minY + maxY) / 2; diff --git a/Game/Physics2D/Primitives/Triangle.cs b/Game/Physics2D/Primitives/Triangle.cs index 6417951..7f01b8b 100644 --- a/Game/Physics2D/Primitives/Triangle.cs +++ b/Game/Physics2D/Primitives/Triangle.cs @@ -6,7 +6,7 @@ namespace Syntriax.Engine.Physics2D.Primitives; public record Triangle(Vector2 A, Vector2 B, Vector2 C) { - public float Area => Math.Abs(( + public float Area => MathF.Abs(( A.X * (B.Y - C.Y) + B.X * (C.Y - A.Y) + C.X * (A.Y - B.Y) @@ -23,7 +23,7 @@ public record Triangle(Vector2 A, Vector2 B, Vector2 C) float slopeBC = (C.Y - B.Y) / (C.X - B.X); Vector2 center; - if (Math.Abs(slopeAB - slopeBC) > float.Epsilon) + if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon) { float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB)); float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2; From 75e6e06099351c80220c6b923d00b936b0237ccd Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:48:26 +0300 Subject: [PATCH 46/81] fix: Reflect --- Game/Physics2D/Primitives/Vector2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index a1e3b34..82072ae 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -23,7 +23,7 @@ public record Vector2D(float X, float Y) public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); - public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal; + public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * (vector - Dot(vector, normal) * normal); public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); From 25e3c818cebf0bc54c045e591b54d3146cc026c6 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 18:49:51 +0300 Subject: [PATCH 47/81] chore: Vector2D.ToString() --- Game/Physics2D/Primitives/Vector2D.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 82072ae..0a562c1 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -30,4 +30,6 @@ public record Vector2D(float X, float Y) public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; + + public override string ToString() => $"Vector2D({X}, {Y})"; } From 3ddf6748e20042251fe713003e9121afde030fef Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:03:16 +0300 Subject: [PATCH 48/81] chore: Vector2D DebuggerDisplay --- Game/Physics2D/Primitives/Vector2D.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 0a562c1..7be741c 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -2,6 +2,7 @@ using System; namespace Syntriax.Engine.Physics2D.Primitives; +[System.Diagnostics.DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)},nq}}")] public record Vector2D(float X, float Y) { public readonly static Vector2D Up = new(0f, 1f); @@ -32,4 +33,8 @@ public record Vector2D(float X, float Y) public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; public override string ToString() => $"Vector2D({X}, {Y})"; + +#if DEBUG + private string GetDebuggerDisplay => $"{ToString()}, Length: {Length(this)}, LengthSquared: {LengthSquared(this)}, Normalized: {Normalize(this)}"; +#endif } From 30102f142cc0a9f0d2c0a5ba46ddaef3046137b1 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:07:50 +0300 Subject: [PATCH 49/81] feat: Vector2D Magnitude & MagnitudeSquared & Normalized Fields --- Game/Physics2D/Primitives/Vector2D.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 7be741c..1d967b7 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -5,6 +5,10 @@ namespace Syntriax.Engine.Physics2D.Primitives; [System.Diagnostics.DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)},nq}}")] public record Vector2D(float X, float Y) { + public float Magnitude => Length(this); + public float MagnitudeSquared => LengthSquared(this); + public Vector2D Normalized => Normalize(this); + public readonly static Vector2D Up = new(0f, 1f); public readonly static Vector2D Down = new(0f, -1f); public readonly static Vector2D Left = new(-1f, 0f); From c1ea190c02cbb4983c5176fc313ffb2f32a07c94 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:10:24 +0300 Subject: [PATCH 50/81] fix: Vector2D.Reflect --- Game/Physics2D/Primitives/Vector2D.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 1d967b7..554c419 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -28,7 +28,7 @@ public record Vector2D(float X, float Y) public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); - public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * (vector - Dot(vector, normal) * normal); + public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal; public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); From cd0a1002247eb7503f5cd7bdbfafcc1b18d0a2f2 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:15:02 +0300 Subject: [PATCH 51/81] chore: Better Debugger Display Declaration --- Game/Physics2D/Primitives/Vector2D.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 554c419..5c11b7b 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -2,7 +2,7 @@ using System; namespace Syntriax.Engine.Physics2D.Primitives; -[System.Diagnostics.DebuggerDisplay($"{{{nameof(GetDebuggerDisplay)},nq}}")] +[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")] public record Vector2D(float X, float Y) { public float Magnitude => Length(this); @@ -36,9 +36,5 @@ public record Vector2D(float X, float Y) public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; - public override string ToString() => $"Vector2D({X}, {Y})"; - -#if DEBUG - private string GetDebuggerDisplay => $"{ToString()}, Length: {Length(this)}, LengthSquared: {LengthSquared(this)}, Normalized: {Normalize(this)}"; -#endif + public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})"; } From 55bde3bafd212510e89004a6d29deb2984545b76 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:16:31 +0300 Subject: [PATCH 52/81] feat: Vector2D.Zero --- Game/Physics2D/Primitives/Vector2D.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 5c11b7b..63070ad 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -13,6 +13,7 @@ public record Vector2D(float X, float Y) public readonly static Vector2D Down = new(0f, -1f); public readonly static Vector2D Left = new(-1f, 0f); public readonly static Vector2D Right = new(1f, 0f); + public readonly static Vector2D Zero = new(0f, 0f); public readonly static Vector2D One = new(1f, 1f); public static Vector2D operator -(Vector2D vector) => new(0f - vector.X, 0f - vector.Y); From a83d983177680f7d84c3f2777f2a466ac0020141 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 19:23:16 +0300 Subject: [PATCH 53/81] feat: Vector2D Min, Max, Clamp & Lerp --- Game/Physics2D/Primitives/Math.cs | 2 ++ Game/Physics2D/Primitives/Vector2D.cs | 5 +++++ Game/Physics2D/Primitives/Vector2DExtensions.cs | 5 +++++ 3 files changed, 12 insertions(+) diff --git a/Game/Physics2D/Primitives/Math.cs b/Game/Physics2D/Primitives/Math.cs index 86ae4c9..79875d4 100644 --- a/Game/Physics2D/Primitives/Math.cs +++ b/Game/Physics2D/Primitives/Math.cs @@ -4,4 +4,6 @@ public static class Math { public const float RadianToDegree = 57.29577866666166f; public const float DegreeToRadian = 0.01745329277777778f; + + public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value; } diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs index 63070ad..720d1eb 100644 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ b/Game/Physics2D/Primitives/Vector2D.cs @@ -33,6 +33,11 @@ public record Vector2D(float X, float Y) public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); + public static Vector2D Min(Vector2D left, Vector2D right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y); + public static Vector2D Max(Vector2D left, Vector2D right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y); + public static Vector2D Clamp(Vector2D vector, Vector2D min, Vector2D max) => new(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y)); + public static Vector2D Lerp(Vector2D from, Vector2D to, float t) => from + FromTo(from, to) * t; + public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs index 8a7cd02..a0456e5 100644 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ b/Game/Physics2D/Primitives/Vector2DExtensions.cs @@ -11,6 +11,11 @@ public static class Vector2DExtensions public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.FromTo(vector, scale); + public static Vector2D Min(this Vector2D left, Vector2D right) => Vector2D.Min(left, right); + public static Vector2D Max(this Vector2D left, Vector2D right) => Vector2D.Max(left, right); + public static Vector2D Clamp(this Vector2D vector, Vector2D min, Vector2D max) => Vector2D.Clamp(vector, min, max); + public static Vector2D Lerp(this Vector2D from, Vector2D to, float t) => Vector2D.Lerp(from, to, t); + public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); From 0486b0343ad3c6dd55c5d3742e64486aa6beb74c Mon Sep 17 00:00:00 2001 From: Syntriax Date: Mon, 22 Jan 2024 23:47:47 +0300 Subject: [PATCH 54/81] First Unmonogame --- Engine | 2 +- Game/Behaviours/KeyboardInputsBehaviour.cs | 107 ++++++++++++++++++ Game/Behaviours/MonoGameCameraBehaviour.cs | 106 +++++++++++++++++ Game/Behaviours/MovementBallBehaviour.cs | 1 - Game/Game1.cs | 70 ++++++------ Game/Physics2D/Primitives/Vector2D.cs | 46 -------- .../Primitives/Vector2DExtensions.cs | 22 ---- 7 files changed, 249 insertions(+), 105 deletions(-) create mode 100644 Game/Behaviours/KeyboardInputsBehaviour.cs create mode 100644 Game/Behaviours/MonoGameCameraBehaviour.cs delete mode 100644 Game/Physics2D/Primitives/Vector2D.cs delete mode 100644 Game/Physics2D/Primitives/Vector2DExtensions.cs diff --git a/Engine b/Engine index c03d74d..485dfcc 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit c03d74dbe0949d75411cd368c8b07dbafd871a20 +Subproject commit 485dfcc51ea548a50eec57b003bc3cb31cfdf579 diff --git a/Game/Behaviours/KeyboardInputsBehaviour.cs b/Game/Behaviours/KeyboardInputsBehaviour.cs new file mode 100644 index 0000000..46bf534 --- /dev/null +++ b/Game/Behaviours/KeyboardInputsBehaviour.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; + +using Microsoft.Xna.Framework.Input; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Input; + +namespace Pong.Behaviours; + +public class KeyboardInputsBehaviour : BehaviourOverride, IButtonInputs +{ + private readonly Dictionary, Keys>> OnPressed = new(256); + private readonly Dictionary, Keys>> OnReleased = new(256); + + private int cachePressedCurrentlyCount = 0; + private readonly Keys[] cachePressedCurrently = new Keys[256]; + + private int cachePressedPreviouslyCount = 0; + private readonly Keys[] cachePressedPreviously = new Keys[256]; + + public void RegisterOnPress(Keys key, Action, Keys> callback) + { + if (OnPressed.TryGetValue(key, out var action)) + { + action += callback; + return; + } + + OnPressed.Add(key, callback); + } + + public void UnregisterOnPress(Keys key, Action, Keys> callback) + { + if (OnPressed.TryGetValue(key, out var action)) + action -= callback; + } + + public void RegisterOnRelease(Keys key, Action, Keys> callback) + { + if (OnReleased.TryGetValue(key, out var action)) + { + action += callback; + return; + } + + OnReleased.Add(key, callback); + } + + public void UnregisterOnRelease(Keys key, Action, Keys> callback) + { + if (OnReleased.TryGetValue(key, out var action)) + action -= callback; + } + + protected override void OnUpdate() + { + KeyboardState keyboardState = Keyboard.GetState(); + keyboardState.GetPressedKeys(cachePressedCurrently); + cachePressedCurrentlyCount = keyboardState.GetPressedKeyCount(); + + for (int i = 0; i < cachePressedCurrentlyCount; i++) + { + Keys currentlyPressedKey = cachePressedCurrently[i]; + + if (!OnPressed.TryGetValue(currentlyPressedKey, out var action)) + continue; + + if (WasPressed(currentlyPressedKey)) + continue; + + action.Invoke(this, currentlyPressedKey); + } + + for (int i = 0; i < cachePressedPreviouslyCount; i++) + { + Keys previouslyPressedKey = cachePressedPreviously[i]; + + if (!OnReleased.TryGetValue(previouslyPressedKey, out var action)) + continue; + + if (IsPressed(previouslyPressedKey)) + continue; + + action.Invoke(this, previouslyPressedKey); + } + + Array.Copy(cachePressedCurrently, cachePressedPreviously, cachePressedCurrentlyCount); + cachePressedPreviouslyCount = cachePressedCurrentlyCount; + } + + public bool IsPressed(Keys key) + { + for (int i = 0; i < cachePressedCurrentlyCount; i++) + if (cachePressedCurrently[i] == key) + return true; + return false; + } + + public bool WasPressed(Keys key) + { + for (int i = 0; i < cachePressedPreviouslyCount; i++) + if (cachePressedPreviously[i] == key) + return true; + return false; + } +} diff --git a/Game/Behaviours/MonoGameCameraBehaviour.cs b/Game/Behaviours/MonoGameCameraBehaviour.cs new file mode 100644 index 0000000..9cb088d --- /dev/null +++ b/Game/Behaviours/MonoGameCameraBehaviour.cs @@ -0,0 +1,106 @@ +using System; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; + +namespace Pong.Behaviours; + +public class MonoGameCameraBehaviour : BehaviourOverride, ICamera +{ + public Action? OnPositionChanged { get; set; } = null; + public Action? OnMatrixTransformChanged { get; set; } = null; + public Action? OnViewportChanged { get; set; } = null; + public Action? OnRotationChanged { get; set; } = null; + public Action? OnZoomChanged { get; set; } = null; + + private Matrix _matrixTransform = Matrix.Identity; + + private Viewport _viewport = default; + + private float _zoom = 1f; + + public Matrix MatrixTransform + { + get => _matrixTransform; + set + { + if (_matrixTransform == value) + return; + + _matrixTransform = value; + OnMatrixTransformChanged?.Invoke(this); + } + } + + public Vector2D Position + { + get => Transform.Position; + set => Transform.Position = value; + } + + public Viewport Viewport + { + get => _viewport; + set + { + if (_viewport.Equals(value)) + return; + + _viewport = value; + OnViewportChanged?.Invoke(this); + } + } + + public float Zoom + { + get => _zoom; + set + { + float newValue = value >= .1f ? value : .1f; + + if (_zoom == newValue) + return; + + _zoom = newValue; + OnZoomChanged?.Invoke(this); + } + } + + public float Rotation + { + get => Transform.Rotation; + set => Transform.Rotation = value; + } + public Action? OnTransformAssigned { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + ITransform IAssignableTransform.Transform => throw new NotImplementedException(); + + public void Update() + { + MatrixTransform = + Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) * + Matrix.CreateRotationZ(Rotation) * + Matrix.CreateScale(Zoom) * + Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f)); + } + + protected override void OnInitialize() + { + Transform.OnRotationChanged += OnTransformRotationChanged; + Transform.OnPositionChanged += OnTransformPositionChanged; + } + + protected override void OnFinalize() + { + Transform.OnRotationChanged -= OnTransformRotationChanged; + Transform.OnPositionChanged -= OnTransformPositionChanged; + } + + private void OnTransformRotationChanged(ITransform _) => OnRotationChanged?.Invoke(this); + private void OnTransformPositionChanged(ITransform _) => OnPositionChanged?.Invoke(this); + + public bool Assign(ITransform transform) => GameObject.Assign(transform); +} diff --git a/Game/Behaviours/MovementBallBehaviour.cs b/Game/Behaviours/MovementBallBehaviour.cs index d6c6b2a..ddfe614 100644 --- a/Game/Behaviours/MovementBallBehaviour.cs +++ b/Game/Behaviours/MovementBallBehaviour.cs @@ -6,7 +6,6 @@ using Syntriax.Engine.Input; using Syntriax.Engine.Physics2D.Abstract; namespace Pong.Behaviours; - public class MovementBallBehaviour(Vector2 StartDirection, float Speed) : BehaviourOverride { public Vector2 StartDirection { get; private set; } = Vector2.Normalize(StartDirection); diff --git a/Game/Game1.cs b/Game/Game1.cs index a1797ca..f8aff67 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -8,7 +8,6 @@ using Pong.Behaviours; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D.Primitives; @@ -55,84 +54,85 @@ public class Game1 : Game IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); gameObjectCamera.Name = "Camera"; - gameObjectCamera.Transform.Position = Vector2.Zero; + gameObjectCamera.Transform.Position = Vector2D.Zero; - gameManager.Camera = gameObjectCamera.BehaviourController.AddBehaviour(); - gameManager.Camera.Viewport = GraphicsDevice.Viewport; + MonoGameCameraBehaviour monoGameCameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour(); + monoGameCameraBehaviour.Viewport = GraphicsDevice.Viewport; + gameManager.Camera = monoGameCameraBehaviour; GameObject gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; - gameObjectBall.Transform.Position = Vector2.Zero; - gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + gameObjectBall.Transform.Position = Vector2D.Zero; + gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .1f), 500f); - gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .1f), 500f); + // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); // gameObjectBall = gameManager.InstantiateGameObject(); // gameObjectBall.Name = "Ball"; - // gameObjectBall.Transform.Position = Vector2.UnitY * 30f; - // gameObjectBall.Transform.Scale = new Vector2(1f / 51.2f, 1f / 51.2f); + // gameObjectBall.Transform.Position = Vector2D.UnitY * 30f; + // gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f); // engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - // gameObjectBall.BehaviourController.AddBehaviour(new Vector2(.1f, .01f), 500f); + // gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .01f), 500f); // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - // gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); + // gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f); // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); // gameObjectLeft.Name = "Left"; - // gameObjectLeft.Transform.Position = new Vector2(-452, 0f); - // gameObjectLeft.Transform.Scale = new Vector2(10f, 40f); + // gameObjectLeft.Transform.Position = new Vector2D(-452, 0f); + // gameObjectLeft.Transform.Scale = new Vector2D(10f, 40f); // gameObjectLeft.BehaviourController.AddBehaviour(); // gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); // gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - // gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + // gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); // engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); // IGameObject gameObjectRight = gameManager.InstantiateGameObject(); // gameObjectRight.Name = "Right"; - // gameObjectRight.Transform.Position = new Vector2(452, 0f); - // gameObjectRight.Transform.Scale = new Vector2(10f, 40f); + // gameObjectRight.Transform.Position = new Vector2D(452, 0f); + // gameObjectRight.Transform.Scale = new Vector2D(10f, 40f); // gameObjectRight.BehaviourController.AddBehaviour(); // gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); // gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); - // gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + // gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); // engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); - goPlayAreaTop.Transform.Position = new Vector2(0f, 288f + 20f); - goPlayAreaTop.Transform.Scale = new Vector2(10240f, 40f); + goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f); + goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f); // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); - goPlayAreaBottom.Transform.Position = new Vector2(0f, -(288f + 20f)); - goPlayAreaBottom.Transform.Scale = new Vector2(10240f, 40f); + goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f)); + goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f); // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); - goPlayAreaRight.Transform.Position = new Vector2(512f + 20f, 0f); - goPlayAreaRight.Transform.Scale = new Vector2(40f, 5760f); + goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f); + goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f); // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); - goPlayAreaLeft.Transform.Position = new Vector2(-(512f + 20f), 0f); - goPlayAreaLeft.Transform.Scale = new Vector2(40f, 5760f); + goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f); + goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f); // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * .5f, Vector2.One * .5f); + goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); - // goPlayAreaCenter.Transform.Position = new Vector2(100f, 100f); - // goPlayAreaCenter.Transform.Scale = new Vector2(40f, 40f); + // goPlayAreaCenter.Transform.Position = new Vector2D(100f, 100f); + // goPlayAreaCenter.Transform.Scale = new Vector2D(40f, 40f); // // goPlayAreaCenter.BehaviourController.AddBehaviour().Assign(spriteBox); // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour()); // TODO: use this.Content to load your game content here } - protected override void Update(GameTime gameTime) + protected override void Update(Microsoft.Xna.Framework.GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); @@ -160,9 +160,9 @@ public class Game1 : Game gameManager.Camera.Zoom -= gameTime.ElapsedGameTime.Nanoseconds * 0.00025f; if (Keyboard.GetState().IsKeyDown(Keys.Q)) - gameManager.Camera.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + gameManager.Camera.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.E)) - gameManager.Camera.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + gameManager.Camera.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.N)) { diff --git a/Game/Physics2D/Primitives/Vector2D.cs b/Game/Physics2D/Primitives/Vector2D.cs deleted file mode 100644 index 720d1eb..0000000 --- a/Game/Physics2D/Primitives/Vector2D.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System; - -namespace Syntriax.Engine.Physics2D.Primitives; - -[System.Diagnostics.DebuggerDisplay("{ToString(),nq}, Length: {Magnitude}, LengthSquared: {MagnitudeSquared}, Normalized: {Normalized}")] -public record Vector2D(float X, float Y) -{ - public float Magnitude => Length(this); - public float MagnitudeSquared => LengthSquared(this); - public Vector2D Normalized => Normalize(this); - - public readonly static Vector2D Up = new(0f, 1f); - public readonly static Vector2D Down = new(0f, -1f); - public readonly static Vector2D Left = new(-1f, 0f); - public readonly static Vector2D Right = new(1f, 0f); - public readonly static Vector2D Zero = new(0f, 0f); - public readonly static Vector2D One = new(1f, 1f); - - public static Vector2D operator -(Vector2D vector) => new(0f - vector.X, 0f - vector.Y); - public static Vector2D operator +(Vector2D left, Vector2D right) => new(left.X + right.X, left.Y + right.Y); - public static Vector2D operator -(Vector2D left, Vector2D right) => new(left.X - right.X, left.Y - right.Y); - public static Vector2D operator *(Vector2D vector, float value) => new(vector.X * value, vector.Y * value); - public static Vector2D operator *(float value, Vector2D vector) => new(vector.X * value, vector.Y * value); - public static Vector2D operator /(Vector2D vector, float value) => new(vector.X / value, vector.Y / value); - - public static float Length(Vector2D vector) => MathF.Sqrt(LengthSquared(vector)); - public static float LengthSquared(Vector2D vector) => vector.X * vector.X + vector.Y * vector.Y; - - public static float Distance(Vector2D from, Vector2D to) => Length(FromTo(from, to)); - - public static Vector2D Normalize(Vector2D vector) => vector / Length(vector); - public static Vector2D Reflect(Vector2D vector, Vector2D normal) => vector - 2f * Dot(vector, normal) * normal; - public static Vector2D FromTo(Vector2D from, Vector2D to) => to - from; - public static Vector2D Scale(Vector2D vector, Vector2D scale) => new(vector.X * scale.X, vector.Y * scale.Y); - - public static Vector2D Min(Vector2D left, Vector2D right) => new((left.X < right.X) ? left.X : right.X, (left.Y < right.Y) ? left.Y : right.Y); - public static Vector2D Max(Vector2D left, Vector2D right) => new((left.X > right.X) ? left.X : right.X, (left.Y > right.Y) ? left.Y : right.Y); - public static Vector2D Clamp(Vector2D vector, Vector2D min, Vector2D max) => new(Math.Clamp(vector.X, min.X, max.X), Math.Clamp(vector.Y, min.Y, max.Y)); - public static Vector2D Lerp(Vector2D from, Vector2D to, float t) => from + FromTo(from, to) * t; - - public static float Cross(Vector2D left, Vector2D right) => left.X * right.Y - left.Y * right.X; - public static float Angle(Vector2D left, Vector2D right) => MathF.Acos(Dot(left, right) / (Length(left) * Length(right))); - public static float Dot(Vector2D left, Vector2D right) => left.X * right.X + left.Y * right.Y; - - public override string ToString() => $"{nameof(Vector2D)}({X}, {Y})"; -} diff --git a/Game/Physics2D/Primitives/Vector2DExtensions.cs b/Game/Physics2D/Primitives/Vector2DExtensions.cs deleted file mode 100644 index a0456e5..0000000 --- a/Game/Physics2D/Primitives/Vector2DExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Primitives; - -public static class Vector2DExtensions -{ - public static float Length(this Vector2D vector) => Vector2D.Length(vector); - public static float LengthSquared(this Vector2D vector) => Vector2D.LengthSquared(vector); - public static float Distance(this Vector2D from, Vector2D to) => Vector2D.Distance(from, to); - - public static Vector2D Reflect(this Vector2D vector, Vector2D normal) => Vector2D.Reflect(vector, normal); - public static Vector2D Normalize(this Vector2D vector) => Vector2D.Normalize(vector); - public static Vector2D FromTo(this Vector2D from, Vector2D to) => Vector2D.FromTo(from, to); - public static Vector2D Scale(this Vector2D vector, Vector2D scale) => Vector2D.FromTo(vector, scale); - - public static Vector2D Min(this Vector2D left, Vector2D right) => Vector2D.Min(left, right); - public static Vector2D Max(this Vector2D left, Vector2D right) => Vector2D.Max(left, right); - public static Vector2D Clamp(this Vector2D vector, Vector2D min, Vector2D max) => Vector2D.Clamp(vector, min, max); - public static Vector2D Lerp(this Vector2D from, Vector2D to, float t) => Vector2D.Lerp(from, to, t); - - public static float Cross(this Vector2D left, Vector2D right) => Vector2D.Cross(left, right); - public static float AngleBetween(this Vector2D left, Vector2D right) => Vector2D.Angle(left, right); - public static float Dot(this Vector2D left, Vector2D right) => Vector2D.Dot(left, right); -} From ba284a199a3e3ed5880d4bd6885382a6e1318039 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:16:58 +0300 Subject: [PATCH 55/81] Engine DeMonoGame #2 --- Engine | 2 +- Game/Behaviours/MovementBallBehaviour.cs | 6 +-- Game/Behaviours/MovementBoxBehaviour.cs | 24 ++++++------ Game/EngineConverted.cs | 11 ++++++ Game/Game.csproj | 1 - Game/Game1.cs | 47 ++++++++++++----------- Game/Physics2D/Abstract/ICollider2D.cs | 7 ++-- Game/Physics2D/Abstract/IRigidBody2D.cs | 5 +-- Game/Physics2D/Collider2DAABBBehaviour.cs | 18 ++++----- Game/Physics2D/PhysicsEngine2D.cs | 20 +++++----- Game/Physics2D/PhysicsMath.cs | 32 ++++++++------- Game/Physics2D/Primitives/AABB.cs | 6 +-- Game/Physics2D/Primitives/Circle.cs | 6 +-- Game/Physics2D/Primitives/Line.cs | 44 ++++++++++----------- Game/Physics2D/Primitives/Shape.cs | 12 +++--- Game/Physics2D/Primitives/Triangle.cs | 16 ++++---- Game/Physics2D/RigidBody2D.cs | 2 +- 17 files changed, 135 insertions(+), 124 deletions(-) create mode 100644 Game/EngineConverted.cs diff --git a/Engine b/Engine index 485dfcc..39e553e 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 485dfcc51ea548a50eec57b003bc3cb31cfdf579 +Subproject commit 39e553ebbf61f398a3ed9a96b20f6819a197cd86 diff --git a/Game/Behaviours/MovementBallBehaviour.cs b/Game/Behaviours/MovementBallBehaviour.cs index ddfe614..063c79e 100644 --- a/Game/Behaviours/MovementBallBehaviour.cs +++ b/Game/Behaviours/MovementBallBehaviour.cs @@ -6,12 +6,12 @@ using Syntriax.Engine.Input; using Syntriax.Engine.Physics2D.Abstract; namespace Pong.Behaviours; -public class MovementBallBehaviour(Vector2 StartDirection, float Speed) : BehaviourOverride +public class MovementBallBehaviour(Vector2D StartDirection, float Speed) : BehaviourOverride { - public Vector2 StartDirection { get; private set; } = Vector2.Normalize(StartDirection); + public Vector2D StartDirection { get; private set; } = Vector2D.Normalize(StartDirection); public float Speed { get; set; } = Speed; - protected override void OnFirstActiveFrame(GameTime time) + protected override void OnFirstActiveFrame() { if (!BehaviourController.TryGetBehaviour(out IRigidBody2D? rigidBody)) throw new Exception($"Where's my {nameof(IRigidBody2D)}????"); diff --git a/Game/Behaviours/MovementBoxBehaviour.cs b/Game/Behaviours/MovementBoxBehaviour.cs index a2ebebc..fd9468a 100644 --- a/Game/Behaviours/MovementBoxBehaviour.cs +++ b/Game/Behaviours/MovementBoxBehaviour.cs @@ -17,25 +17,25 @@ public class MovementBoxBehaviour(Keys Up, Keys Down, float High, float Low, flo private bool isUpPressed = false; private bool isDownPressed = false; - private IKeyboardInputs inputs = null!; + private IButtonInputs inputs = null!; - protected override void OnUpdate(GameTime time) + protected override void OnUpdate() { if (isUpPressed && isDownPressed) return; if (isUpPressed) - GameObject.Transform.Position = GameObject.Transform.Position + Vector2.UnitY * (float)time.ElapsedGameTime.TotalSeconds * Speed; + GameObject.Transform.Position = GameObject.Transform.Position + Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed; else if (isDownPressed) - GameObject.Transform.Position = GameObject.Transform.Position + -Vector2.UnitY * (float)time.ElapsedGameTime.TotalSeconds * Speed; + GameObject.Transform.Position = GameObject.Transform.Position + -Vector2D.Up * (float)Time.Elapsed.TotalSeconds * Speed; - GameObject.Transform.Position = new Vector2(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low)); + GameObject.Transform.Position = new Vector2D(GameObject.Transform.Position.X, MathF.Max(MathF.Min(GameObject.Transform.Position.Y, High), Low)); } - protected override void OnFirstActiveFrame(GameTime time) + protected override void OnFirstActiveFrame() { - if (!BehaviourController.TryGetBehaviour(out var behaviourResult)) - throw new Exception($"{nameof(IKeyboardInputs)} is missing on ${GameObject.Name}."); + if (!BehaviourController.TryGetBehaviour>(out var behaviourResult)) + throw new Exception($"{nameof(IButtonInputs)} is missing on ${GameObject.Name}."); inputs = behaviourResult; @@ -55,8 +55,8 @@ public class MovementBoxBehaviour(Keys Up, Keys Down, float High, float Low, flo inputs.UnregisterOnRelease(Down, OnDownReleased); } - private void OnUpPressed(IKeyboardInputs inputs, Keys keys) => isUpPressed = true; - private void OnUpReleased(IKeyboardInputs inputs, Keys keys) => isUpPressed = false; - private void OnDownPressed(IKeyboardInputs inputs, Keys keys) => isDownPressed = true; - private void OnDownReleased(IKeyboardInputs inputs, Keys keys) => isDownPressed = false; + private void OnUpPressed(IButtonInputs inputs, Keys keys) => isUpPressed = true; + private void OnUpReleased(IButtonInputs inputs, Keys keys) => isUpPressed = false; + private void OnDownPressed(IButtonInputs inputs, Keys keys) => isDownPressed = true; + private void OnDownReleased(IButtonInputs inputs, Keys keys) => isDownPressed = false; } diff --git a/Game/EngineConverted.cs b/Game/EngineConverted.cs new file mode 100644 index 0000000..1a4173f --- /dev/null +++ b/Game/EngineConverted.cs @@ -0,0 +1,11 @@ +using System.Runtime.CompilerServices; +using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; + +namespace Pong; + +public static class EngineConverted +{ + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); +} diff --git a/Game/Game.csproj b/Game/Game.csproj index 9b23577..323a3f6 100644 --- a/Game/Game.csproj +++ b/Game/Game.csproj @@ -26,7 +26,6 @@ - diff --git a/Game/Game1.cs b/Game/Game1.cs index f8aff67..7e06d96 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -1,5 +1,4 @@ using System; - using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; @@ -19,7 +18,9 @@ public class Game1 : Game private PhysicsEngine2D engine; private SpriteBatch _spriteBatch = null!; public static GameManager gameManager = null!; - public static Sprite spriteBox = null!; + // public static Sprite spriteBox = null!; + private MonoGameCameraBehaviour cameraBehaviour; + public Game1() { @@ -49,16 +50,16 @@ public class Game1 : Game { _spriteBatch = new SpriteBatch(GraphicsDevice); - spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; - Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; + // spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + // Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); gameObjectCamera.Name = "Camera"; gameObjectCamera.Transform.Position = Vector2D.Zero; - MonoGameCameraBehaviour monoGameCameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour(); - monoGameCameraBehaviour.Viewport = GraphicsDevice.Viewport; - gameManager.Camera = monoGameCameraBehaviour; + cameraBehaviour = gameObjectCamera.BehaviourController.AddBehaviour(); + cameraBehaviour.Viewport = GraphicsDevice.Viewport; + gameManager.Camera = cameraBehaviour; GameObject gameObjectBall = gameManager.InstantiateGameObject(); gameObjectBall.Name = "Ball"; @@ -67,7 +68,7 @@ public class Game1 : Game engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .1f), 500f); // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2.One * 512f * .5f, Vector2.One * 512f * .5f); + gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f); // gameObjectBall = gameManager.InstantiateGameObject(); // gameObjectBall.Name = "Ball"; // gameObjectBall.Transform.Position = Vector2D.UnitY * 30f; @@ -102,26 +103,26 @@ public class Game1 : Game goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f); // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + // goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f); // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + // goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f); // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + // goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f); // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + // goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); @@ -132,7 +133,7 @@ public class Game1 : Game // TODO: use this.Content to load your game content here } - protected override void Update(Microsoft.Xna.Framework.GameTime gameTime) + protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); @@ -148,21 +149,21 @@ public class Game1 : Game _graphics.IsFullScreen = true; _graphics.ApplyChanges(); - float previousScreenSize = MathF.Sqrt(MathF.Pow(gameManager.Camera.Viewport.Width, 2f) + MathF.Pow(gameManager.Camera.Viewport.Height, 2f)); + float previousScreenSize = MathF.Sqrt(MathF.Pow(cameraBehaviour.Viewport.Width, 2f) + MathF.Pow(cameraBehaviour.Viewport.Height, 2f)); float currentScreenSize = MathF.Sqrt(MathF.Pow(GraphicsDevice.Viewport.Width, 2f) + MathF.Pow(GraphicsDevice.Viewport.Height, 2f)); - gameManager.Camera.Zoom /= previousScreenSize / currentScreenSize; - gameManager.Camera.Viewport = GraphicsDevice.Viewport; + cameraBehaviour.Zoom /= previousScreenSize / currentScreenSize; + cameraBehaviour.Viewport = GraphicsDevice.Viewport; } if (Keyboard.GetState().IsKeyDown(Keys.U)) - gameManager.Camera.Zoom += gameTime.ElapsedGameTime.Nanoseconds * 0.00025f; + cameraBehaviour.Zoom += gameTime.ElapsedGameTime.Nanoseconds * 0.00025f; if (Keyboard.GetState().IsKeyDown(Keys.J)) - gameManager.Camera.Zoom -= gameTime.ElapsedGameTime.Nanoseconds * 0.00025f; + cameraBehaviour.Zoom -= gameTime.ElapsedGameTime.Nanoseconds * 0.00025f; if (Keyboard.GetState().IsKeyDown(Keys.Q)) - gameManager.Camera.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.E)) - gameManager.Camera.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.N)) { @@ -210,7 +211,7 @@ public class Game1 : Game // physicsTimer += 0.01f; // engine.Step(.01f); // } - gameManager.Update(gameTime); + gameManager.Update(gameTime.ToEngineTime()); base.Update(gameTime); } static float physicsTimer = 0f; @@ -224,9 +225,9 @@ public class Game1 : Game // Console.WriteLine($"Pos: {gameManager.Camera.Position}"); // TODO: Add your drawing code here - gameManager.PreDraw(gameTime); + gameManager.PreDraw(); gameManager.Camera.Update(); - gameManager.Draw(_spriteBatch); + // gameManager.Draw(_spriteBatch); base.Draw(gameTime); } diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs index 64eba9b..a88a19f 100644 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ b/Game/Physics2D/Abstract/ICollider2D.cs @@ -1,8 +1,7 @@ using System; using System.Collections.Generic; -using Microsoft.Xna.Framework; - +using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Abstract; @@ -13,8 +12,8 @@ public interface ICollider2D : IBehaviour, IAssignableTransform IRigidBody2D? RigidBody2D { get; } - IList Vertices { get; } + IList Vertices { get; } - bool CheckCollision(Vector2 point); + bool CheckCollision(Vector2D point); void Recalculate(); } diff --git a/Game/Physics2D/Abstract/IRigidBody2D.cs b/Game/Physics2D/Abstract/IRigidBody2D.cs index 0881c48..820caa6 100644 --- a/Game/Physics2D/Abstract/IRigidBody2D.cs +++ b/Game/Physics2D/Abstract/IRigidBody2D.cs @@ -1,5 +1,4 @@ -using Microsoft.Xna.Framework; - +using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; namespace Syntriax.Engine.Physics2D.Abstract; @@ -8,7 +7,7 @@ public interface IRigidBody2D : IBehaviour, IAssignableTransform { IPhysicsMaterial2D Material { get; set; } - Vector2 Velocity { get; set; } + Vector2D Velocity { get; set; } float AngularVelocity { get; set; } float Mass { get; set; } diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs index ccb59d2..79fc368 100644 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ b/Game/Physics2D/Collider2DAABBBehaviour.cs @@ -1,8 +1,6 @@ using System; using System.Collections.Generic; -using Microsoft.Xna.Framework; - using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; @@ -16,7 +14,7 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D public AABB AABBWorld { get; private set; } = null!; private IRigidBody2D? _rigidBody2D = null; - private List _vertices = new List(4); + private List _vertices = new List(4); public IRigidBody2D? RigidBody2D { @@ -35,9 +33,9 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D ITransform IAssignableTransform.Transform => Transform; public bool Assign(ITransform transform) => GameObject.Assign(transform); - public IList Vertices => _vertices; + public IList Vertices => _vertices; - public bool CheckCollision(Vector2 point) + public bool CheckCollision(Vector2D point) { return AABBWorld.Overlaps(point); } @@ -51,11 +49,11 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D Vertices.Clear(); Vertices.Add(AABBWorld.LowerBoundary); - Vertices.Add(new Vector2(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); + Vertices.Add(new Vector2D(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); Vertices.Add(AABBWorld.UpperBoundary); - Vertices.Add(new Vector2(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); + Vertices.Add(new Vector2D(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); } - public Collider2DAABBBehaviour(Vector2 lowerBoundary, Vector2 upperBoundary) + public Collider2DAABBBehaviour(Vector2D lowerBoundary, Vector2D upperBoundary) { AABBLocal = new AABB(lowerBoundary, upperBoundary); AABBWorld = new AABB(lowerBoundary, upperBoundary); @@ -63,7 +61,7 @@ public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D public Collider2DAABBBehaviour() { - AABBLocal = new(Vector2.Zero, Vector2.Zero); - AABBWorld = new(Vector2.Zero, Vector2.Zero); + AABBLocal = new(Vector2D.Zero, Vector2D.Zero); + AABBWorld = new(Vector2D.Zero, Vector2D.Zero); } } diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index e1acfb6..4c0bb66 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; - +using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; using Syntriax.Engine.Physics2D.Primitives; @@ -60,7 +60,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D } } - private void ResolveCollision(ICollider2D c1, ICollider2D c2, Vector2 vertex, float intervalDeltaTime) + private void ResolveCollision(ICollider2D c1, ICollider2D c2, Vector2D vertex, float intervalDeltaTime) { if (c1.RigidBody2D is not IRigidBody2D) return; @@ -71,16 +71,16 @@ public class PhysicsEngine2D : IPhysicsEngine2D c2.Vertices.ToLines(lines); - Vector2 normal = Vector2.UnitY; + Vector2D normal = Vector2D.Up; float t = 1f; bool hasIntersectedWithLines = false; foreach (var line in lines) { - if (!vertexTrajectory.Intersects(line, out Vector2? intersectionPoint)) + if (!vertexTrajectory.Intersects(line, out Vector2D? intersectionPoint)) continue; - if (intersectionPoint is not Vector2 ip) + if (intersectionPoint is not Vector2D ip) continue; float tTemp = vertexTrajectory.GetT(ip); @@ -88,7 +88,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D continue; t = tTemp; - Vector2 lineDirection = line.Direction; + Vector2D lineDirection = line.Direction; normal = new(lineDirection.Y, lineDirection.X); hasIntersectedWithLines = true; } @@ -99,11 +99,11 @@ public class PhysicsEngine2D : IPhysicsEngine2D float rewindInterval = intervalDeltaTime - t * intervalDeltaTime; StepRigidBody(c1.RigidBody2D, -rewindInterval); - c1.RigidBody2D.Velocity = Vector2.Reflect(c1.RigidBody2D.Velocity, normal); + c1.RigidBody2D.Velocity = Vector2D.Reflect(c1.RigidBody2D.Velocity, normal); StepRigidBody(c1.RigidBody2D, rewindInterval); } - private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) + private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) { for (int i = 0; i < collider2Ds.Count; i++) { @@ -113,7 +113,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D for (int y = 0; y < collider2D.Vertices.Count; y++) { - Vector2 vertex = collider2D.Vertices[y]; + Vector2D vertex = collider2D.Vertices[y]; if (collider2DItem.CheckCollision(vertex)) { OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem, vertex); @@ -128,7 +128,7 @@ public class PhysicsEngine2D : IPhysicsEngine2D private void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) { - Vector2 nextPosition = rigidBody.Transform.Position; + Vector2D nextPosition = rigidBody.Transform.Position; nextPosition += rigidBody.Velocity * intervalDeltaTime; rigidBody.Transform.Position = nextPosition; diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs index a19f014..7ccd28c 100644 --- a/Game/Physics2D/PhysicsMath.cs +++ b/Game/Physics2D/PhysicsMath.cs @@ -2,22 +2,22 @@ using System; using System.Collections.Generic; using Microsoft.Xna.Framework; - +using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Primitives; namespace Syntriax.Engine.Physics2D; public static class PhysicsMath { - public static Vector2 Scale(this Vector2 original, Vector2 scale) - => new Vector2(original.X * scale.X, original.Y * scale.Y); + public static Vector2D Scale(this Vector2D original, Vector2D scale) + => new Vector2D(original.X * scale.X, original.Y * scale.Y); - public static Triangle ToSuperTriangle(this IList vertices) + public static Triangle ToSuperTriangle(this IList vertices) { float minX = float.MaxValue, minY = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue; - foreach (Vector2 point in vertices) + foreach (Vector2D point in vertices) { minX = MathF.Min(minX, point.X); minY = MathF.Min(minY, point.Y); @@ -31,21 +31,21 @@ public static class PhysicsMath float midX = (minX + maxX) / 2; float midY = (minY + maxY) / 2; - Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); - Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); - Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax); + Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); return new Triangle(p1, p2, p3); } - public static IList ToLines(this IList vertices) + public static IList ToLines(this IList vertices) { List lines = new List(vertices.Count - 1); ToLines(vertices, lines); return lines; } - public static void ToLines(this IList vertices, IList lines) + public static void ToLines(this IList vertices, IList lines) { lines.Clear(); for (int i = 0; i < vertices.Count - 1; i++) @@ -53,13 +53,13 @@ public static class PhysicsMath lines.Add(new(vertices[^1], vertices[0])); } - public static bool LaysOn(this Vector2 point, Line line) + public static bool LaysOn(this Vector2D point, Line line) => line.Resolve(point.X).ApproximatelyEquals(point); // Given three collinear points p, q, r, the function checks if // point q lies on line segment 'pr' - public static bool OnSegment(Vector2 p, Vector2 q, Vector2 r) + public static bool OnSegment(Vector2D p, Vector2D q, Vector2D r) { if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) && q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y)) @@ -73,7 +73,7 @@ public static class PhysicsMath // 0 --> p, q and r are collinear // 1 --> Clockwise // 2 --> Counterclockwise - public static int Orientation(Vector2 p, Vector2 q, Vector2 r) + public static int Orientation(Vector2D p, Vector2D q, Vector2D r) { // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ // for details of below formula. @@ -85,7 +85,7 @@ public static class PhysicsMath return (val > 0) ? 1 : 2; // clock or counterclock wise } - public static float IntersectionParameterT(Vector2 p0, Vector2 p1, Vector2 q0, Vector2 q1) + public static float IntersectionParameterT(Vector2D p0, Vector2D p1, Vector2D q0, Vector2D q1) => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); @@ -96,6 +96,10 @@ public static class PhysicsMath => ApproximatelyEquals(a, b, float.Epsilon); public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon) => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon); + public static bool ApproximatelyEquals(this Vector2D a, Vector2D b) + => ApproximatelyEquals(a, b, float.Epsilon); + public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon) + => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon); public static bool ApproximatelyEquals(this float a, float b, float epsilon) { if (a == b) diff --git a/Game/Physics2D/Primitives/AABB.cs b/Game/Physics2D/Primitives/AABB.cs index e6d3c28..96e1560 100644 --- a/Game/Physics2D/Primitives/AABB.cs +++ b/Game/Physics2D/Primitives/AABB.cs @@ -1,10 +1,10 @@ -using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record AABB(Vector2 LowerBoundary, Vector2 UpperBoundary) +public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) { - public bool Overlaps(Vector2 point) + public bool Overlaps(Vector2D point) => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X && point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y; diff --git a/Game/Physics2D/Primitives/Circle.cs b/Game/Physics2D/Primitives/Circle.cs index 386e651..1d30cf2 100644 --- a/Game/Physics2D/Primitives/Circle.cs +++ b/Game/Physics2D/Primitives/Circle.cs @@ -1,8 +1,8 @@ -using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Circle(Vector2 Position, float Radius) +public record Circle(Vector2D Position, float Radius) { public bool Intersects(Circle other) { @@ -12,7 +12,7 @@ public record Circle(Vector2 Position, float Radius) return distanceSquared < radiusSumSquared; } - public bool Overlaps(Vector2 point) => (Position - point).LengthSquared() <= Radius * Radius; + public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius; public bool ApproximatelyEquals(Circle other) => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius); } diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs index 4b61625..bd3162c 100644 --- a/Game/Physics2D/Primitives/Line.cs +++ b/Game/Physics2D/Primitives/Line.cs @@ -2,14 +2,14 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Line(Vector2 From, Vector2 To) +public record Line(Vector2D From, Vector2D To) { public Line Reversed => new(To, From); - public Vector2 Direction => Vector2.Normalize(To - From); + public Vector2D Direction => Vector2D.Normalize(To - From); public float Length => (From - To).Length(); public float LengthSquared => (From - To).LengthSquared(); @@ -17,7 +17,7 @@ public record Line(Vector2 From, Vector2 To) { get { - Vector2 slopeVector = To - From; + Vector2D slopeVector = To - From; float slope = slopeVector.Y / slopeVector.X; float yOffset = From.Y - (slope * From.X); @@ -26,10 +26,10 @@ public record Line(Vector2 From, Vector2 To) } } - public bool Intersects(Vector2 point) + public bool Intersects(Vector2D point) => Resolve(point.X).ApproximatelyEquals(point); - public float GetT(Vector2 point) + public float GetT(Vector2D point) { float fromX = MathF.Abs(From.X); float toX = MathF.Abs(To.X); @@ -51,18 +51,18 @@ public record Line(Vector2 From, Vector2 To) return t; } - public bool Exist(List vertices) + public bool Exist(List vertices) { for (int i = 0; i < vertices.Count - 1; i++) { - Vector2 vertexCurrent = vertices[i]; - Vector2 vertexNext = vertices[i]; + Vector2D vertexCurrent = vertices[i]; + Vector2D vertexNext = vertices[i]; if (From == vertexCurrent && To == vertexNext) return true; if (From == vertexNext && To == vertexCurrent) return true; } - Vector2 vertexFirst = vertices[0]; - Vector2 vertexLast = vertices[^1]; + Vector2D vertexFirst = vertices[0]; + Vector2D vertexLast = vertices[^1]; if (From == vertexFirst && To == vertexLast) return true; if (From == vertexLast && To == vertexFirst) return true; return false; @@ -80,20 +80,20 @@ public record Line(Vector2 From, Vector2 To) return numerator / denominator; } - public Vector2 Lerp(float t) - => new Vector2( + public Vector2D Lerp(float t) + => new Vector2D( From.X + (To.X - From.X) * t, From.Y + (To.Y - From.Y) * t ); - public Vector2 Resolve(float x) - => new Vector2(x, LineEquation.Resolve(x)); + public Vector2D Resolve(float x) + => new Vector2D(x, LineEquation.Resolve(x)); - public Vector2 ClosestPointTo(Vector2 point) + public Vector2D ClosestPointTo(Vector2D point) { // Convert edge points to vectors - var edgeVector = new Vector2(To.X - From.X, To.Y - From.Y); - var pointVector = new Vector2(point.X - From.X, point.Y - From.Y); + var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y); + var pointVector = new Vector2D(point.X - From.X, point.Y - From.Y); // Calculate the projection of pointVector onto edgeVector float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); @@ -105,11 +105,11 @@ public record Line(Vector2 From, Vector2 To) float closestX = From.X + t * edgeVector.X; float closestY = From.Y + t * edgeVector.Y; - return new Vector2((float)closestX, (float)closestY); + return new Vector2D((float)closestX, (float)closestY); } - public Vector2 IntersectionPoint(Line other) - => Vector2.Lerp(From, To, IntersectionParameterT(other)); + public Vector2D IntersectionPoint(Line other) + => Vector2D.Lerp(From, To, IntersectionParameterT(other)); public bool Intersects(Line other) { @@ -129,7 +129,7 @@ public record Line(Vector2 From, Vector2 To) return false; } - public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2? point) + public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point) { point = null; diff --git a/Game/Physics2D/Primitives/Shape.cs b/Game/Physics2D/Primitives/Shape.cs index f5fa09b..8ba8dbf 100644 --- a/Game/Physics2D/Primitives/Shape.cs +++ b/Game/Physics2D/Primitives/Shape.cs @@ -1,11 +1,11 @@ using System; using System.Collections.Generic; -using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Shape(IList Vertices) +public record Shape(IList Vertices) { public Triangle SuperTriangle { @@ -14,7 +14,7 @@ public record Shape(IList Vertices) float minX = float.MaxValue, minY = float.MaxValue; float maxX = float.MinValue, maxY = float.MinValue; - foreach (Vector2 point in Vertices) + foreach (Vector2D point in Vertices) { minX = MathF.Min(minX, point.X); minY = MathF.Min(minY, point.Y); @@ -28,9 +28,9 @@ public record Shape(IList Vertices) float midX = (minX + maxX) / 2; float midY = (minY + maxY) / 2; - Vector2 p1 = new Vector2((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); - Vector2 p2 = new Vector2((float)midX, (float)midY + 20 * (float)deltaMax); - Vector2 p3 = new Vector2((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); + Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax); + Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); return new Triangle(p1, p2, p3); } diff --git a/Game/Physics2D/Primitives/Triangle.cs b/Game/Physics2D/Primitives/Triangle.cs index 7f01b8b..5ffcd6a 100644 --- a/Game/Physics2D/Primitives/Triangle.cs +++ b/Game/Physics2D/Primitives/Triangle.cs @@ -1,10 +1,10 @@ using System; -using Microsoft.Xna.Framework; +using Syntriax.Engine.Core; namespace Syntriax.Engine.Physics2D.Primitives; -public record Triangle(Vector2 A, Vector2 B, Vector2 C) +public record Triangle(Vector2D A, Vector2D B, Vector2D C) { public float Area => MathF.Abs(( A.X * (B.Y - C.Y) + @@ -16,27 +16,27 @@ public record Triangle(Vector2 A, Vector2 B, Vector2 C) { get { - Vector2 midAB = (A + B) / 2; - Vector2 midBC = (B + C) / 2; + Vector2D midAB = (A + B) / 2; + Vector2D midBC = (B + C) / 2; float slopeAB = (B.Y - A.Y) / (B.X - A.X); float slopeBC = (C.Y - B.Y) / (C.X - B.X); - Vector2 center; + Vector2D center; if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon) { float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB)); float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2; - center = new Vector2(x, y); + center = new Vector2D(x, y); } else center = (midAB + midBC) * .5f; - return new(center, Vector2.Distance(center, A)); + return new(center, Vector2D.Distance(center, A)); } } - public bool Overlaps(Vector2 point) + public bool Overlaps(Vector2D point) { float originalTriangleArea = Area; diff --git a/Game/Physics2D/RigidBody2D.cs b/Game/Physics2D/RigidBody2D.cs index efc384d..454a3ab 100644 --- a/Game/Physics2D/RigidBody2D.cs +++ b/Game/Physics2D/RigidBody2D.cs @@ -15,7 +15,7 @@ public class RigidBody2D : BehaviourOverride, IRigidBody2D public IPhysicsMaterial2D Material { get; set; } = null!; - public Vector2 Velocity { get; set; } = Vector2.Zero; + public Vector2D Velocity { get; set; } = Vector2D.Zero; public float AngularVelocity { get; set; } = 0f; public float Mass { get; set; } = 0f; ITransform IAssignableTransform.Transform => Transform; From 8f6b48eb88dc6fc10000ce59d45eba41f588757f Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:17:14 +0300 Subject: [PATCH 56/81] style: Wrong Typed Class Name --- Game/{EngineConverted.cs => EngineConverter.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Game/{EngineConverted.cs => EngineConverter.cs} (89%) diff --git a/Game/EngineConverted.cs b/Game/EngineConverter.cs similarity index 89% rename from Game/EngineConverted.cs rename to Game/EngineConverter.cs index 1a4173f..3e75700 100644 --- a/Game/EngineConverted.cs +++ b/Game/EngineConverter.cs @@ -4,7 +4,7 @@ using Syntriax.Engine.Core; namespace Pong; -public static class EngineConverted +public static class EngineConverter { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); From 7c18ccf4c28491d212a521f28755b6f40c3afe10 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:15:24 +0300 Subject: [PATCH 57/81] chore: Added Back Graphics --- Engine | 2 +- Game/EngineConverter.cs | 4 + Game/Game1.cs | 30 +++-- .../Abstract/Assignable/IAssignableSprite.cs | 26 ++++ Game/Graphics/Abstract/ISprite.cs | 13 ++ Game/Graphics/Sprite.cs | 27 ++++ .../TwoDimensional/Abstract/IDisplayable.cs | 8 ++ .../Abstract/IDisplayableSprite.cs | 20 +++ .../DisplayableSpriteBehaviour.cs | 117 ++++++++++++++++++ 9 files changed, 236 insertions(+), 11 deletions(-) create mode 100644 Game/Graphics/Abstract/Assignable/IAssignableSprite.cs create mode 100644 Game/Graphics/Abstract/ISprite.cs create mode 100644 Game/Graphics/Sprite.cs create mode 100644 Game/Graphics/TwoDimensional/Abstract/IDisplayable.cs create mode 100644 Game/Graphics/TwoDimensional/Abstract/IDisplayableSprite.cs create mode 100644 Game/Graphics/TwoDimensional/DisplayableSpriteBehaviour.cs diff --git a/Engine b/Engine index 39e553e..d08495a 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 39e553ebbf61f398a3ed9a96b20f6819a197cd86 +Subproject commit d08495afbb7ca9f1afa2c8edcdaf0786bf095e9d diff --git a/Game/EngineConverter.cs b/Game/EngineConverter.cs index 3e75700..6e5aed4 100644 --- a/Game/EngineConverter.cs +++ b/Game/EngineConverter.cs @@ -8,4 +8,8 @@ public static class EngineConverter { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); } diff --git a/Game/Game1.cs b/Game/Game1.cs index 7e06d96..0144dc0 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -7,6 +7,7 @@ using Pong.Behaviours; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D.Primitives; @@ -18,8 +19,8 @@ public class Game1 : Game private PhysicsEngine2D engine; private SpriteBatch _spriteBatch = null!; public static GameManager gameManager = null!; - // public static Sprite spriteBox = null!; - private MonoGameCameraBehaviour cameraBehaviour; + public static Sprite spriteBox = null!; + private MonoGameCameraBehaviour cameraBehaviour = null!; public Game1() @@ -50,8 +51,8 @@ public class Game1 : Game { _spriteBatch = new SpriteBatch(GraphicsDevice); - // spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; - // Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; + spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); gameObjectCamera.Name = "Camera"; @@ -67,7 +68,7 @@ public class Game1 : Game gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f); engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .1f), 500f); - // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); + gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f); // gameObjectBall = gameManager.InstantiateGameObject(); // gameObjectBall.Name = "Ball"; @@ -102,26 +103,26 @@ public class Game1 : Game IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f); - // goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); // goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f); - // goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); // goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f); - // goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); // goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f); - // goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); + goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); // goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); @@ -227,7 +228,16 @@ public class Game1 : Game // TODO: Add your drawing code here gameManager.PreDraw(); gameManager.Camera.Update(); - // gameManager.Draw(_spriteBatch); + + _spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform); + foreach (IGameObject gameObject in gameManager) + { + if (!gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable)) + continue; + + displayable.Draw(_spriteBatch); + } + _spriteBatch.End(); base.Draw(gameTime); } diff --git a/Game/Graphics/Abstract/Assignable/IAssignableSprite.cs b/Game/Graphics/Abstract/Assignable/IAssignableSprite.cs new file mode 100644 index 0000000..8f05c68 --- /dev/null +++ b/Game/Graphics/Abstract/Assignable/IAssignableSprite.cs @@ -0,0 +1,26 @@ +using System; + +namespace Syntriax.Engine.Core.Abstract; + +/// +/// Indicates the object is an with an assignable field. +/// +public interface IAssignableSprite : IAssignable +{ + /// + /// Callback triggered when the value has has been assigned a new value. + /// + Action? OnSpriteAssigned { get; set; } + + /// + ISprite Sprite { get; } + + /// + /// Assign a value to the field of this object + /// + /// New to assign. + /// + /// , if the value given assigned successfully assigned, if not. + /// + bool Assign(ISprite sprite); +} diff --git a/Game/Graphics/Abstract/ISprite.cs b/Game/Graphics/Abstract/ISprite.cs new file mode 100644 index 0000000..feb19e8 --- /dev/null +++ b/Game/Graphics/Abstract/ISprite.cs @@ -0,0 +1,13 @@ +using System; + +using Microsoft.Xna.Framework.Graphics; + +namespace Syntriax.Engine.Core.Abstract; + +// TODO Probably gonna have to rethink this +public interface ISprite +{ + Action? OnTextureChanged { get; set; } + + Texture2D Texture2D { get; set; } +} diff --git a/Game/Graphics/Sprite.cs b/Game/Graphics/Sprite.cs new file mode 100644 index 0000000..5adcdd3 --- /dev/null +++ b/Game/Graphics/Sprite.cs @@ -0,0 +1,27 @@ +using System; + +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Core; + +public class Sprite : ISprite +{ + public Action? OnTextureChanged { get; set; } + + private Texture2D _texture = null!; + + public Texture2D Texture2D + { + get => _texture; + set + { + if (_texture == value) + return; + + _texture = value; + OnTextureChanged?.Invoke(this); + } + } +} diff --git a/Game/Graphics/TwoDimensional/Abstract/IDisplayable.cs b/Game/Graphics/TwoDimensional/Abstract/IDisplayable.cs new file mode 100644 index 0000000..d27a812 --- /dev/null +++ b/Game/Graphics/TwoDimensional/Abstract/IDisplayable.cs @@ -0,0 +1,8 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace Syntriax.Engine.Core.Abstract; + +public interface IDisplayable +{ + public void Draw(SpriteBatch spriteBatch); +} diff --git a/Game/Graphics/TwoDimensional/Abstract/IDisplayableSprite.cs b/Game/Graphics/TwoDimensional/Abstract/IDisplayableSprite.cs new file mode 100644 index 0000000..83b8215 --- /dev/null +++ b/Game/Graphics/TwoDimensional/Abstract/IDisplayableSprite.cs @@ -0,0 +1,20 @@ +using System; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core.Abstract; + +namespace Syntriax.Engine.Graphics.TwoDimensional.Abstract; +public interface IDisplayableSprite : IDisplayable, IAssignableSprite +{ + Action? OnSpriteEffectsChanged { get; set; } + Action? OnOriginChanged { get; set; } + Action? OnColorChanged { get; set; } + Action? OnDepthChanged { get; set; } + + SpriteEffects SpriteEffects { get; set; } + Vector2 Origin { get; set; } + Color Color { get; set; } + float Depth { get; set; } +} diff --git a/Game/Graphics/TwoDimensional/DisplayableSpriteBehaviour.cs b/Game/Graphics/TwoDimensional/DisplayableSpriteBehaviour.cs new file mode 100644 index 0000000..05b2d0d --- /dev/null +++ b/Game/Graphics/TwoDimensional/DisplayableSpriteBehaviour.cs @@ -0,0 +1,117 @@ +using System; + +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Graphics.TwoDimensional.Abstract; + +namespace Syntriax.Engine.Graphics.TwoDimensional; + +public class DisplayableSpriteBehaviour : Behaviour, IDisplayableSprite, IAssignableSprite +{ + public Action? OnSpriteAssigned { get; set; } = null; + public Action? OnSpriteEffectsChanged { get; set; } = null; + public Action? OnOriginChanged { get; set; } = null; + public Action? OnColorChanged { get; set; } = null; + public Action? OnDepthChanged { get; set; } = null; + + private ISprite _sprite = null!; + private Color _color = Color.White; + private float _depth = 0f; + private SpriteEffects _spriteEffects = SpriteEffects.None; + private Vector2 _origin = Vector2.One * .5f; + + + public ISprite Sprite => _sprite; + + public SpriteEffects SpriteEffects + { + get => _spriteEffects; + set + { + if (_spriteEffects == value) + return; + + _spriteEffects = value; + OnSpriteEffectsChanged?.Invoke(this); + } + } + + public Vector2 Origin + { + get => _origin; + set + { + if (_origin == value) + return; + + _origin = value; + OnOriginChanged?.Invoke(this); + } + } + + public Color Color + { + get => _color; + set + { + if (_color == value) + return; + + _color = value; + OnColorChanged?.Invoke(this); + } + } + + public float Depth + { + get => _depth; + set + { + if (_depth == value) + return; + + _depth = value; + OnDepthChanged?.Invoke(this); + } + } + + public void Draw(SpriteBatch spriteBatch) + { + if (!BehaviourController.GameObject.StateEnable.Enabled || !StateEnable.Enabled) + return; + + ITransform transform = BehaviourController.GameObject.Transform; + Vector2D position = transform.Position; + Vector2D scale = transform.Scale; + + Rectangle rectangle = new((int)position.X, -(int)position.Y, (int)(Sprite.Texture2D.Width * scale.X), (int)(Sprite.Texture2D.Height * scale.Y)); + + spriteBatch.Draw(Sprite.Texture2D, rectangle, null, Color, transform.Rotation, new Vector2(Sprite.Texture2D.Width, Sprite.Texture2D.Height) * Origin, SpriteEffects, Depth); + } + + public bool Assign(ISprite sprite) + { + _sprite = sprite; + OnSpriteAssigned?.Invoke(this); + return true; + } + + public DisplayableSpriteBehaviour() => OnUnassigned += OnUnassign; + public DisplayableSpriteBehaviour( + Color? color = null, + float? depth = null, + SpriteEffects? spriteEffects = null, + Vector2? origin = null) + { + OnUnassigned += OnUnassign; + + _color = color ?? _color; + _depth = depth ?? _depth; + _spriteEffects = spriteEffects ?? _spriteEffects; + _origin = origin ?? _origin; + } + private void OnUnassign(IAssignable assignable) => _sprite = null!; +} From b6b974feeb43f7439a80544d1897c17db18b471b Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:17:49 +0300 Subject: [PATCH 58/81] feat: Default Physic Materials --- Game/Physics2D/PhysicsMaterial2D.cs | 5 +++++ Game/Physics2D/PhysicsMaterial2DDefault.cs | 6 ++++++ Game/Physics2D/RigidBody2D.cs | 5 ++--- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 Game/Physics2D/PhysicsMaterial2D.cs create mode 100644 Game/Physics2D/PhysicsMaterial2DDefault.cs diff --git a/Game/Physics2D/PhysicsMaterial2D.cs b/Game/Physics2D/PhysicsMaterial2D.cs new file mode 100644 index 0000000..878691a --- /dev/null +++ b/Game/Physics2D/PhysicsMaterial2D.cs @@ -0,0 +1,5 @@ +using Syntriax.Engine.Physics2D.Abstract; + +namespace Syntriax.Engine.Physics2D; + +public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { } diff --git a/Game/Physics2D/PhysicsMaterial2DDefault.cs b/Game/Physics2D/PhysicsMaterial2DDefault.cs new file mode 100644 index 0000000..61b4367 --- /dev/null +++ b/Game/Physics2D/PhysicsMaterial2DDefault.cs @@ -0,0 +1,6 @@ +namespace Syntriax.Engine.Physics2D; + +public record PhysicsMaterial2DDefault : PhysicsMaterial2D +{ + public PhysicsMaterial2DDefault() : base(.1f, .1f) { } +} diff --git a/Game/Physics2D/RigidBody2D.cs b/Game/Physics2D/RigidBody2D.cs index 454a3ab..ed4fb4a 100644 --- a/Game/Physics2D/RigidBody2D.cs +++ b/Game/Physics2D/RigidBody2D.cs @@ -1,7 +1,5 @@ using System; -using Microsoft.Xna.Framework; - using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; @@ -13,11 +11,12 @@ public class RigidBody2D : BehaviourOverride, IRigidBody2D public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } - public IPhysicsMaterial2D Material { get; set; } = null!; + public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault(); public Vector2D Velocity { get; set; } = Vector2D.Zero; public float AngularVelocity { get; set; } = 0f; public float Mass { get; set; } = 0f; + ITransform IAssignableTransform.Transform => Transform; From 30612fc99510dcd254af06ce1f2153b5f2e40cbb Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:18:05 +0300 Subject: [PATCH 59/81] fix: Forgotten File --- Game/Physics2D/Abstract/IPhysicsMaterial2D.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs b/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs index 266545d..c533cda 100644 --- a/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs +++ b/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs @@ -2,6 +2,6 @@ namespace Syntriax.Engine.Physics2D.Abstract; public interface IPhysicsMaterial2D { - float Friction { get; set; } - float Restitution { get; set; } + float Friction { get; } + float Restitution { get; } } From 4ae9578123ea5b2434dbead7ab37dfc244e987d8 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:18:41 +0300 Subject: [PATCH 60/81] chore: Enabled Walls --- Game/Game1.cs | 8 ++++---- Game/Physics2D/PhysicsEngine2D.cs | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 0144dc0..5056882 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -104,26 +104,26 @@ public class Game1 : Game goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f); goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f); goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - // goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f)); goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f); goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - // goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f); goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f); goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - // goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f); goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f); goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - // goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); + goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 4c0bb66..6758039 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; -using Microsoft.Xna.Framework; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Abstract; From 64205353e5fccdd094627b4b662896d28c1d05a2 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:19:13 +0300 Subject: [PATCH 61/81] chore: Removed Old Physics Checks & Resolvers --- Game/Physics2D/PhysicsEngine2D.cs | 72 ------------------------------- 1 file changed, 72 deletions(-) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index 6758039..ecd8bd4 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -48,80 +48,8 @@ public class PhysicsEngine2D : IPhysicsEngine2D foreach (var rigidBody in rigidBodies) StepRigidBody(rigidBody, intervalDeltaTime); - foreach (var collider in colliders) collider.Recalculate(); - - for (int i = colliders.Count - 1; i >= 0; i--) - CheckCollisions(colliders[i], colliders, (collider1, collider2, collisionVertex) => - ResolveCollision(collider1, collider2, collisionVertex, intervalDeltaTime) - ); - } - } - - private void ResolveCollision(ICollider2D c1, ICollider2D c2, Vector2D vertex, float intervalDeltaTime) - { - if (c1.RigidBody2D is not IRigidBody2D) - return; - - Line vertexTrajectory = new Line(vertex - c1.RigidBody2D.Velocity * intervalDeltaTime, vertex); - if (vertexTrajectory.LengthSquared <= 0.001f) - return; - - c2.Vertices.ToLines(lines); - - Vector2D normal = Vector2D.Up; - float t = 1f; - bool hasIntersectedWithLines = false; - - foreach (var line in lines) - { - if (!vertexTrajectory.Intersects(line, out Vector2D? intersectionPoint)) - continue; - - if (intersectionPoint is not Vector2D ip) - continue; - - float tTemp = vertexTrajectory.GetT(ip); - if (tTemp > t) // React to the earliest collision value - continue; - - t = tTemp; - Vector2D lineDirection = line.Direction; - normal = new(lineDirection.Y, lineDirection.X); - hasIntersectedWithLines = true; - } - - if (!hasIntersectedWithLines) - return; - - float rewindInterval = intervalDeltaTime - t * intervalDeltaTime; - StepRigidBody(c1.RigidBody2D, -rewindInterval); - - c1.RigidBody2D.Velocity = Vector2D.Reflect(c1.RigidBody2D.Velocity, normal); - StepRigidBody(c1.RigidBody2D, rewindInterval); - } - - private void CheckCollisions(ICollider2D collider2D, List collider2Ds, Action OnCollisionDetectedAction) - { - for (int i = 0; i < collider2Ds.Count; i++) - { - ICollider2D collider2DItem = collider2Ds[i]; - if (collider2DItem == collider2D) - continue; - - for (int y = 0; y < collider2D.Vertices.Count; y++) - { - Vector2D vertex = collider2D.Vertices[y]; - if (collider2DItem.CheckCollision(vertex)) - { - OnCollisionDetectedAction?.Invoke(collider2D, collider2DItem, vertex); - OnCollisionDetectedAction?.Invoke(collider2DItem, collider2D, vertex); - collider2D.Recalculate(); - collider2DItem.Recalculate(); - y--; - } - } } } From 697e7c35b95b4567a9d68d93e226ce79a46735c5 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 12:20:43 +0300 Subject: [PATCH 62/81] refactor: StepRigidbody Method Improved --- Game/Physics2D/PhysicsEngine2D.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs index ecd8bd4..684bdeb 100644 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ b/Game/Physics2D/PhysicsEngine2D.cs @@ -37,8 +37,6 @@ public class PhysicsEngine2D : IPhysicsEngine2D rigidBodies.Remove(rigidBody); } - private List lines = new List(32); - public void Step(float deltaTime) { float intervalDeltaTime = deltaTime / IterationCount; @@ -53,12 +51,10 @@ public class PhysicsEngine2D : IPhysicsEngine2D } } - private void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) + private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) { - Vector2D nextPosition = rigidBody.Transform.Position; - nextPosition += rigidBody.Velocity * intervalDeltaTime; - - rigidBody.Transform.Position = nextPosition; + rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime; + rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime; } private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) From 8ea76f91f6223460af84739e009a5dc9a7bdb6b9 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 18:40:12 +0300 Subject: [PATCH 63/81] chore: Removed Physics Code --- Engine | 2 +- Game/Physics2D/Abstract/ICollider2D.cs | 19 --- .../Abstract/ICollisionResolver2D.cs | 6 - Game/Physics2D/Abstract/IPhysicsEngine2D.cs | 11 -- Game/Physics2D/Abstract/IPhysicsMaterial2D.cs | 7 - Game/Physics2D/Abstract/IRigidBody2D.cs | 14 -- Game/Physics2D/Collider2DAABBBehaviour.cs | 67 -------- Game/Physics2D/CollisionInformation.cs | 9 -- Game/Physics2D/PhysicsEngine2D.cs | 75 --------- Game/Physics2D/PhysicsMaterial2D.cs | 5 - Game/Physics2D/PhysicsMaterial2DDefault.cs | 6 - Game/Physics2D/PhysicsMath.cs | 118 -------------- Game/Physics2D/Primitives/AABB.cs | 17 -- Game/Physics2D/Primitives/Circle.cs | 18 --- Game/Physics2D/Primitives/Line.cs | 146 ------------------ Game/Physics2D/Primitives/LineEquation.cs | 8 - Game/Physics2D/Primitives/Math.cs | 9 -- Game/Physics2D/Primitives/Shape.cs | 68 -------- Game/Physics2D/Primitives/Triangle.cs | 54 ------- Game/Physics2D/RigidBody2D.cs | 24 --- 20 files changed, 1 insertion(+), 682 deletions(-) delete mode 100644 Game/Physics2D/Abstract/ICollider2D.cs delete mode 100644 Game/Physics2D/Abstract/ICollisionResolver2D.cs delete mode 100644 Game/Physics2D/Abstract/IPhysicsEngine2D.cs delete mode 100644 Game/Physics2D/Abstract/IPhysicsMaterial2D.cs delete mode 100644 Game/Physics2D/Abstract/IRigidBody2D.cs delete mode 100644 Game/Physics2D/Collider2DAABBBehaviour.cs delete mode 100644 Game/Physics2D/CollisionInformation.cs delete mode 100644 Game/Physics2D/PhysicsEngine2D.cs delete mode 100644 Game/Physics2D/PhysicsMaterial2D.cs delete mode 100644 Game/Physics2D/PhysicsMaterial2DDefault.cs delete mode 100644 Game/Physics2D/PhysicsMath.cs delete mode 100644 Game/Physics2D/Primitives/AABB.cs delete mode 100644 Game/Physics2D/Primitives/Circle.cs delete mode 100644 Game/Physics2D/Primitives/Line.cs delete mode 100644 Game/Physics2D/Primitives/LineEquation.cs delete mode 100644 Game/Physics2D/Primitives/Math.cs delete mode 100644 Game/Physics2D/Primitives/Shape.cs delete mode 100644 Game/Physics2D/Primitives/Triangle.cs delete mode 100644 Game/Physics2D/RigidBody2D.cs diff --git a/Engine b/Engine index d08495a..a948547 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit d08495afbb7ca9f1afa2c8edcdaf0786bf095e9d +Subproject commit a9485475c7583a626801e7ae15550d34bd02f8dd diff --git a/Game/Physics2D/Abstract/ICollider2D.cs b/Game/Physics2D/Abstract/ICollider2D.cs deleted file mode 100644 index a88a19f..0000000 --- a/Game/Physics2D/Abstract/ICollider2D.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System; -using System.Collections.Generic; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; - -namespace Syntriax.Engine.Physics2D.Abstract; - -public interface ICollider2D : IBehaviour, IAssignableTransform -{ - Action? OnCollisionPreResolve { get; set; } - - IRigidBody2D? RigidBody2D { get; } - - IList Vertices { get; } - - bool CheckCollision(Vector2D point); - void Recalculate(); -} diff --git a/Game/Physics2D/Abstract/ICollisionResolver2D.cs b/Game/Physics2D/Abstract/ICollisionResolver2D.cs deleted file mode 100644 index 83d54b4..0000000 --- a/Game/Physics2D/Abstract/ICollisionResolver2D.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Abstract; - -public interface ICollisionResolver2D -{ - void ResolveCollision(ICollider2D colliderA, ICollider2D colliderB); -} diff --git a/Game/Physics2D/Abstract/IPhysicsEngine2D.cs b/Game/Physics2D/Abstract/IPhysicsEngine2D.cs deleted file mode 100644 index aed1d10..0000000 --- a/Game/Physics2D/Abstract/IPhysicsEngine2D.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Abstract; - -public interface IPhysicsEngine2D -{ - int IterationCount { get; set; } - - void AddRigidBody(IRigidBody2D rigidBody); - void RemoveRigidBody(IRigidBody2D rigidBody); - - void Step(float deltaTime); -} diff --git a/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs b/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs deleted file mode 100644 index c533cda..0000000 --- a/Game/Physics2D/Abstract/IPhysicsMaterial2D.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Abstract; - -public interface IPhysicsMaterial2D -{ - float Friction { get; } - float Restitution { get; } -} diff --git a/Game/Physics2D/Abstract/IRigidBody2D.cs b/Game/Physics2D/Abstract/IRigidBody2D.cs deleted file mode 100644 index 820caa6..0000000 --- a/Game/Physics2D/Abstract/IRigidBody2D.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; - -namespace Syntriax.Engine.Physics2D.Abstract; - -public interface IRigidBody2D : IBehaviour, IAssignableTransform -{ - IPhysicsMaterial2D Material { get; set; } - - Vector2D Velocity { get; set; } - float AngularVelocity { get; set; } - - float Mass { get; set; } -} diff --git a/Game/Physics2D/Collider2DAABBBehaviour.cs b/Game/Physics2D/Collider2DAABBBehaviour.cs deleted file mode 100644 index 79fc368..0000000 --- a/Game/Physics2D/Collider2DAABBBehaviour.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System; -using System.Collections.Generic; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Physics2D.Abstract; -using Syntriax.Engine.Physics2D.Primitives; - -namespace Syntriax.Engine.Physics2D; - -public class Collider2DAABBBehaviour : BehaviourOverride, ICollider2D -{ - public AABB AABBLocal { get; set; } = null!; - public AABB AABBWorld { get; private set; } = null!; - - private IRigidBody2D? _rigidBody2D = null; - private List _vertices = new List(4); - - public IRigidBody2D? RigidBody2D - { - get - { - if (_rigidBody2D is null) - BehaviourController.TryGetBehaviour(out _rigidBody2D); - - return _rigidBody2D; - } - } - - public Action? OnCollisionPreResolve { get; set; } = null; - - public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } - ITransform IAssignableTransform.Transform => Transform; - public bool Assign(ITransform transform) => GameObject.Assign(transform); - - public IList Vertices => _vertices; - - public bool CheckCollision(Vector2D point) - { - return AABBWorld.Overlaps(point); - } - - public void Recalculate() - { - AABBWorld = new AABB( - AABBLocal.LowerBoundary.Scale(Transform.Scale) + Transform.Position, - AABBLocal.UpperBoundary.Scale(Transform.Scale) + Transform.Position - ); - - Vertices.Clear(); - Vertices.Add(AABBWorld.LowerBoundary); - Vertices.Add(new Vector2D(AABBWorld.LowerBoundary.X, AABBWorld.UpperBoundary.Y)); - Vertices.Add(AABBWorld.UpperBoundary); - Vertices.Add(new Vector2D(AABBWorld.UpperBoundary.X, AABBWorld.LowerBoundary.Y)); - } - public Collider2DAABBBehaviour(Vector2D lowerBoundary, Vector2D upperBoundary) - { - AABBLocal = new AABB(lowerBoundary, upperBoundary); - AABBWorld = new AABB(lowerBoundary, upperBoundary); - } - - public Collider2DAABBBehaviour() - { - AABBLocal = new(Vector2D.Zero, Vector2D.Zero); - AABBWorld = new(Vector2D.Zero, Vector2D.Zero); - } -} diff --git a/Game/Physics2D/CollisionInformation.cs b/Game/Physics2D/CollisionInformation.cs deleted file mode 100644 index 24d561d..0000000 --- a/Game/Physics2D/CollisionInformation.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Microsoft.Xna.Framework; - -namespace Syntriax.Engine.Physics2D; - -public record CollisionInformation -( - Vector2 Normal, - Vector2 ContactPosition -); diff --git a/Game/Physics2D/PhysicsEngine2D.cs b/Game/Physics2D/PhysicsEngine2D.cs deleted file mode 100644 index 684bdeb..0000000 --- a/Game/Physics2D/PhysicsEngine2D.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Physics2D.Abstract; -using Syntriax.Engine.Physics2D.Primitives; - -namespace Syntriax.Engine.Physics2D; - -public class PhysicsEngine2D : IPhysicsEngine2D -{ - private List rigidBodies = new List(32); - private List colliders = new List(64); - - private int _iterationCount = 1; - - - public int IterationCount { get => _iterationCount; set => _iterationCount = value < 1 ? 1 : value; } - - public void AddRigidBody(IRigidBody2D rigidBody) - { - if (rigidBodies.Contains(rigidBody)) - return; - - rigidBodies.Add(rigidBody); - - foreach (var collider2D in rigidBody.BehaviourController.GetBehaviours()) - colliders.Add(collider2D); - - rigidBody.BehaviourController.OnBehaviourAdded += OnBehaviourAdded; - rigidBody.BehaviourController.OnBehaviourRemoved += OnBehaviourRemoved; - } - - public void RemoveRigidBody(IRigidBody2D rigidBody) - { - rigidBodies.Remove(rigidBody); - } - - public void Step(float deltaTime) - { - float intervalDeltaTime = deltaTime / IterationCount; - - for (int iterationIndex = 0; iterationIndex < IterationCount; iterationIndex++) - { - foreach (var rigidBody in rigidBodies) - StepRigidBody(rigidBody, intervalDeltaTime); - - foreach (var collider in colliders) - collider.Recalculate(); - } - } - - private static void StepRigidBody(IRigidBody2D rigidBody, float intervalDeltaTime) - { - rigidBody.Transform.Position += rigidBody.Velocity * intervalDeltaTime; - rigidBody.Transform.Rotation += rigidBody.AngularVelocity * intervalDeltaTime; - } - - private void OnBehaviourAdded(IBehaviourController controller, IBehaviour behaviour) - { - if (behaviour is not ICollider2D collider2D) - return; - - colliders.Add(collider2D); - } - - private void OnBehaviourRemoved(IBehaviourController controller, IBehaviour behaviour) - { - if (behaviour is not ICollider2D collider2D) - return; - - colliders.Remove(collider2D); - } -} diff --git a/Game/Physics2D/PhysicsMaterial2D.cs b/Game/Physics2D/PhysicsMaterial2D.cs deleted file mode 100644 index 878691a..0000000 --- a/Game/Physics2D/PhysicsMaterial2D.cs +++ /dev/null @@ -1,5 +0,0 @@ -using Syntriax.Engine.Physics2D.Abstract; - -namespace Syntriax.Engine.Physics2D; - -public record PhysicsMaterial2D(float Friction, float Restitution) : IPhysicsMaterial2D { } diff --git a/Game/Physics2D/PhysicsMaterial2DDefault.cs b/Game/Physics2D/PhysicsMaterial2DDefault.cs deleted file mode 100644 index 61b4367..0000000 --- a/Game/Physics2D/PhysicsMaterial2DDefault.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Syntriax.Engine.Physics2D; - -public record PhysicsMaterial2DDefault : PhysicsMaterial2D -{ - public PhysicsMaterial2DDefault() : base(.1f, .1f) { } -} diff --git a/Game/Physics2D/PhysicsMath.cs b/Game/Physics2D/PhysicsMath.cs deleted file mode 100644 index 7ccd28c..0000000 --- a/Game/Physics2D/PhysicsMath.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.Collections.Generic; - -using Microsoft.Xna.Framework; -using Syntriax.Engine.Core; -using Syntriax.Engine.Physics2D.Primitives; - -namespace Syntriax.Engine.Physics2D; - -public static class PhysicsMath -{ - public static Vector2D Scale(this Vector2D original, Vector2D scale) - => new Vector2D(original.X * scale.X, original.Y * scale.Y); - - public static Triangle ToSuperTriangle(this IList vertices) - { - float minX = float.MaxValue, minY = float.MaxValue; - float maxX = float.MinValue, maxY = float.MinValue; - - foreach (Vector2D point in vertices) - { - minX = MathF.Min(minX, point.X); - minY = MathF.Min(minY, point.Y); - maxX = MathF.Max(maxX, point.X); - maxY = MathF.Max(maxY, point.Y); - } - - float dx = maxX - minX; - float dy = maxY - minY; - float deltaMax = MathF.Max(dx, dy); - float midX = (minX + maxX) / 2; - float midY = (minY + maxY) / 2; - - Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); - Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax); - Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); - - return new Triangle(p1, p2, p3); - } - - public static IList ToLines(this IList vertices) - { - List lines = new List(vertices.Count - 1); - ToLines(vertices, lines); - return lines; - } - - public static void ToLines(this IList vertices, IList lines) - { - lines.Clear(); - for (int i = 0; i < vertices.Count - 1; i++) - lines.Add(new(vertices[i], vertices[i + 1])); - lines.Add(new(vertices[^1], vertices[0])); - } - - public static bool LaysOn(this Vector2D point, Line line) - => line.Resolve(point.X).ApproximatelyEquals(point); - - - // Given three collinear points p, q, r, the function checks if - // point q lies on line segment 'pr' - public static bool OnSegment(Vector2D p, Vector2D q, Vector2D r) - { - if (q.X <= MathF.Max(p.X, r.X) && q.X >= MathF.Min(p.X, r.X) && - q.Y <= MathF.Max(p.Y, r.Y) && q.Y >= MathF.Min(p.Y, r.Y)) - return true; - - return false; - } - - // To find orientation of ordered triplet (p, q, r). - // The function returns following values - // 0 --> p, q and r are collinear - // 1 --> Clockwise - // 2 --> Counterclockwise - public static int Orientation(Vector2D p, Vector2D q, Vector2D r) - { - // See https://www.geeksforgeeks.org/orientation-3-ordered-points/ - // for details of below formula. - float val = (q.Y - p.Y) * (r.X - q.X) - - (q.X - p.X) * (r.Y - q.Y); - - if (val == 0) return 0; // collinear - - return (val > 0) ? 1 : 2; // clock or counterclock wise - } - - public static float IntersectionParameterT(Vector2D p0, Vector2D p1, Vector2D q0, Vector2D q1) - => ((q0.X - p0.X) * (p1.Y - p0.Y) - (q0.Y - p0.Y) * (p1.X - p0.X)) / - ((q1.Y - q0.Y) * (p1.X - p0.X) - (q1.X - q0.X) * (p1.Y - p0.Y)); - - - public static bool ApproximatelyEquals(this float a, float b) - => ApproximatelyEquals(a, b, float.Epsilon); - public static bool ApproximatelyEquals(this Vector2 a, Vector2 b) - => ApproximatelyEquals(a, b, float.Epsilon); - public static bool ApproximatelyEquals(this Vector2 a, Vector2 b, float epsilon) - => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon); - public static bool ApproximatelyEquals(this Vector2D a, Vector2D b) - => ApproximatelyEquals(a, b, float.Epsilon); - public static bool ApproximatelyEquals(this Vector2D a, Vector2D b, float epsilon) - => ApproximatelyEquals(a.X, b.X, epsilon) && ApproximatelyEquals(a.Y, b.Y, epsilon); - public static bool ApproximatelyEquals(this float a, float b, float epsilon) - { - if (a == b) - return true; - - const float floatNormal = (1 << 23) * float.Epsilon; - float absA = MathF.Abs(a); - float absB = MathF.Abs(b); - float diff = MathF.Abs(a - b); - - if (a == 0.0f || b == 0.0f || diff < floatNormal) - return diff < (epsilon * floatNormal); - - return diff / MathF.Min(absA + absB, float.MaxValue) < epsilon; - } -} diff --git a/Game/Physics2D/Primitives/AABB.cs b/Game/Physics2D/Primitives/AABB.cs deleted file mode 100644 index 96e1560..0000000 --- a/Game/Physics2D/Primitives/AABB.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record AABB(Vector2D LowerBoundary, Vector2D UpperBoundary) -{ - public bool Overlaps(Vector2D point) - => point.X >= LowerBoundary.X && point.X <= UpperBoundary.X && - point.Y >= LowerBoundary.Y && point.Y <= UpperBoundary.Y; - - public bool Overlaps(AABB other) - => LowerBoundary.X <= other.UpperBoundary.X && UpperBoundary.X >= other.LowerBoundary.X && - LowerBoundary.Y <= other.UpperBoundary.Y && UpperBoundary.Y >= other.LowerBoundary.Y; - - public bool ApproximatelyEquals(AABB other) - => LowerBoundary.ApproximatelyEquals(other.LowerBoundary) && UpperBoundary.ApproximatelyEquals(other.UpperBoundary); -} diff --git a/Game/Physics2D/Primitives/Circle.cs b/Game/Physics2D/Primitives/Circle.cs deleted file mode 100644 index 1d30cf2..0000000 --- a/Game/Physics2D/Primitives/Circle.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record Circle(Vector2D Position, float Radius) -{ - public bool Intersects(Circle other) - { - float distanceSquared = (Position - other.Position).LengthSquared(); - float radiusSumSquared = Radius * Radius + other.Radius * other.Radius; - - return distanceSquared < radiusSumSquared; - } - - public bool Overlaps(Vector2D point) => (Position - point).LengthSquared() <= Radius * Radius; - public bool ApproximatelyEquals(Circle other) - => Position.ApproximatelyEquals(other.Position) && Radius.ApproximatelyEquals(other.Radius); -} diff --git a/Game/Physics2D/Primitives/Line.cs b/Game/Physics2D/Primitives/Line.cs deleted file mode 100644 index bd3162c..0000000 --- a/Game/Physics2D/Primitives/Line.cs +++ /dev/null @@ -1,146 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; - -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record Line(Vector2D From, Vector2D To) -{ - public Line Reversed => new(To, From); - public Vector2D Direction => Vector2D.Normalize(To - From); - public float Length => (From - To).Length(); - public float LengthSquared => (From - To).LengthSquared(); - - public LineEquation LineEquation - { - get - { - Vector2D slopeVector = To - From; - float slope = slopeVector.Y / slopeVector.X; - - float yOffset = From.Y - (slope * From.X); - - return new LineEquation(slope, yOffset); - } - } - - public bool Intersects(Vector2D point) - => Resolve(point.X).ApproximatelyEquals(point); - - public float GetT(Vector2D point) - { - float fromX = MathF.Abs(From.X); - float toX = MathF.Abs(To.X); - float pointX = MathF.Abs(point.X); - - float min = MathF.Min(fromX, toX); - float max = MathF.Max(fromX, toX) - min; - - pointX -= min; - - float t = pointX / max; - - // FIXME - // I don't even know, apparently whatever I wrote up there doesn't take into account of the direction of the line - // Which... I can see how, but I am also not sure how I can make it take into account. Or actually I'm for some reason - // too unmotivated to find a solution. Future me, find a better way if possible, please. - if (!Lerp(t).ApproximatelyEquals(point)) - return 1f - t; - return t; - } - - public bool Exist(List vertices) - { - for (int i = 0; i < vertices.Count - 1; i++) - { - Vector2D vertexCurrent = vertices[i]; - Vector2D vertexNext = vertices[i]; - if (From == vertexCurrent && To == vertexNext) return true; - if (From == vertexNext && To == vertexCurrent) return true; - } - - Vector2D vertexFirst = vertices[0]; - Vector2D vertexLast = vertices[^1]; - if (From == vertexFirst && To == vertexLast) return true; - if (From == vertexLast && To == vertexFirst) return true; - return false; - } - - public float IntersectionParameterT(Line other) - { - float numerator = (From.X - other.From.X) * (other.From.Y - other.To.Y) - (From.Y - other.From.Y) * (other.From.X - other.To.X); - float denominator = (From.X - To.X) * (other.From.Y - other.To.Y) - (From.Y - To.Y) * (other.From.X - other.To.X); - - // Lines are parallel - if (denominator == 0) - return float.NaN; - - return numerator / denominator; - } - - public Vector2D Lerp(float t) - => new Vector2D( - From.X + (To.X - From.X) * t, - From.Y + (To.Y - From.Y) * t - ); - - public Vector2D Resolve(float x) - => new Vector2D(x, LineEquation.Resolve(x)); - - public Vector2D ClosestPointTo(Vector2D point) - { - // Convert edge points to vectors - var edgeVector = new Vector2D(To.X - From.X, To.Y - From.Y); - var pointVector = new Vector2D(point.X - From.X, point.Y - From.Y); - - // Calculate the projection of pointVector onto edgeVector - float t = (pointVector.X * edgeVector.X + pointVector.Y * edgeVector.Y) / (edgeVector.X * edgeVector.X + edgeVector.Y * edgeVector.Y); - - // Clamp t to the range [0, 1] to ensure the closest point is on the edge - t = MathF.Max(0, MathF.Min(1, t)); - - // Calculate the closest point on the edge - float closestX = From.X + t * edgeVector.X; - float closestY = From.Y + t * edgeVector.Y; - - return new Vector2D((float)closestX, (float)closestY); - } - - public Vector2D IntersectionPoint(Line other) - => Vector2D.Lerp(From, To, IntersectionParameterT(other)); - - public bool Intersects(Line other) - { - int o1 = PhysicsMath.Orientation(From, To, other.From); - int o2 = PhysicsMath.Orientation(From, To, other.To); - int o3 = PhysicsMath.Orientation(other.From, other.To, From); - int o4 = PhysicsMath.Orientation(other.From, other.To, To); - - if (o1 != o2 && o3 != o4) - return true; - - if (o1 == 0 && PhysicsMath.OnSegment(From, other.From, To)) return true; - if (o2 == 0 && PhysicsMath.OnSegment(From, other.To, To)) return true; - if (o3 == 0 && PhysicsMath.OnSegment(other.From, From, other.To)) return true; - if (o4 == 0 && PhysicsMath.OnSegment(other.From, To, other.To)) return true; - - return false; - } - - public bool Intersects(Line other, [NotNullWhen(returnValue: true)] out Vector2D? point) - { - point = null; - - bool result = Intersects(other); - - if (result) - point = IntersectionPoint(other); - - return result; - } - - public bool ApproximatelyEquals(Line other) - => From.ApproximatelyEquals(other.From) && To.ApproximatelyEquals(other.To); -} diff --git a/Game/Physics2D/Primitives/LineEquation.cs b/Game/Physics2D/Primitives/LineEquation.cs deleted file mode 100644 index a60977b..0000000 --- a/Game/Physics2D/Primitives/LineEquation.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Primitives; - -public record LineEquation(float Slope, float OffsetY) -{ - public float Resolve(float x) => Slope * x + OffsetY; // y = mx + b - public bool ApproximatelyEquals(LineEquation other) - => Slope.ApproximatelyEquals(other.Slope) && OffsetY.ApproximatelyEquals(other.OffsetY); -} diff --git a/Game/Physics2D/Primitives/Math.cs b/Game/Physics2D/Primitives/Math.cs deleted file mode 100644 index 79875d4..0000000 --- a/Game/Physics2D/Primitives/Math.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Syntriax.Engine.Physics2D.Primitives; - -public static class Math -{ - public const float RadianToDegree = 57.29577866666166f; - public const float DegreeToRadian = 0.01745329277777778f; - - public static float Clamp(float value, float min, float max) => (value < min) ? min : (value > max) ? max : value; -} diff --git a/Game/Physics2D/Primitives/Shape.cs b/Game/Physics2D/Primitives/Shape.cs deleted file mode 100644 index 8ba8dbf..0000000 --- a/Game/Physics2D/Primitives/Shape.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; - -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record Shape(IList Vertices) -{ - public Triangle SuperTriangle - { - get - { - float minX = float.MaxValue, minY = float.MaxValue; - float maxX = float.MinValue, maxY = float.MinValue; - - foreach (Vector2D point in Vertices) - { - minX = MathF.Min(minX, point.X); - minY = MathF.Min(minY, point.Y); - maxX = MathF.Max(maxX, point.X); - maxY = MathF.Max(maxY, point.Y); - } - - float dx = maxX - minX; - float dy = maxY - minY; - float deltaMax = MathF.Max(dx, dy); - float midX = (minX + maxX) / 2; - float midY = (minY + maxY) / 2; - - Vector2D p1 = new Vector2D((float)midX - 20f * (float)deltaMax, (float)midY - (float)deltaMax); - Vector2D p2 = new Vector2D((float)midX, (float)midY + 20 * (float)deltaMax); - Vector2D p3 = new Vector2D((float)midX + 20 * (float)deltaMax, (float)midY - (float)deltaMax); - - return new Triangle(p1, p2, p3); - } - } - - public List Lines - { - get - { - List lines = new List(Vertices.Count - 1); - GetLinesNonAlloc(lines); - return lines; - } - } - - public void GetLinesNonAlloc(IList lines) - { - lines.Clear(); - for (int i = 0; i < Vertices.Count - 1; i++) - lines.Add(new(Vertices[i], Vertices[i + 1])); - lines.Add(new(Vertices[^1], Vertices[0])); - } - - public bool ApproximatelyEquals(Shape other) - { - if (Vertices.Count != other.Vertices.Count) - return false; - - for (int i = 0; i < Vertices.Count; i++) - if (!Vertices[i].ApproximatelyEquals(other.Vertices[i])) - return false; - - return true; - } -} diff --git a/Game/Physics2D/Primitives/Triangle.cs b/Game/Physics2D/Primitives/Triangle.cs deleted file mode 100644 index 5ffcd6a..0000000 --- a/Game/Physics2D/Primitives/Triangle.cs +++ /dev/null @@ -1,54 +0,0 @@ -using System; - -using Syntriax.Engine.Core; - -namespace Syntriax.Engine.Physics2D.Primitives; - -public record Triangle(Vector2D A, Vector2D B, Vector2D C) -{ - public float Area => MathF.Abs(( - A.X * (B.Y - C.Y) + - B.X * (C.Y - A.Y) + - C.X * (A.Y - B.Y) - ) * .5f); - - public Circle CircumCircle - { - get - { - Vector2D midAB = (A + B) / 2; - Vector2D midBC = (B + C) / 2; - - float slopeAB = (B.Y - A.Y) / (B.X - A.X); - float slopeBC = (C.Y - B.Y) / (C.X - B.X); - - Vector2D center; - if (MathF.Abs(slopeAB - slopeBC) > float.Epsilon) - { - float x = (slopeAB * slopeBC * (A.Y - C.Y) + slopeBC * (A.X + B.X) - slopeAB * (B.X + C.X)) / (2 * (slopeBC - slopeAB)); - float y = -(x - (A.X + B.X) / 2) / slopeAB + (A.Y + B.Y) / 2; - center = new Vector2D(x, y); - } - else - center = (midAB + midBC) * .5f; - - return new(center, Vector2D.Distance(center, A)); - } - } - - public bool Overlaps(Vector2D point) - { - float originalTriangleArea = Area; - - float pointTriangleArea1 = new Triangle(point, B, C).Area; - float pointTriangleArea2 = new Triangle(A, point, C).Area; - float pointTriangleArea3 = new Triangle(A, B, point).Area; - - float pointTriangleAreasSum = pointTriangleArea1 + pointTriangleArea2 + pointTriangleArea3; - - return originalTriangleArea.ApproximatelyEquals(pointTriangleAreasSum, float.Epsilon * 3f); - } - - public bool ApproximatelyEquals(Triangle other) - => A.ApproximatelyEquals(other.A) && B.ApproximatelyEquals(other.B) && C.ApproximatelyEquals(other.C); -} diff --git a/Game/Physics2D/RigidBody2D.cs b/Game/Physics2D/RigidBody2D.cs deleted file mode 100644 index ed4fb4a..0000000 --- a/Game/Physics2D/RigidBody2D.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; - -using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Physics2D.Abstract; - -namespace Syntriax.Engine.Physics2D; - -public class RigidBody2D : BehaviourOverride, IRigidBody2D -{ - public Action? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; } - - - public IPhysicsMaterial2D Material { get; set; } = new PhysicsMaterial2DDefault(); - - public Vector2D Velocity { get; set; } = Vector2D.Zero; - public float AngularVelocity { get; set; } = 0f; - public float Mass { get; set; } = 0f; - - ITransform IAssignableTransform.Transform => Transform; - - - public bool Assign(ITransform transform) => GameObject.Assign(transform); -} From a70a934b3d500cf5ecb6e23230931a7d0d0146a1 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 18:45:35 +0300 Subject: [PATCH 64/81] chore: Removed Old References --- Pong.sln | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Pong.sln b/Pong.sln index d951ade..f5561fd 100644 --- a/Pong.sln +++ b/Pong.sln @@ -11,7 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Game", "Game\Game.csproj", EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Input", "Engine\Engine.Input\Engine.Input.csproj", "{7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Graphics", "Engine\Engine.Graphics\Engine.Graphics.csproj", "{7371D9AF-6F4D-4F05-8458-197C4EE66B01}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Physics2D", "Engine\Engine.Physics2D\Engine.Physics2D.csproj", "{0D97F83C-B043-48B1-B155-7354C4E84FC0}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,14 +34,14 @@ Global {7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Debug|Any CPU.Build.0 = Debug|Any CPU {7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.ActiveCfg = Release|Any CPU {7EED4EC3-79D5-4C6C-A54D-1B396213C0E4}.Release|Any CPU.Build.0 = Release|Any CPU - {7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7371D9AF-6F4D-4F05-8458-197C4EE66B01}.Release|Any CPU.Build.0 = Release|Any CPU + {0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D97F83C-B043-48B1-B155-7354C4E84FC0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D97F83C-B043-48B1-B155-7354C4E84FC0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {990CA10C-1EBB-4395-A43A-456B7029D8C9} = {F7F62670-237A-4C93-A30E-CE661C6FC401} {7EED4EC3-79D5-4C6C-A54D-1B396213C0E4} = {F7F62670-237A-4C93-A30E-CE661C6FC401} - {7371D9AF-6F4D-4F05-8458-197C4EE66B01} = {F7F62670-237A-4C93-A30E-CE661C6FC401} + {0D97F83C-B043-48B1-B155-7354C4E84FC0} = {F7F62670-237A-4C93-A30E-CE661C6FC401} EndGlobalSection EndGlobal From 40903eacc398030a1dd6a032e27d06a7b931a0c5 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Tue, 23 Jan 2024 19:21:21 +0300 Subject: [PATCH 65/81] chore: Engine Submodule Update --- Engine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine b/Engine index a948547..5ed7ccd 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit a9485475c7583a626801e7ae15550d34bd02f8dd +Subproject commit 5ed7ccdded04e075dca04ef93f3c75aefa338566 From 04653711e9151ee3ba5c4ecaedee257e2d05c318 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 24 Jan 2024 12:17:21 +0300 Subject: [PATCH 66/81] feat: Apo.Shapes Added --- Engine | 2 +- Game/Behaviours/IDisplayableShape.cs | 8 ++ Game/Behaviours/ShapeBehaviour.cs | 54 ++++++++++++++ Game/Game.csproj | 2 + Game/Game.sln | 18 ++--- Game/Game1.cs | 106 +++++++-------------------- 6 files changed, 98 insertions(+), 92 deletions(-) create mode 100644 Game/Behaviours/IDisplayableShape.cs create mode 100644 Game/Behaviours/ShapeBehaviour.cs diff --git a/Engine b/Engine index 5ed7ccd..e5732f0 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 5ed7ccdded04e075dca04ef93f3c75aefa338566 +Subproject commit e5732f0ac57886f1b127e154d52b6a9655d7bf85 diff --git a/Game/Behaviours/IDisplayableShape.cs b/Game/Behaviours/IDisplayableShape.cs new file mode 100644 index 0000000..0949f13 --- /dev/null +++ b/Game/Behaviours/IDisplayableShape.cs @@ -0,0 +1,8 @@ +using Apos.Shapes; + +namespace Pong.Behaviours; + +public interface IDisplayableShape +{ + void Draw(ShapeBatch shapeBatch); +} diff --git a/Game/Behaviours/ShapeBehaviour.cs b/Game/Behaviours/ShapeBehaviour.cs new file mode 100644 index 0000000..4771049 --- /dev/null +++ b/Game/Behaviours/ShapeBehaviour.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Apos.Shapes; + +using Engine.Physics2D; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Primitives; + +namespace Pong.Behaviours; + +public class ShapeBehaviour : BehaviourOverride, IDisplayableShape +{ + private readonly List vectors = []; + + public ShapeBehaviour(Shape Shape) { this.Shape = Shape; } + public ShapeBehaviour(Shape Shape, float Thickness) { this.Shape = Shape; this.Thickness = Thickness; } + public ShapeBehaviour(Shape Shape, Color color) { this.Shape = Shape; Color = color; } + public ShapeBehaviour(Shape Shape, Color color, float Thickness) { this.Shape = Shape; this.Thickness = Thickness; Color = color; } + + public Shape Shape { get; } = default!; + public Color Color { get; set; } = Color.White; + public float Thickness { get; set; } = .5f; + + public void Draw(ShapeBatch shapeBatch) + { + Shape.TransformShape(GameObject.Transform, vectors); + + for (int i = 0; i < vectors.Count - 1; i++) + shapeBatch.DrawLine(vectors[i].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), vectors[i + 1].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), Thickness, Color, Color); + shapeBatch.DrawLine(vectors[0].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), vectors[^1].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), Thickness, Color, Color); + } +} + +public static class ShapeTransform +{ + public static void TransformShape(this Shape shape, ITransform transform, List vectors) + { + vectors.Clear(); + + int count = shape.Vertices.Count; + for (int i = 0; i < count; i++) + vectors.Add + ( + shape[i] + .Scale(transform.Scale) + .Rotate(transform.Rotation * Physics2D.DegreeToRadian) + .Add(transform.Position) + ); + } +} diff --git a/Game/Game.csproj b/Game/Game.csproj index 323a3f6..f15750f 100644 --- a/Game/Game.csproj +++ b/Game/Game.csproj @@ -20,12 +20,14 @@ + + diff --git a/Game/Game.sln b/Game/Game.sln index 58640a0..47a229d 100644 --- a/Game/Game.sln +++ b/Game/Game.sln @@ -3,9 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.5.002.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{42644486-9F9E-4242-B6C4-AF31BBFA31D2}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Engine.Core", "..\Engine\Engine.Core\Engine.Core.csproj", "{EF1FE4A2-40DF-4967-8003-CF6D98010D02}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -13,19 +11,15 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {42644486-9F9E-4242-B6C4-AF31BBFA31D2}.Release|Any CPU.Build.0 = Release|Any CPU - {EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF1FE4A2-40DF-4967-8003-CF6D98010D02}.Release|Any CPU.Build.0 = Release|Any CPU + {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {AB3225EE-1621-439F-8F83-DF4515922FEF} + SolutionGuid = {5C7F09EA-E22F-4BDB-A0F1-1F295EBCE4A0} EndGlobalSection EndGlobal diff --git a/Game/Game1.cs b/Game/Game1.cs index 5056882..42b3fd2 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -4,10 +4,10 @@ using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Pong.Behaviours; +using Apos.Shapes; using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; -using Syntriax.Engine.Graphics.TwoDimensional; using Syntriax.Engine.Physics2D; using Syntriax.Engine.Physics2D.Primitives; @@ -18,6 +18,7 @@ public class Game1 : Game private GraphicsDeviceManager _graphics = null!; private PhysicsEngine2D engine; private SpriteBatch _spriteBatch = null!; + private ShapeBatch _shapeBatch = null!; public static GameManager gameManager = null!; public static Sprite spriteBox = null!; private MonoGameCameraBehaviour cameraBehaviour = null!; @@ -30,7 +31,8 @@ public class Game1 : Game _graphics = new GraphicsDeviceManager(this) { PreferredBackBufferWidth = 1024, - PreferredBackBufferHeight = 576 + PreferredBackBufferHeight = 576, + GraphicsProfile = GraphicsProfile.HiDef }; Content.RootDirectory = "Content"; @@ -50,9 +52,10 @@ public class Game1 : Game protected override void LoadContent() { _spriteBatch = new SpriteBatch(GraphicsDevice); + _shapeBatch = new ShapeBatch(GraphicsDevice, Content); - spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; - Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; + // spriteBox = new Sprite() { Texture2D = Content.Load("Sprites/Pixel") }; + // Sprite spriteBall = new Sprite() { Texture2D = Content.Load("Sprites/Circle") }; IGameObject gameObjectCamera = gameManager.InstantiateGameObject(); gameObjectCamera.Name = "Camera"; @@ -62,76 +65,14 @@ public class Game1 : Game cameraBehaviour.Viewport = GraphicsDevice.Viewport; gameManager.Camera = cameraBehaviour; - GameObject gameObjectBall = gameManager.InstantiateGameObject(); - gameObjectBall.Name = "Ball"; - gameObjectBall.Transform.Position = Vector2D.Zero; - gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f); - engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .1f), 500f); - gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f); - // gameObjectBall = gameManager.InstantiateGameObject(); - // gameObjectBall.Name = "Ball"; - // gameObjectBall.Transform.Position = Vector2D.UnitY * 30f; - // gameObjectBall.Transform.Scale = new Vector2D(1f / 51.2f, 1f / 51.2f); - // engine.AddRigidBody(gameObjectBall.BehaviourController.AddBehaviour()); - // gameObjectBall.BehaviourController.AddBehaviour(new Vector2D(.1f, .01f), 500f); - // gameObjectBall.BehaviourController.AddBehaviour().Assign(spriteBall); - // gameObjectBall.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * 512f * .5f, Vector2D.One * 512f * .5f); - // IGameObject gameObjectLeft = gameManager.InstantiateGameObject(); - // gameObjectLeft.Name = "Left"; - // gameObjectLeft.Transform.Position = new Vector2D(-452, 0f); - // gameObjectLeft.Transform.Scale = new Vector2D(10f, 40f); - // gameObjectLeft.BehaviourController.AddBehaviour(); - // gameObjectLeft.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - // gameObjectLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - // gameObjectLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - // engine.AddRigidBody(gameObjectLeft.BehaviourController.AddBehaviour()); - - // IGameObject gameObjectRight = gameManager.InstantiateGameObject(); - // gameObjectRight.Name = "Right"; - // gameObjectRight.Transform.Position = new Vector2D(452, 0f); - // gameObjectRight.Transform.Scale = new Vector2D(10f, 40f); - // gameObjectRight.BehaviourController.AddBehaviour(); - // gameObjectRight.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); - // gameObjectRight.BehaviourController.AddBehaviour().Assign(spriteBox); - // gameObjectRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - // engine.AddRigidBody(gameObjectRight.BehaviourController.AddBehaviour()); - - - IGameObject goPlayAreaTop = gameManager.InstantiateGameObject(); - goPlayAreaTop.Transform.Position = new Vector2D(0f, 288f + 20f); - goPlayAreaTop.Transform.Scale = new Vector2D(10240f, 40f); - goPlayAreaTop.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaTop.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - engine.AddRigidBody(goPlayAreaTop.BehaviourController.AddBehaviour()); - IGameObject goPlayAreaBottom = gameManager.InstantiateGameObject(); - goPlayAreaBottom.Transform.Position = new Vector2D(0f, -(288f + 20f)); - goPlayAreaBottom.Transform.Scale = new Vector2D(10240f, 40f); - goPlayAreaBottom.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaBottom.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - engine.AddRigidBody(goPlayAreaBottom.BehaviourController.AddBehaviour()); - - IGameObject goPlayAreaRight = gameManager.InstantiateGameObject(); - goPlayAreaRight.Transform.Position = new Vector2D(512f + 20f, 0f); - goPlayAreaRight.Transform.Scale = new Vector2D(40f, 5760f); - goPlayAreaRight.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaRight.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - engine.AddRigidBody(goPlayAreaRight.BehaviourController.AddBehaviour()); - IGameObject goPlayAreaLeft = gameManager.InstantiateGameObject(); - goPlayAreaLeft.Transform.Position = new Vector2D(-(512f + 20f), 0f); - goPlayAreaLeft.Transform.Scale = new Vector2D(40f, 5760f); - goPlayAreaLeft.BehaviourController.AddBehaviour().Assign(spriteBox); - goPlayAreaLeft.BehaviourController.AddBehaviour().AABBLocal = new AABB(-Vector2D.One * .5f, Vector2D.One * .5f); - engine.AddRigidBody(goPlayAreaLeft.BehaviourController.AddBehaviour()); - - // IGameObject goPlayAreaCenter = gameManager.InstantiateGameObject(); - // goPlayAreaCenter.Transform.Position = new Vector2D(100f, 100f); - // goPlayAreaCenter.Transform.Scale = new Vector2D(40f, 40f); - // // goPlayAreaCenter.BehaviourController.AddBehaviour().Assign(spriteBox); - // engine.AddRigidBody(goPlayAreaCenter.BehaviourController.AddBehaviour()); - // TODO: use this.Content to load your game content here + gameObjectDiamond = gameManager.InstantiateGameObject(); + gameObjectDiamond.Name = "Diamond"; + gameObjectDiamond.Transform.Position = new Vector2D(0f, 0f); + gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); + gameObjectDiamond.BehaviourController.AddBehaviour(); + gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Left])); } protected override void Update(GameTime gameTime) @@ -165,6 +106,10 @@ public class Game1 : Game cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.E)) cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; + if (Keyboard.GetState().IsKeyDown(Keys.NumPad4)) + gameObjectDiamond.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.0025f; + if (Keyboard.GetState().IsKeyDown(Keys.NumPad6)) + gameObjectDiamond.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.0025f; if (Keyboard.GetState().IsKeyDown(Keys.N)) { @@ -217,6 +162,7 @@ public class Game1 : Game } static float physicsTimer = 0f; static float seconds = 0f; + private GameObject gameObjectDiamond; protected override void Draw(GameTime gameTime) { @@ -231,14 +177,16 @@ public class Game1 : Game _spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform); foreach (IGameObject gameObject in gameManager) - { - if (!gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable)) - continue; - - displayable.Draw(_spriteBatch); - } + if (gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable)) + displayable.Draw(_spriteBatch); _spriteBatch.End(); + _shapeBatch.Begin(cameraBehaviour.MatrixTransform); + foreach (IGameObject gameObject in gameManager) + if (gameObject.BehaviourController.TryGetBehaviour(out IDisplayableShape? displayableShape)) + displayableShape.Draw(_shapeBatch); + _shapeBatch.End(); + base.Draw(gameTime); } } From 5b484eb38c7211b780a160cf0dd9b3068c4130d7 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 24 Jan 2024 18:40:12 +0300 Subject: [PATCH 67/81] feat: ShapeAABB --- Engine | 2 +- Game/Behaviours/ShapeAABBBehaviour.cs | 42 +++++++++++++++++++++++++++ Game/Behaviours/ShapeBehaviour.cs | 17 ++++------- Game/Game1.cs | 7 +++-- 4 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 Game/Behaviours/ShapeAABBBehaviour.cs diff --git a/Engine b/Engine index e5732f0..3428fcc 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit e5732f0ac57886f1b127e154d52b6a9655d7bf85 +Subproject commit 3428fcc6ca759805c26f742f9b2ca820953c3ba3 diff --git a/Game/Behaviours/ShapeAABBBehaviour.cs b/Game/Behaviours/ShapeAABBBehaviour.cs new file mode 100644 index 0000000..c0b7e5e --- /dev/null +++ b/Game/Behaviours/ShapeAABBBehaviour.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; + +using Microsoft.Xna.Framework; + +using Apos.Shapes; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Physics2D.Primitives; +using Syntriax.Engine.Core.Abstract; + +namespace Pong.Behaviours; + +public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape +{ + private readonly List vectors = []; + private ShapeBehaviour? shapeBehaviour = null; + private readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; + + public ShapeAABBBehaviour() { } + public ShapeAABBBehaviour(float Thickness) { this.Thickness = Thickness; } + public ShapeAABBBehaviour(Color color) { Color = color; } + public ShapeAABBBehaviour(Color color, float Thickness) { this.Thickness = Thickness; Color = color; } + + public Color Color { get; set; } = Color.White; + public float Thickness { get; set; } = .5f; + + protected override void OnFirstActiveFrame() + { + BehaviourController.TryGetBehaviour(out shapeBehaviour); + } + + public void Draw(ShapeBatch shapeBatch) + { + if (shapeBehaviour is null) + return; + + shapeBehaviour.Shape.TransformShape(Transform, vectors); + AABB aabb = AABB.FromVectors(vectors); + + shapeBatch.DrawRectangle(aabb.Center.Scale(screenScale).Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); + } +} diff --git a/Game/Behaviours/ShapeBehaviour.cs b/Game/Behaviours/ShapeBehaviour.cs index 4771049..cd0b2bd 100644 --- a/Game/Behaviours/ShapeBehaviour.cs +++ b/Game/Behaviours/ShapeBehaviour.cs @@ -4,8 +4,6 @@ using Microsoft.Xna.Framework; using Apos.Shapes; -using Engine.Physics2D; - using Syntriax.Engine.Core; using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Primitives; @@ -15,6 +13,7 @@ namespace Pong.Behaviours; public class ShapeBehaviour : BehaviourOverride, IDisplayableShape { private readonly List vectors = []; + private readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; public ShapeBehaviour(Shape Shape) { this.Shape = Shape; } public ShapeBehaviour(Shape Shape, float Thickness) { this.Shape = Shape; this.Thickness = Thickness; } @@ -28,10 +27,12 @@ public class ShapeBehaviour : BehaviourOverride, IDisplayableShape public void Draw(ShapeBatch shapeBatch) { Shape.TransformShape(GameObject.Transform, vectors); + for (int i = 0; i < vectors.Count; i++) + vectors[i] = vectors[i].Scale(screenScale); for (int i = 0; i < vectors.Count - 1; i++) - shapeBatch.DrawLine(vectors[i].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), vectors[i + 1].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), Thickness, Color, Color); - shapeBatch.DrawLine(vectors[0].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), vectors[^1].Scale(Vector2D.Down + Vector2D.Right).ToVector2(), Thickness, Color, Color); + shapeBatch.DrawLine(vectors[i].ToVector2(), vectors[i + 1].ToVector2(), Thickness, Color, Color); + shapeBatch.DrawLine(vectors[0].ToVector2(), vectors[^1].ToVector2(), Thickness, Color, Color); } } @@ -43,12 +44,6 @@ public static class ShapeTransform int count = shape.Vertices.Count; for (int i = 0; i < count; i++) - vectors.Add - ( - shape[i] - .Scale(transform.Scale) - .Rotate(transform.Rotation * Physics2D.DegreeToRadian) - .Add(transform.Position) - ); + vectors.Add(transform.TransformVector2D(shape[i])); } } diff --git a/Game/Game1.cs b/Game/Game1.cs index 42b3fd2..2b0482a 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -72,7 +72,8 @@ public class Game1 : Game gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); gameObjectDiamond.BehaviourController.AddBehaviour(); gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Left])); + gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One * 2f, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); + gameObjectDiamond.BehaviourController.AddBehaviour(); } protected override void Update(GameTime gameTime) @@ -177,13 +178,13 @@ public class Game1 : Game _spriteBatch.Begin(SpriteSortMode.Deferred, transformMatrix: cameraBehaviour.MatrixTransform); foreach (IGameObject gameObject in gameManager) - if (gameObject.BehaviourController.TryGetBehaviour(out IDisplayable? displayable)) + foreach (var displayable in gameObject.BehaviourController.GetBehaviours()) displayable.Draw(_spriteBatch); _spriteBatch.End(); _shapeBatch.Begin(cameraBehaviour.MatrixTransform); foreach (IGameObject gameObject in gameManager) - if (gameObject.BehaviourController.TryGetBehaviour(out IDisplayableShape? displayableShape)) + foreach (var displayableShape in gameObject.BehaviourController.GetBehaviours()) displayableShape.Draw(_shapeBatch); _shapeBatch.End(); From 6e6475f8bf3ddb1abcef470f810aeb6c83585a8d Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 24 Jan 2024 18:40:31 +0300 Subject: [PATCH 68/81] chore: Fixed Test Shape --- Game/Game1.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game/Game1.cs b/Game/Game1.cs index 2b0482a..643fec5 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -72,7 +72,7 @@ public class Game1 : Game gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); gameObjectDiamond.BehaviourController.AddBehaviour(); gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One * 2f, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); + gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); gameObjectDiamond.BehaviourController.AddBehaviour(); } From bf825fd961c3ad36488c37f91e27e78ced6c9b52 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Wed, 24 Jan 2024 19:25:31 +0300 Subject: [PATCH 69/81] Lots of Stuff That I Can't Break Into Smaller Commits --- Engine | 2 +- Game/Behaviours/RotatableBehaviour.cs | 29 ++++++++++++++++++ Game/Behaviours/ShapeAABBBehaviour.cs | 17 +++++------ Game/Behaviours/ShapeBehaviour.cs | 42 ++++++++------------------- Game/EngineConverter.cs | 4 +++ Game/Game1.cs | 19 ++++++++---- 6 files changed, 67 insertions(+), 46 deletions(-) create mode 100644 Game/Behaviours/RotatableBehaviour.cs diff --git a/Engine b/Engine index 3428fcc..ed15238 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 3428fcc6ca759805c26f742f9b2ca820953c3ba3 +Subproject commit ed15238dcdc094453c697a8f83d9308f6702dc21 diff --git a/Game/Behaviours/RotatableBehaviour.cs b/Game/Behaviours/RotatableBehaviour.cs new file mode 100644 index 0000000..15f3201 --- /dev/null +++ b/Game/Behaviours/RotatableBehaviour.cs @@ -0,0 +1,29 @@ +using Microsoft.Xna.Framework; + +using Apos.Shapes; + +using Syntriax.Engine.Core; + +namespace Pong.Behaviours; + +public class RotatableBehaviour : BehaviourOverride +{ + private KeyboardInputsBehaviour? inputs = null; + + protected override void OnFirstActiveFrame() + { + if (BehaviourController.TryGetBehaviour(out inputs)) + inputs.BehaviourController.AddBehaviour(); + } + + protected override void OnUpdate() + { + if (inputs is null) + return; + + if (inputs.IsPressed(Microsoft.Xna.Framework.Input.Keys.NumPad4)) + Transform.Rotation += Time.Elapsed.Nanoseconds * 0.0025f; + if (inputs.IsPressed(Microsoft.Xna.Framework.Input.Keys.NumPad6)) + Transform.Rotation -= Time.Elapsed.Nanoseconds * 0.0025f; + } +} diff --git a/Game/Behaviours/ShapeAABBBehaviour.cs b/Game/Behaviours/ShapeAABBBehaviour.cs index c0b7e5e..9f22fe9 100644 --- a/Game/Behaviours/ShapeAABBBehaviour.cs +++ b/Game/Behaviours/ShapeAABBBehaviour.cs @@ -1,19 +1,17 @@ -using System.Collections.Generic; - using Microsoft.Xna.Framework; using Apos.Shapes; using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Primitives; -using Syntriax.Engine.Core.Abstract; +using Syntriax.Engine.Physics2D.Abstract; namespace Pong.Behaviours; public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape { - private readonly List vectors = []; - private ShapeBehaviour? shapeBehaviour = null; + private Shape transformedShape = new([]); + private IShapeCollider2D? shapeCollider = null; private readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; public ShapeAABBBehaviour() { } @@ -26,16 +24,17 @@ public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape protected override void OnFirstActiveFrame() { - BehaviourController.TryGetBehaviour(out shapeBehaviour); + BehaviourController.TryGetBehaviour(out shapeCollider); } public void Draw(ShapeBatch shapeBatch) { - if (shapeBehaviour is null) + if (shapeCollider is null) return; - shapeBehaviour.Shape.TransformShape(Transform, vectors); - AABB aabb = AABB.FromVectors(vectors); + AABB aabb = AABB.FromVectors(shapeCollider.ShapeWorld); + + shapeBatch.BorderCircle(aabb.Center.ToDisplayVector2(), 7.5f, Color.Beige); shapeBatch.DrawRectangle(aabb.Center.Scale(screenScale).Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); } diff --git a/Game/Behaviours/ShapeBehaviour.cs b/Game/Behaviours/ShapeBehaviour.cs index cd0b2bd..e4c089e 100644 --- a/Game/Behaviours/ShapeBehaviour.cs +++ b/Game/Behaviours/ShapeBehaviour.cs @@ -1,49 +1,31 @@ -using System.Collections.Generic; - using Microsoft.Xna.Framework; using Apos.Shapes; using Syntriax.Engine.Core; -using Syntriax.Engine.Core.Abstract; using Syntriax.Engine.Physics2D.Primitives; namespace Pong.Behaviours; -public class ShapeBehaviour : BehaviourOverride, IDisplayableShape +public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour, IDisplayableShape { - private readonly List vectors = []; - private readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; + public ShapeBehaviour(Shape Shape) { this.ShapeLocal = Shape; } + public ShapeBehaviour(Shape Shape, float Thickness) { this.ShapeLocal = Shape; this.Thickness = Thickness; } + public ShapeBehaviour(Shape Shape, Color color) { this.ShapeLocal = Shape; Color = color; } + public ShapeBehaviour(Shape Shape, Color color, float Thickness) { this.ShapeLocal = Shape; this.Thickness = Thickness; Color = color; } - public ShapeBehaviour(Shape Shape) { this.Shape = Shape; } - public ShapeBehaviour(Shape Shape, float Thickness) { this.Shape = Shape; this.Thickness = Thickness; } - public ShapeBehaviour(Shape Shape, Color color) { this.Shape = Shape; Color = color; } - public ShapeBehaviour(Shape Shape, Color color, float Thickness) { this.Shape = Shape; this.Thickness = Thickness; Color = color; } - - public Shape Shape { get; } = default!; public Color Color { get; set; } = Color.White; public float Thickness { get; set; } = .5f; public void Draw(ShapeBatch shapeBatch) { - Shape.TransformShape(GameObject.Transform, vectors); - for (int i = 0; i < vectors.Count; i++) - vectors[i] = vectors[i].Scale(screenScale); + Recalculate(); + int count = ShapeWorld.Vertices.Count; - for (int i = 0; i < vectors.Count - 1; i++) - shapeBatch.DrawLine(vectors[i].ToVector2(), vectors[i + 1].ToVector2(), Thickness, Color, Color); - shapeBatch.DrawLine(vectors[0].ToVector2(), vectors[^1].ToVector2(), Thickness, Color, Color); - } -} - -public static class ShapeTransform -{ - public static void TransformShape(this Shape shape, ITransform transform, List vectors) - { - vectors.Clear(); - - int count = shape.Vertices.Count; - for (int i = 0; i < count; i++) - vectors.Add(transform.TransformVector2D(shape[i])); + shapeBatch.BorderCircle(Transform.Position.ToDisplayVector2(), 5f, Color.DarkRed); + + for (int i = 0; i < count - 1; i++) + shapeBatch.DrawLine(ShapeWorld[i].ToDisplayVector2(), ShapeWorld[i + 1].ToDisplayVector2(), Thickness, Color, Color); + shapeBatch.DrawLine(ShapeWorld[0].ToDisplayVector2(), ShapeWorld[^1].ToDisplayVector2(), Thickness, Color, Color); } } diff --git a/Game/EngineConverter.cs b/Game/EngineConverter.cs index 6e5aed4..e3937c3 100644 --- a/Game/EngineConverter.cs +++ b/Game/EngineConverter.cs @@ -6,10 +6,14 @@ namespace Pong; public static class EngineConverter { + public readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EngineTime ToEngineTime(this GameTime gameTime) => new(gameTime.TotalGameTime, gameTime.ElapsedGameTime); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); } diff --git a/Game/Game1.cs b/Game/Game1.cs index 643fec5..08ea495 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -66,14 +66,26 @@ public class Game1 : Game gameManager.Camera = cameraBehaviour; - gameObjectDiamond = gameManager.InstantiateGameObject(); + IGameObject gameObjectDiamond = gameManager.InstantiateGameObject(); gameObjectDiamond.Name = "Diamond"; gameObjectDiamond.Transform.Position = new Vector2D(0f, 0f); gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); gameObjectDiamond.BehaviourController.AddBehaviour(); gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectDiamond.BehaviourController.AddBehaviour(); gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); gameObjectDiamond.BehaviourController.AddBehaviour(); + + + IGameObject gameObjectShape = gameManager.InstantiateGameObject(); + gameObjectShape.Name = "Shape"; + gameObjectShape.Transform.Position = new Vector2D(250f, 0f); + gameObjectShape.Transform.Scale = new Vector2D(100f, 100f); + gameObjectShape.BehaviourController.AddBehaviour(); + gameObjectShape.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectShape.BehaviourController.AddBehaviour(); + gameObjectShape.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); + // gameObjectShape.BehaviourController.AddBehaviour(); } protected override void Update(GameTime gameTime) @@ -107,10 +119,6 @@ public class Game1 : Game cameraBehaviour.BehaviourController.GameObject.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; if (Keyboard.GetState().IsKeyDown(Keys.E)) cameraBehaviour.BehaviourController.GameObject.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.000025f; - if (Keyboard.GetState().IsKeyDown(Keys.NumPad4)) - gameObjectDiamond.Transform.Rotation += gameTime.ElapsedGameTime.Nanoseconds * 0.0025f; - if (Keyboard.GetState().IsKeyDown(Keys.NumPad6)) - gameObjectDiamond.Transform.Rotation -= gameTime.ElapsedGameTime.Nanoseconds * 0.0025f; if (Keyboard.GetState().IsKeyDown(Keys.N)) { @@ -163,7 +171,6 @@ public class Game1 : Game } static float physicsTimer = 0f; static float seconds = 0f; - private GameObject gameObjectDiamond; protected override void Draw(GameTime gameTime) { From faf30b82278049f291f58982a5862076491e5964 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 12:12:53 +0300 Subject: [PATCH 70/81] feat: EngineConverter.ApplyDisplayScale --- Game/Behaviours/ShapeAABBBehaviour.cs | 4 +--- Game/EngineConverter.cs | 2 ++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Game/Behaviours/ShapeAABBBehaviour.cs b/Game/Behaviours/ShapeAABBBehaviour.cs index 9f22fe9..23f2b21 100644 --- a/Game/Behaviours/ShapeAABBBehaviour.cs +++ b/Game/Behaviours/ShapeAABBBehaviour.cs @@ -10,9 +10,7 @@ namespace Pong.Behaviours; public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape { - private Shape transformedShape = new([]); private IShapeCollider2D? shapeCollider = null; - private readonly static Vector2D screenScale = Vector2D.Down + Vector2D.Right; public ShapeAABBBehaviour() { } public ShapeAABBBehaviour(float Thickness) { this.Thickness = Thickness; } @@ -36,6 +34,6 @@ public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape shapeBatch.BorderCircle(aabb.Center.ToDisplayVector2(), 7.5f, Color.Beige); - shapeBatch.DrawRectangle(aabb.Center.Scale(screenScale).Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); + shapeBatch.DrawRectangle(aabb.Center.ApplyDisplayScale().Subtract(aabb.SizeHalf).ToVector2(), aabb.Size.ToVector2(), Color.Transparent, Color.Blue); } } diff --git a/Game/EngineConverter.cs b/Game/EngineConverter.cs index e3937c3..6458aea 100644 --- a/Game/EngineConverter.cs +++ b/Game/EngineConverter.cs @@ -16,4 +16,6 @@ public static class EngineConverter public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ApplyDisplayScale(this Vector2D vector) => vector.Scale(screenScale); } From 76484017e1b171f5a92f8b0f03f488d457f2e358 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 18:52:47 +0300 Subject: [PATCH 71/81] feat: Circle Behaviour --- Engine | 2 +- Game/Behaviours/CircleBehaviour.cs | 26 +++++++++++++ Game/Game1.cs | 62 +++++++++++++++++++----------- 3 files changed, 66 insertions(+), 24 deletions(-) create mode 100644 Game/Behaviours/CircleBehaviour.cs diff --git a/Engine b/Engine index ed15238..9e1f388 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit ed15238dcdc094453c697a8f83d9308f6702dc21 +Subproject commit 9e1f38897fe9fbb229631dc5886bb0fe79e56427 diff --git a/Game/Behaviours/CircleBehaviour.cs b/Game/Behaviours/CircleBehaviour.cs new file mode 100644 index 0000000..d5c7e67 --- /dev/null +++ b/Game/Behaviours/CircleBehaviour.cs @@ -0,0 +1,26 @@ +using Microsoft.Xna.Framework; + +using Apos.Shapes; + +using Syntriax.Engine.Core; +using Syntriax.Engine.Physics2D.Primitives; + +namespace Pong.Behaviours; + +public class CircleBehaviour : Syntriax.Engine.Physics2D.Collider2DCircleBehaviour, IDisplayableShape +{ + public CircleBehaviour(Circle circle) { this.CircleLocal = circle; } + public CircleBehaviour(Circle circle, float Thickness) { this.CircleLocal = circle; this.Thickness = Thickness; } + public CircleBehaviour(Circle circle, Color color) { this.CircleLocal = circle; Color = color; } + public CircleBehaviour(Circle circle, Color color, float Thickness) { this.CircleLocal = circle; this.Thickness = Thickness; Color = color; } + + public Color Color { get; set; } = Color.White; + public float Thickness { get; set; } = .5f; + + public void Draw(ShapeBatch shapeBatch) + { + Recalculate(); + + shapeBatch.BorderCircle(CircleWorld.Center.ToDisplayVector2(), CircleWorld.Radius, Color); + } +} diff --git a/Game/Game1.cs b/Game/Game1.cs index 08ea495..a103e9f 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -66,25 +66,41 @@ public class Game1 : Game gameManager.Camera = cameraBehaviour; - IGameObject gameObjectDiamond = gameManager.InstantiateGameObject(); - gameObjectDiamond.Name = "Diamond"; - gameObjectDiamond.Transform.Position = new Vector2D(0f, 0f); - gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); - gameObjectDiamond.BehaviourController.AddBehaviour(); - gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectDiamond.BehaviourController.AddBehaviour(); - gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); - gameObjectDiamond.BehaviourController.AddBehaviour(); + IGameObject gameObjectCircle = gameManager.InstantiateGameObject(); + gameObjectCircle.Name = "Circle"; + gameObjectCircle.Transform.Position = new Vector2D(0f, -50f); + gameObjectCircle.Transform.Scale = new Vector2D(25f, 25f); + gameObjectCircle.BehaviourController.AddBehaviour(); + gameObjectCircle.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectCircle.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); + engine.AddRigidBody(gameObjectCircle.BehaviourController.AddBehaviour()); + + IGameObject gameObjectCircle2 = gameManager.InstantiateGameObject(); + gameObjectCircle2.Name = "Circle2"; + gameObjectCircle2.Transform.Position = new Vector2D(0f, 50f); + gameObjectCircle2.Transform.Scale = new Vector2D(25f, 25f); + gameObjectCircle2.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); + engine.AddRigidBody(gameObjectCircle2.BehaviourController.AddBehaviour()); + + // IGameObject gameObjectDiamond = gameManager.InstantiateGameObject(); + // gameObjectDiamond.Name = "Diamond"; + // gameObjectDiamond.Transform.Position = new Vector2D(0f, 0f); + // gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); + // gameObjectDiamond.BehaviourController.AddBehaviour(); + // gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + // gameObjectDiamond.BehaviourController.AddBehaviour(); + // gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); + // gameObjectDiamond.BehaviourController.AddBehaviour(); - IGameObject gameObjectShape = gameManager.InstantiateGameObject(); - gameObjectShape.Name = "Shape"; - gameObjectShape.Transform.Position = new Vector2D(250f, 0f); - gameObjectShape.Transform.Scale = new Vector2D(100f, 100f); - gameObjectShape.BehaviourController.AddBehaviour(); - gameObjectShape.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectShape.BehaviourController.AddBehaviour(); - gameObjectShape.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); + // IGameObject gameObjectShape = gameManager.InstantiateGameObject(); + // gameObjectShape.Name = "Shape"; + // gameObjectShape.Transform.Position = new Vector2D(250f, 0f); + // gameObjectShape.Transform.Scale = new Vector2D(100f, 100f); + // gameObjectShape.BehaviourController.AddBehaviour(); + // gameObjectShape.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + // gameObjectShape.BehaviourController.AddBehaviour(); + // gameObjectShape.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); // gameObjectShape.BehaviourController.AddBehaviour(); } @@ -160,12 +176,12 @@ public class Game1 : Game } - // while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) - // { - // Console.WriteLine($"Physics Timer: {physicsTimer}"); - // physicsTimer += 0.01f; - // engine.Step(.01f); - // } + while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) + { + Console.WriteLine($"Physics Timer: {physicsTimer}"); + physicsTimer += 0.01f; + engine.Step(.01f); + } gameManager.Update(gameTime.ToEngineTime()); base.Update(gameTime); } From 91ad13628cd18842a963f3779c07871242384d70 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 22:01:42 +0300 Subject: [PATCH 72/81] perf: Removed Unnecessary Recalculate in CircleBehaviour --- Game/Behaviours/CircleBehaviour.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Game/Behaviours/CircleBehaviour.cs b/Game/Behaviours/CircleBehaviour.cs index d5c7e67..6e107a7 100644 --- a/Game/Behaviours/CircleBehaviour.cs +++ b/Game/Behaviours/CircleBehaviour.cs @@ -2,7 +2,6 @@ using Microsoft.Xna.Framework; using Apos.Shapes; -using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Primitives; namespace Pong.Behaviours; @@ -19,8 +18,6 @@ public class CircleBehaviour : Syntriax.Engine.Physics2D.Collider2DCircleBehavio public void Draw(ShapeBatch shapeBatch) { - Recalculate(); - shapeBatch.BorderCircle(CircleWorld.Center.ToDisplayVector2(), CircleWorld.Radius, Color); } } From 80c0f4cdd604fdca4443a04fac6e54a57e74daf5 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 22:03:31 +0300 Subject: [PATCH 73/81] refactor: Removed Unnecessary Recalculate on Shape Behaviour --- Game/Behaviours/ShapeBehaviour.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Game/Behaviours/ShapeBehaviour.cs b/Game/Behaviours/ShapeBehaviour.cs index e4c089e..c27ad33 100644 --- a/Game/Behaviours/ShapeBehaviour.cs +++ b/Game/Behaviours/ShapeBehaviour.cs @@ -2,7 +2,6 @@ using Microsoft.Xna.Framework; using Apos.Shapes; -using Syntriax.Engine.Core; using Syntriax.Engine.Physics2D.Primitives; namespace Pong.Behaviours; @@ -19,7 +18,6 @@ public class ShapeBehaviour : Syntriax.Engine.Physics2D.Collider2DShapeBehaviour public void Draw(ShapeBatch shapeBatch) { - Recalculate(); int count = ShapeWorld.Vertices.Count; shapeBatch.BorderCircle(Transform.Position.ToDisplayVector2(), 5f, Color.DarkRed); From e252d8fbb27752ae3e086990f3bc99146daff881 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 22:04:04 +0300 Subject: [PATCH 74/81] chore: Physics Test --- Engine | 2 +- Game/Game1.cs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Engine b/Engine index 9e1f388..0ba8927 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 9e1f38897fe9fbb229631dc5886bb0fe79e56427 +Subproject commit 0ba8927858a4f43ce59ddd5917fb65d469786e5d diff --git a/Game/Game1.cs b/Game/Game1.cs index a103e9f..00e7486 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -79,6 +79,8 @@ public class Game1 : Game gameObjectCircle2.Name = "Circle2"; gameObjectCircle2.Transform.Position = new Vector2D(0f, 50f); gameObjectCircle2.Transform.Scale = new Vector2D(25f, 25f); + gameObjectCircle2.BehaviourController.AddBehaviour(); + gameObjectCircle2.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); gameObjectCircle2.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); engine.AddRigidBody(gameObjectCircle2.BehaviourController.AddBehaviour()); @@ -178,7 +180,7 @@ public class Game1 : Game while (physicsTimer + 0.01f < gameTime.TotalGameTime.TotalMilliseconds * .001f)//seconds) { - Console.WriteLine($"Physics Timer: {physicsTimer}"); + // Console.WriteLine($"Physics Timer: {physicsTimer}"); physicsTimer += 0.01f; engine.Step(.01f); } From 427ab5ed54e083f82a23334813319a919d2d3f2a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Thu, 25 Jan 2024 22:15:52 +0300 Subject: [PATCH 75/81] feat: Mouse Movement --- Game/Behaviours/MovementMouseBehaviour.cs | 13 +++++++++++++ Game/EngineConverter.cs | 2 ++ Game/Game1.cs | 5 ++--- 3 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 Game/Behaviours/MovementMouseBehaviour.cs diff --git a/Game/Behaviours/MovementMouseBehaviour.cs b/Game/Behaviours/MovementMouseBehaviour.cs new file mode 100644 index 0000000..afdb67e --- /dev/null +++ b/Game/Behaviours/MovementMouseBehaviour.cs @@ -0,0 +1,13 @@ +using System; +using Microsoft.Xna.Framework.Input; +using Syntriax.Engine.Core; + +namespace Pong.Behaviours; + +public class MovementMouseBehaviour : BehaviourOverride +{ + protected override void OnUpdate() + { + GameObject.Transform.Position = Mouse.GetState().Position.ToVector2D().ApplyDisplayScale(); + } +} diff --git a/Game/EngineConverter.cs b/Game/EngineConverter.cs index 6458aea..fe904cc 100644 --- a/Game/EngineConverter.cs +++ b/Game/EngineConverter.cs @@ -13,6 +13,8 @@ public static class EngineConverter [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2D ToVector2D(this Vector2 vector) => new(vector.X, vector.Y); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2D ToVector2D(this Point point) => new(point.X, point.Y); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToVector2(this Vector2D vector) => new(vector.X, vector.Y); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 ToDisplayVector2(this Vector2D vector) => vector.Scale(screenScale).ToVector2(); diff --git a/Game/Game1.cs b/Game/Game1.cs index 00e7486..05a7b27 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -77,10 +77,9 @@ public class Game1 : Game IGameObject gameObjectCircle2 = gameManager.InstantiateGameObject(); gameObjectCircle2.Name = "Circle2"; - gameObjectCircle2.Transform.Position = new Vector2D(0f, 50f); + gameObjectCircle2.Transform.Position = new Vector2D(5f, 50f); gameObjectCircle2.Transform.Scale = new Vector2D(25f, 25f); - gameObjectCircle2.BehaviourController.AddBehaviour(); - gameObjectCircle2.BehaviourController.AddBehaviour(Keys.Up, Keys.Down, 268f, -268f, 400f); + gameObjectCircle2.BehaviourController.AddBehaviour(); gameObjectCircle2.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); engine.AddRigidBody(gameObjectCircle2.BehaviourController.AddBehaviour()); From 9eed07402592eb2756f9a0b018adaf9610401aca Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 26 Jan 2024 12:31:19 +0300 Subject: [PATCH 76/81] chore: Removed Unnecessary .sln Files --- Engine | 2 +- Game/Game.sln | 25 ------------------------- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 Game/Game.sln diff --git a/Engine b/Engine index 0ba8927..ceebe21 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 0ba8927858a4f43ce59ddd5917fb65d469786e5d +Subproject commit ceebe210417e52abf6d904ae603d82263b658599 diff --git a/Game/Game.sln b/Game/Game.sln deleted file mode 100644 index 47a229d..0000000 --- a/Game/Game.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {5C2459D3-9CB7-4778-BBDC-4F5B8298AACD}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {5C7F09EA-E22F-4BDB-A0F1-1F295EBCE4A0} - EndGlobalSection -EndGlobal From ef08eedc349a1cffb760d4f796fe79169027de2a Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 26 Jan 2024 19:21:26 +0300 Subject: [PATCH 77/81] feat: Test Shapes Scene --- Engine | 2 +- Game/Behaviours/ShapeAABBBehaviour.cs | 10 ++++- Game/Game1.cs | 62 +++++++++++++++++++-------- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Engine b/Engine index ceebe21..85bad95 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit ceebe210417e52abf6d904ae603d82263b658599 +Subproject commit 85bad951ff9802d1b8c0a00e23f11914b5acd20d diff --git a/Game/Behaviours/ShapeAABBBehaviour.cs b/Game/Behaviours/ShapeAABBBehaviour.cs index 23f2b21..635ef75 100644 --- a/Game/Behaviours/ShapeAABBBehaviour.cs +++ b/Game/Behaviours/ShapeAABBBehaviour.cs @@ -3,8 +3,9 @@ using Microsoft.Xna.Framework; using Apos.Shapes; using Syntriax.Engine.Core; -using Syntriax.Engine.Physics2D.Primitives; +using Syntriax.Engine.Input; using Syntriax.Engine.Physics2D.Abstract; +using Syntriax.Engine.Physics2D.Primitives; namespace Pong.Behaviours; @@ -19,14 +20,21 @@ public class ShapeAABBBehaviour : BehaviourOverride, IDisplayableShape public Color Color { get; set; } = Color.White; public float Thickness { get; set; } = .5f; + public bool display = true; protected override void OnFirstActiveFrame() { BehaviourController.TryGetBehaviour(out shapeCollider); + + if (BehaviourController.TryGetBehaviour(out IButtonInputs? keys)) + keys.RegisterOnPress(Microsoft.Xna.Framework.Input.Keys.D, (_1, _2) => display = !display); } public void Draw(ShapeBatch shapeBatch) { + if (!display) + return; + if (shapeCollider is null) return; diff --git a/Game/Game1.cs b/Game/Game1.cs index 05a7b27..9515341 100644 --- a/Game/Game1.cs +++ b/Game/Game1.cs @@ -66,14 +66,14 @@ public class Game1 : Game gameManager.Camera = cameraBehaviour; - IGameObject gameObjectCircle = gameManager.InstantiateGameObject(); - gameObjectCircle.Name = "Circle"; - gameObjectCircle.Transform.Position = new Vector2D(0f, -50f); - gameObjectCircle.Transform.Scale = new Vector2D(25f, 25f); - gameObjectCircle.BehaviourController.AddBehaviour(); - gameObjectCircle.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - gameObjectCircle.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); - engine.AddRigidBody(gameObjectCircle.BehaviourController.AddBehaviour()); + // IGameObject gameObjectCircle = gameManager.InstantiateGameObject(); + // gameObjectCircle.Name = "Circle"; + // gameObjectCircle.Transform.Position = new Vector2D(0f, -50f); + // gameObjectCircle.Transform.Scale = new Vector2D(25f, 25f); + // gameObjectCircle.BehaviourController.AddBehaviour(); + // gameObjectCircle.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + // gameObjectCircle.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); + // engine.AddRigidBody(gameObjectCircle.BehaviourController.AddBehaviour()); IGameObject gameObjectCircle2 = gameManager.InstantiateGameObject(); gameObjectCircle2.Name = "Circle2"; @@ -83,15 +83,43 @@ public class Game1 : Game gameObjectCircle2.BehaviourController.AddBehaviour(new Circle(Vector2D.Zero, 1f)); engine.AddRigidBody(gameObjectCircle2.BehaviourController.AddBehaviour()); - // IGameObject gameObjectDiamond = gameManager.InstantiateGameObject(); - // gameObjectDiamond.Name = "Diamond"; - // gameObjectDiamond.Transform.Position = new Vector2D(0f, 0f); - // gameObjectDiamond.Transform.Scale = new Vector2D(100f, 100f); - // gameObjectDiamond.BehaviourController.AddBehaviour(); - // gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); - // gameObjectDiamond.BehaviourController.AddBehaviour(); - // gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, Vector2D.Zero, Vector2D.Left])); - // gameObjectDiamond.BehaviourController.AddBehaviour(); + IGameObject gameObjectDiamond = gameManager.InstantiateGameObject(); + gameObjectDiamond.Name = "Diamond"; + gameObjectDiamond.Transform.Position = new Vector2D(-150f, -150f); + gameObjectDiamond.Transform.Scale = new Vector2D(50f, 50f); + gameObjectDiamond.BehaviourController.AddBehaviour(); + gameObjectDiamond.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectDiamond.BehaviourController.AddBehaviour(); + gameObjectDiamond.BehaviourController.AddBehaviour(new Shape([Vector2D.Up, Vector2D.One, Vector2D.Right, Vector2D.Down, -Vector2D.One, Vector2D.Left])); + gameObjectDiamond.BehaviourController.AddBehaviour(); + engine.AddRigidBody(gameObjectDiamond.BehaviourController.AddBehaviour()); + + IGameObject gameObjectBox = gameManager.InstantiateGameObject(); + gameObjectBox.Name = "Box"; + gameObjectBox.Transform.Position = new Vector2D(150f, -150f); + gameObjectBox.Transform.Scale = new Vector2D(100f, 100f); + gameObjectBox.BehaviourController.AddBehaviour(); + gameObjectBox.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + gameObjectBox.BehaviourController.AddBehaviour(); + gameObjectBox.BehaviourController.AddBehaviour(Shape.Pentagon); + gameObjectBox.BehaviourController.AddBehaviour(); + engine.AddRigidBody(gameObjectBox.BehaviourController.AddBehaviour()); + + for (int i = 3; i < 10; i++) + { + IGameObject Test = gameManager.InstantiateGameObject(); + Test.Name = i.ToString(); + Test.Transform.Position = new Vector2D((i - 6) * 150, 0f); + Test.Transform.Scale = new Vector2D(75f, 75f); + Test.BehaviourController.AddBehaviour(); + Test.BehaviourController.AddBehaviour(Keys.W, Keys.S, 268f, -268f, 400f); + Test.BehaviourController.AddBehaviour(); + Test.BehaviourController.AddBehaviour(Shape.CreateNgon(i)); + Test.BehaviourController.AddBehaviour(); + RigidBody2D rigidBody = Test.BehaviourController.AddBehaviour(); + rigidBody.AngularVelocity = 90f; + engine.AddRigidBody(rigidBody); + } // IGameObject gameObjectShape = gameManager.InstantiateGameObject(); From 42b427f49b29c4d4cfd4774eeb687002fb6598a0 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 26 Jan 2024 19:32:42 +0300 Subject: [PATCH 78/81] chore: Engine Update --- Engine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine b/Engine index 85bad95..058c6da 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 85bad951ff9802d1b8c0a00e23f11914b5acd20d +Subproject commit 058c6dafe3ba572d1d14c139e8d468e87931a1a6 From bd9974f410e9ad2905be88e6f5d9ac9329d2d72d Mon Sep 17 00:00:00 2001 From: Syntriax Date: Fri, 26 Jan 2024 20:46:51 +0300 Subject: [PATCH 79/81] chore: Engine Update --- Engine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine b/Engine index 058c6da..c32add4 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit 058c6dafe3ba572d1d14c139e8d468e87931a1a6 +Subproject commit c32add40ff07beadeaa5464353ee156b3028afd9 From 7ed6c1e050a00f66e85043b658fab868abb2fcd3 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 27 Jan 2024 14:47:29 +0300 Subject: [PATCH 80/81] fix: RotatableBehaviour Not Assigning KeyboardInputsBehaviour when It's Missing --- Game/Behaviours/RotatableBehaviour.cs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Game/Behaviours/RotatableBehaviour.cs b/Game/Behaviours/RotatableBehaviour.cs index 15f3201..09185c4 100644 --- a/Game/Behaviours/RotatableBehaviour.cs +++ b/Game/Behaviours/RotatableBehaviour.cs @@ -1,7 +1,3 @@ -using Microsoft.Xna.Framework; - -using Apos.Shapes; - using Syntriax.Engine.Core; namespace Pong.Behaviours; @@ -12,8 +8,8 @@ public class RotatableBehaviour : BehaviourOverride protected override void OnFirstActiveFrame() { - if (BehaviourController.TryGetBehaviour(out inputs)) - inputs.BehaviourController.AddBehaviour(); + if (!BehaviourController.TryGetBehaviour(out inputs)) + inputs = BehaviourController.AddBehaviour(); } protected override void OnUpdate() From 2f500bef19c47879a308af3dd9526d2441d66e28 Mon Sep 17 00:00:00 2001 From: Syntriax Date: Sat, 27 Jan 2024 20:38:53 +0300 Subject: [PATCH 81/81] chore: Engine Submodule Update --- Engine | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Engine b/Engine index c32add4..6a104d8 160000 --- a/Engine +++ b/Engine @@ -1 +1 @@ -Subproject commit c32add40ff07beadeaa5464353ee156b3028afd9 +Subproject commit 6a104d8abd013334ed2787c4b4c6fa6481e4c6a4