Engine-Pong/Game/Physics2D/Collider2DBehaviour.cs

186 lines
7.0 KiB
C#
Raw Normal View History

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
}