Syntriax.Engine/Engine.Core/Transform.cs

249 lines
6.1 KiB
C#
Raw Normal View History

2023-11-23 22:07:49 +03:00
using System;
2024-02-06 12:34:18 +03:00
using System.Collections;
using System.Collections.Generic;
2023-11-23 22:07:49 +03:00
using Syntriax.Engine.Core.Abstract;
namespace Syntriax.Engine.Core;
2024-02-06 12:57:01 +03:00
[System.Diagnostics.DebuggerDisplay("Position: {Position.ToString(), nq}, Scale: {Scale.ToString(), nq}, Rotation: {Rotation}")]
2023-11-23 22:07:49 +03:00
public class Transform : ITransform
{
public Action<ITransform>? OnPositionChanged { get; set; } = null;
public Action<ITransform>? OnScaleChanged { get; set; } = null;
public Action<ITransform>? OnRotationChanged { get; set; } = null;
2024-02-06 12:34:18 +03:00
public Action<ITransform, ITransform?>? OnParentChanged { get; set; } = null;
public Action<ITransform, ITransform>? OnChildrenAdded { get; set; } = null;
public Action<ITransform, ITransform>? OnChildrenRemoved { get; set; } = null;
private Vector2D _position = Vector2D.Zero;
private Vector2D _scale = Vector2D.One;
2023-11-23 22:07:49 +03:00
private float _rotation = 0f;
2024-02-06 12:34:18 +03:00
private Vector2D _localPosition = Vector2D.Zero;
private Vector2D _localScale = Vector2D.One;
private float _localRotation = 0f;
private readonly List<ITransform> _children = [];
public ITransform? Parent { get; private set; } = null;
public IReadOnlyList<ITransform> Children => _children;
public Vector2D Position
2023-11-23 22:07:49 +03:00
{
get => _position;
set
{
if (value == _position)
return;
_position = value;
2024-02-06 12:34:18 +03:00
UpdateLocalPosition();
2023-11-23 22:07:49 +03:00
OnPositionChanged?.Invoke(this);
}
}
public Vector2D Scale
2023-11-23 22:07:49 +03:00
{
get => _scale;
set
{
if (value == _scale)
return;
_scale = value;
2024-02-06 12:34:18 +03:00
UpdateLocalScale();
2023-11-23 22:07:49 +03:00
OnScaleChanged?.Invoke(this);
}
}
public float Rotation
{
get => _rotation;
set
{
if (value == _rotation)
return;
_rotation = value;
2024-02-06 12:34:18 +03:00
UpdateLocalPosition();
OnRotationChanged?.Invoke(this);
}
}
public Vector2D LocalPosition
{
get => _localPosition;
set
{
if (value == _localPosition)
return;
_localPosition = value;
UpdatePosition();
OnPositionChanged?.Invoke(this);
}
}
public Vector2D LocalScale
{
get => _localScale;
set
{
if (value == _localScale)
return;
_localScale = value;
UpdateScale();
OnScaleChanged?.Invoke(this);
}
}
public float LocalRotation
{
get => _localRotation;
set
{
if (value == _localRotation)
return;
_localRotation = value;
UpdateRotation();
2023-11-23 22:07:49 +03:00
OnRotationChanged?.Invoke(this);
}
}
2024-02-06 12:34:18 +03:00
public void SetParent(ITransform? transform)
{
if (transform == this || Parent == transform)
return;
ITransform? previousParent = Parent;
if (Parent is not null)
{
Parent.RemoveChild(this);
Parent.OnPositionChanged -= RecalculatePosition;
Parent.OnScaleChanged -= RecalculateScale;
Parent.OnRotationChanged -= RecalculateRotation;
}
Parent = transform;
if (transform is not null)
{
transform.AddChild(this);
transform.OnPositionChanged += RecalculatePosition;
transform.OnScaleChanged += RecalculateScale;
transform.OnRotationChanged += RecalculateRotation;
}
UpdateLocalPosition();
UpdateLocalScale();
UpdateLocalRotation();
OnParentChanged?.Invoke(this, previousParent);
}
public void AddChild(ITransform transform)
{
if (_children.Contains(transform))
return;
_children.Add(transform);
transform.SetParent(this);
OnChildrenAdded?.Invoke(this, transform);
}
public void RemoveChild(ITransform transform)
{
if (!_children.Remove(transform))
return;
transform.SetParent(null);
OnChildrenRemoved?.Invoke(this, transform);
}
public IEnumerator<ITransform> GetEnumerator() => _children.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => _children.GetEnumerator();
private void RecalculatePosition(ITransform _)
{
if (Parent is null)
return;
UpdatePosition();
OnPositionChanged?.Invoke(this);
}
private void RecalculateScale(ITransform _)
{
if (Parent is null)
return;
UpdateScale();
OnScaleChanged?.Invoke(this);
}
private void RecalculateRotation(ITransform _)
{
if (Parent is null)
return;
UpdatePosition();
UpdateRotation();
OnPositionChanged?.Invoke(this);
OnRotationChanged?.Invoke(this);
}
private void UpdateLocalPosition()
{
if (Parent is null)
_localPosition = Position;
else
_localPosition = Parent.Position.FromTo(Position).Scale(Parent.Scale);
}
private void UpdateLocalScale()
{
if (Parent is null)
_localScale = Scale;
else
_localScale = Scale.Scale(new(1f / Parent.Scale.X, 1f / Parent.Scale.Y));
}
private void UpdateLocalRotation()
{
if (Parent is null)
_localRotation = Rotation;
else
_localRotation = Rotation - Parent.Rotation;
}
private void UpdatePosition()
{
if (Parent is null)
_position = LocalPosition.Scale(Vector2D.One).Rotate(0f * Math.DegreeToRadian);
else
_position = Parent.Position + LocalPosition.Scale(new(1f / Parent.Scale.X, 1f / Parent.Scale.Y)).Rotate(Parent.Rotation * Math.DegreeToRadian);
}
private void UpdateScale()
{
if (Parent is null)
_scale = LocalScale;
else
_scale = Vector2D.Scale(Parent.Scale, LocalScale);
}
private void UpdateRotation()
{
if (Parent is null)
_rotation = LocalRotation;
else
_rotation = Parent.Rotation + LocalRotation;
}
2023-11-23 22:07:49 +03:00
}