using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Syntriax.Engine.Core; namespace Syntriax.Engine.Integration.MonoGame; public class MonoGameCamera2DBehaviour : BehaviourBase, ICamera2D, IFirstFrameUpdate, IPreDraw { public event MatrixTransformChangedArguments? OnMatrixTransformChanged = null; public event ViewportChangedArguments? OnViewportChanged = null; public event ZoomChangedArguments? OnZoomChanged = null; private Matrix _matrixTransform = Matrix.Identity; private Viewport _viewport = default; private float _zoom = 1f; public GraphicsDeviceManager Graphics { get; private set; } = null!; public ITransform2D Transform { get; private set; } = null!; public Matrix MatrixTransform { get => _matrixTransform; set { if (_matrixTransform == value) return; _matrixTransform = value; OnMatrixTransformChanged?.Invoke(this); } } public Vector2D Position { get => Transform.Position; set => Transform.Position = value; } public Viewport Viewport { get => _viewport; set { if (_viewport.Equals(value)) return; _viewport = value; OnViewportChanged?.Invoke(this); } } public float Zoom { get => _zoom; set { float newValue = Syntriax.Engine.Core.Math.Max(0.1f, value); if (_zoom == newValue) return; _zoom = newValue; OnZoomChanged?.Invoke(this); } } public float Rotation { get => Transform.Rotation; set => Transform.Rotation = value; } // TODO This causes delay since OnPreDraw calls assuming this is called in in Update public Vector2D ScreenToWorldPosition(Vector2D screenPosition) { Vector2D worldPosition = Vector2.Transform(screenPosition.ToVector2(), Matrix.Invert(MatrixTransform)).ToVector2D(); return worldPosition.Scale(EngineConverterExtensions.screenScale); } public Vector2D WorldToScreenPosition(Vector2D worldPosition) { Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), MatrixTransform).ToVector2D(); return screenPosition.Scale(EngineConverterExtensions.screenScale); } public void FirstActiveFrame() { Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour().Window.Graphics; Viewport = Graphics.GraphicsDevice.Viewport; } public void PreDraw() { MatrixTransform = Matrix.CreateTranslation(new Vector3(-Position.X, Position.Y, 0f)) * Matrix.CreateRotationZ(Rotation * Syntriax.Engine.Core.Math.DegreeToRadian) * Matrix.CreateScale(Transform.Scale.X.Max(Transform.Scale.Y)) * Matrix.CreateScale(Zoom) * Matrix.CreateTranslation(new Vector3(_viewport.Width * .5f, _viewport.Height * .5f, 0f)); } protected sealed override void InitializeInternal() => Transform = BehaviourController.GetRequiredBehaviour(); protected sealed override void FinalizeInternal() => Transform = null!; public delegate void MatrixTransformChangedArguments(MonoGameCamera2DBehaviour sender); public delegate void ViewportChangedArguments(MonoGameCamera2DBehaviour sender); public delegate void ZoomChangedArguments(MonoGameCamera2DBehaviour sender); }