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.OnPositionChangedEventHandler? OnPositionChanged = null; public event ITransform2D.OnScaleChangedEventHandler? OnScaleChanged = null; public event ITransform2D.OnRotationChangedEventHandler? 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(); 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); } }