Syntriax.Engine/Engine.Core/Transform2D.cs

256 lines
7.1 KiB
C#

using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Core;
[System.Diagnostics.DebuggerDisplay("Name: {HierarchyObject.Name, nq} Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
public class Transform2D : Behaviour, ITransform2D
{
public event ITransform2D.PositionChangedEventHandler? OnPositionChanged = null;
public event ITransform2D.ScaleChangedEventHandler? OnScaleChanged = null;
public event ITransform2D.RotationChangedEventHandler? OnRotationChanged = null;
private Vector2D _position = Vector2D.Zero;
private Vector2D _scale = Vector2D.One;
private float _rotation = 0f;
private Vector2D _localPosition = Vector2D.Zero;
private Vector2D _localScale = Vector2D.One;
private float _localRotation = 0f;
private ITransform2D? parentTransform = null;
public Vector2D Position
{
get => _position;
set
{
if (value == _position)
return;
Vector2D previousPosition = _position;
_position = value;
UpdateLocalPosition();
OnPositionChanged?.Invoke(this, _position);
}
}
public Vector2D Scale
{
get => _scale;
set
{
if (value == _scale)
return;
Vector2D previousScale = _scale;
_scale = value;
UpdateLocalScale();
OnScaleChanged?.Invoke(this, previousScale);
}
}
public float Rotation
{
get => _rotation;
set
{
if (value == _rotation)
return;
float previousRotation = _rotation;
_rotation = value;
UpdateLocalRotation();
OnRotationChanged?.Invoke(this, previousRotation);
}
}
public Vector2D LocalPosition
{
get => _localPosition;
set
{
if (value == _localPosition)
return;
Vector2D previousPosition = _position;
_localPosition = value;
UpdatePosition();
OnPositionChanged?.Invoke(this, previousPosition);
}
}
public Vector2D LocalScale
{
get => _localScale;
set
{
if (value == _localScale)
return;
Vector2D previousScale = _scale;
_localScale = value;
UpdateScale();
OnScaleChanged?.Invoke(this, previousScale);
}
}
public float LocalRotation
{
get => _localRotation;
set
{
if (value == _localRotation)
return;
float previousRotation = _rotation;
_localRotation = value;
UpdateRotation();
OnRotationChanged?.Invoke(this, previousRotation);
}
}
private void RecalculatePosition(ITransform2D _, Vector2D previousPosition)
{
if (parentTransform is null)
return;
float previousRotation = Rotation;
UpdatePosition();
UpdateRotation();
OnPositionChanged?.Invoke(this, previousPosition);
OnRotationChanged?.Invoke(this, previousRotation);
}
private void RecalculateScale(ITransform2D _, Vector2D previousScale)
{
if (parentTransform is null)
return;
UpdateScale();
OnScaleChanged?.Invoke(this, previousScale);
}
private void RecalculateRotation(ITransform2D _, float previousRotation)
{
if (parentTransform is null)
return;
Vector2D previousPosition = Position;
UpdatePosition();
UpdateRotation();
OnPositionChanged?.Invoke(this, previousPosition);
OnRotationChanged?.Invoke(this, previousRotation);
}
private void UpdateLocalPosition()
{
if (parentTransform is null)
_localPosition = Position;
else
_localPosition = parentTransform.Position.FromTo(Position).Scale(parentTransform.Scale);
}
private void UpdateLocalScale()
{
if (parentTransform is null)
_localScale = Scale;
else
_localScale = Scale.Scale(new(1f / parentTransform.Scale.X, 1f / parentTransform.Scale.Y));
}
private void UpdateLocalRotation()
{
if (parentTransform is null)
_localRotation = Rotation;
else
_localRotation = Rotation - parentTransform.Rotation;
}
private void UpdatePosition()
{
if (parentTransform is null)
_position = LocalPosition.Rotate(0f * Math.DegreeToRadian);
else
_position = parentTransform.Position + LocalPosition.Scale(new(parentTransform.Scale.X, parentTransform.Scale.Y)).Rotate(parentTransform.Rotation * Math.DegreeToRadian);
}
private void UpdateScale()
{
if (parentTransform is null)
_scale = LocalScale;
else
_scale = (parentTransform?.Scale ?? Vector2D.One).Scale(_localScale);
}
private void UpdateRotation()
{
if (parentTransform is null)
_rotation = LocalRotation;
else
_rotation = parentTransform.Rotation + LocalRotation;
}
protected override void InitializeInternal()
{
UpdateParent(BehaviourController.HierarchyObject.Parent);
BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged;
}
protected override void FinalizeInternal()
{
BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged;
}
private void UpdateParent(IHierarchyObject? parent)
{
ITransform2D? previousParent = parentTransform;
if (previousParent is not null)
{
previousParent.BehaviourController.HierarchyObject.RemoveChild(HierarchyObject);
previousParent.OnPositionChanged -= RecalculatePosition;
previousParent.OnScaleChanged -= RecalculateScale;
previousParent.OnRotationChanged -= RecalculateRotation;
previousParent.BehaviourController.HierarchyObject.OnParentChanged -= OnParentChanged;
}
parentTransform = parent?.BehaviourController.GetBehaviour<ITransform2D>();
if (parentTransform is not null)
{
parentTransform.BehaviourController.HierarchyObject.AddChild(HierarchyObject);
parentTransform.OnPositionChanged += RecalculatePosition;
parentTransform.OnScaleChanged += RecalculateScale;
parentTransform.OnRotationChanged += RecalculateRotation;
parentTransform.BehaviourController.HierarchyObject.OnParentChanged += OnParentChanged;
UpdatePosition();
UpdateScale();
UpdateRotation();
}
UpdateLocalPosition();
UpdateLocalScale();
UpdateLocalRotation();
OnPositionChanged?.Invoke(this, Position);
OnScaleChanged?.Invoke(this, Scale);
OnRotationChanged?.Invoke(this, Rotation);
}
private void OnParentChanged(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent)
{
UpdateParent(newParent);
}
}