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