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; } }