2023-12-01 17:42:07 +03:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Collections.ObjectModel;
|
2023-12-04 13:14:23 +03:00
|
|
|
using System.Diagnostics.CodeAnalysis;
|
2023-12-05 17:04:26 +03:00
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
using Microsoft.Xna.Framework;
|
2023-12-05 17:04:26 +03:00
|
|
|
|
2023-12-04 17:48:22 +03:00
|
|
|
using Pong;
|
2023-12-05 17:04:26 +03:00
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
using Syntriax.Engine.Core;
|
|
|
|
using Syntriax.Engine.Core.Abstract;
|
2023-12-04 17:48:22 +03:00
|
|
|
using Syntriax.Engine.Graphics.TwoDimensional;
|
2023-12-01 17:42:07 +03:00
|
|
|
using Syntriax.Engine.Physics2D.Abstract;
|
|
|
|
|
|
|
|
namespace Syntriax.Engine.Physics2D;
|
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
public class Collider2DBehaviour(IList<Vector2> vertices) : BehaviourOverride, ICollider2D
|
|
|
|
{
|
|
|
|
private List<Triangle> triangles = new List<Triangle>(32);
|
|
|
|
private readonly List<Vector2> _vertices = new List<Vector2>(32);
|
2023-12-04 13:14:23 +03:00
|
|
|
private IRigidBody2D? _rigidBody2D = null;
|
2023-12-01 17:42:07 +03:00
|
|
|
|
|
|
|
public Action<IAssignableTransform>? OnTransformAssigned { get => GameObject.OnTransformAssigned; set => GameObject.OnTransformAssigned = value; }
|
|
|
|
public Action<ICollider2D, ICollider2D>? OnCollision { get; set; } = null;
|
|
|
|
|
2023-12-04 13:14:23 +03:00
|
|
|
|
|
|
|
private IList<Vector2> verticesOriginal { get; } = vertices;
|
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
public Vector2 OffsetPosition { get; set; } = Vector2.Zero;
|
|
|
|
public Vector2 OffsetScale { get; set; } = Vector2.One;
|
|
|
|
public float OffsetRotation { get; set; } = 0f;
|
|
|
|
|
|
|
|
ITransform IAssignableTransform.Transform => Transform;
|
2023-12-04 13:14:23 +03:00
|
|
|
public IReadOnlyList<Vector2> Vertices => _vertices;
|
|
|
|
|
|
|
|
public IRigidBody2D? RigidBody2D
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
if (_rigidBody2D is null)
|
|
|
|
BehaviourController.TryGetBehaviour(out _rigidBody2D);
|
|
|
|
|
|
|
|
return _rigidBody2D;
|
|
|
|
}
|
|
|
|
}
|
2023-12-01 17:42:07 +03:00
|
|
|
|
|
|
|
public bool Assign(ITransform transform) => GameObject.Assign(transform);
|
|
|
|
|
2023-12-04 17:48:22 +03:00
|
|
|
public bool CheckCollision(Vector2 point, ICollider2D otherCollider, out CollisionInformation collisionInformation)
|
2023-12-01 17:42:07 +03:00
|
|
|
{
|
2023-12-04 17:48:22 +03:00
|
|
|
collisionInformation = new CollisionInformation(Vector2.Zero, Vector2.Zero);
|
2023-12-04 13:14:23 +03:00
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
foreach (var triangle in triangles)
|
|
|
|
{
|
2023-12-05 17:04:26 +03:00
|
|
|
if (!PhysicsMath.IsInTriangle(point, triangle))
|
2023-12-01 17:42:07 +03:00
|
|
|
continue;
|
|
|
|
|
|
|
|
OnCollision?.Invoke(this, otherCollider);
|
2023-12-04 13:14:23 +03:00
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
Line main = new(otherCollider.Transform.Position, point);
|
2023-12-04 13:35:31 +03:00
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C]))
|
2023-12-04 13:35:31 +03:00
|
|
|
{
|
2023-12-05 17:04:26 +03:00
|
|
|
if (!PhysicsMath.DoIntersect(main, line))
|
2023-12-04 13:35:31 +03:00
|
|
|
continue;
|
2023-12-04 17:48:22 +03:00
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
Vector2 contactPoint = PhysicsMath.ClosestPointOnLine(point, line);
|
2023-12-04 17:48:22 +03:00
|
|
|
|
|
|
|
Vector2 normal = contactPoint - point;
|
2023-12-05 14:47:17 +03:00
|
|
|
if (normal.LengthSquared() < 0.001f)
|
|
|
|
normal = new Vector2(0f, 1f);
|
|
|
|
|
2023-12-04 13:35:31 +03:00
|
|
|
normal.Normalize();
|
2023-12-04 17:48:22 +03:00
|
|
|
|
|
|
|
collisionInformation = new CollisionInformation(normal, contactPoint);
|
2023-12-04 13:35:31 +03:00
|
|
|
break;
|
|
|
|
}
|
2023-12-01 17:42:07 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void RecalculateVertices()
|
|
|
|
{
|
|
|
|
triangles.Clear();
|
|
|
|
|
2023-12-04 12:32:28 +03:00
|
|
|
_vertices.Clear();
|
2023-12-04 13:14:23 +03:00
|
|
|
foreach (var vertex in verticesOriginal)
|
2023-12-04 13:35:31 +03:00
|
|
|
{
|
|
|
|
Vector2 scaledPosition = new Vector2(vertex.X * Transform.Scale.X * OffsetScale.X, vertex.Y * Transform.Scale.Y * OffsetScale.Y);
|
|
|
|
_vertices.Add(scaledPosition + Transform.Position);
|
|
|
|
}
|
2023-12-04 12:32:28 +03:00
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
Triangle superTriangle = PhysicsMath.GetSuperTriangle(_vertices);
|
2023-12-01 17:42:07 +03:00
|
|
|
triangles.Add(superTriangle);
|
|
|
|
|
|
|
|
List<Triangle> badTriangles = new(32);
|
2023-12-05 17:04:26 +03:00
|
|
|
List<Line> polygon = new(32);
|
2023-12-01 17:42:07 +03:00
|
|
|
|
|
|
|
foreach (var vertex in _vertices)
|
|
|
|
{
|
|
|
|
badTriangles.Clear();
|
|
|
|
polygon.Clear();
|
|
|
|
|
|
|
|
foreach (var triangle in triangles)
|
|
|
|
{
|
2023-12-05 17:04:26 +03:00
|
|
|
Circle circle = PhysicsMath.GetCircumCircle(triangle);
|
2023-12-01 17:42:07 +03:00
|
|
|
if (Vector2.DistanceSquared(circle.Center, vertex) <= circle.Radius * circle.Radius)
|
|
|
|
badTriangles.Add(triangle);
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach (var triangle in badTriangles)
|
2023-12-05 17:04:26 +03:00
|
|
|
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);
|
2023-12-01 17:42:07 +03:00
|
|
|
|
|
|
|
foreach (var triangle in badTriangles)
|
|
|
|
triangles.Remove(triangle);
|
|
|
|
|
2023-12-05 17:04:26 +03:00
|
|
|
foreach (var line in polygon)
|
|
|
|
triangles.Add(new(line.From, line.To, vertex));
|
2023-12-01 17:42:07 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2023-12-05 14:47:17 +03:00
|
|
|
for (int i = gameObjects.Count - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
IGameObject gameObject = gameObjects[i];
|
|
|
|
Game1.gameManager.RemoveGameObject(gameObject);
|
|
|
|
gameObjects.RemoveAt(i);
|
|
|
|
}
|
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
|
2023-12-05 14:47:17 +03:00
|
|
|
for (int i = 0; i < triangles.Count; i++)
|
|
|
|
{
|
|
|
|
Triangle triangle = triangles[i];
|
2023-12-05 17:04:26 +03:00
|
|
|
foreach (var line in PhysicsMath.GetLines([triangle.A, triangle.B, triangle.C]))
|
2023-12-05 14:47:17 +03:00
|
|
|
{
|
|
|
|
GameObject gameObject = Game1.gameManager.InstantiateGameObject<GameObject>();
|
|
|
|
DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>();
|
|
|
|
displayableSpriteBehaviour.Color = Color.Aqua;
|
|
|
|
displayableSpriteBehaviour.Origin = new(0.5f, 1f);
|
|
|
|
displayableSpriteBehaviour.Assign(Game1.spriteBox);
|
2023-12-05 17:04:26 +03:00
|
|
|
gameObject.Transform.Position = line.From;
|
|
|
|
Vector2 vector2 = line.To - line.From;
|
2023-12-05 14:47:17 +03:00
|
|
|
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<GameObject>();
|
|
|
|
displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>();
|
|
|
|
displayableSpriteBehaviour.Color = Color.Crimson;
|
|
|
|
displayableSpriteBehaviour.Assign(Game1.spriteBox);
|
2023-12-05 17:04:26 +03:00
|
|
|
gameObject.Transform.Position = line.To;
|
2023-12-05 14:47:17 +03:00
|
|
|
gameObject.Transform.Scale = new Vector2(4f, 4f);
|
|
|
|
gameObjects.Add(gameObject);
|
|
|
|
}
|
|
|
|
}
|
2023-12-01 17:42:07 +03:00
|
|
|
|
2023-12-05 14:47:17 +03:00
|
|
|
foreach (var vertex in Vertices)
|
|
|
|
{
|
|
|
|
GameObject gameObject = Game1.gameManager.InstantiateGameObject<GameObject>();
|
|
|
|
DisplayableSpriteBehaviour displayableSpriteBehaviour = gameObject.BehaviourController.AddBehaviour<DisplayableSpriteBehaviour>();
|
|
|
|
displayableSpriteBehaviour.Color = Color.GreenYellow;
|
|
|
|
displayableSpriteBehaviour.Assign(Game1.spriteBox);
|
|
|
|
gameObject.Transform.Position = vertex;
|
|
|
|
gameObject.Transform.Scale = new Vector2(2f, 2f);
|
|
|
|
gameObjects.Add(gameObject);
|
|
|
|
}
|
2023-12-01 17:42:07 +03:00
|
|
|
}
|
|
|
|
|
2023-12-05 14:47:17 +03:00
|
|
|
private List<IGameObject> gameObjects = new List<IGameObject>(32);
|
|
|
|
|
2023-12-01 17:42:07 +03:00
|
|
|
}
|