using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Engine.Core; namespace Engine.Integration.MonoGame; public class MonoGameCamera2D : Behaviour, ICamera2D, IFirstFrameUpdate, ILastFrameUpdate, IPreDraw, IUpdate { public Event OnViewMatrixChanged { get; } = new(); public Event OnProjectionMatrixChanged { get; } = new(); public Event OnViewportChanged { get; } = new(); public Event OnZoomChanged { get; } = new(); public GraphicsDeviceManager Graphics { get; private set; } = null!; public ITransform2D Transform { get; private set; } = null!; public Matrix4x4 ProjectionMatrix { get; private set { if (field == value) return; field = value; OnProjectionMatrixChanged.Invoke(this); } } = Matrix4x4.Identity; public Matrix4x4 ViewMatrix { get; private set { if (field == value) return; field = value; OnViewMatrixChanged.Invoke(this); } } = Matrix4x4.Identity; public Viewport Viewport { get; set { if (field.Equals(value)) return; field = value; OnViewportChanged.Invoke(this); } } = default; public float Zoom { get; set { float newValue = Math.Max(0.1f, value); if (field == newValue) return; field = newValue; OnZoomChanged.Invoke(this); } } = 1f; // 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(), ViewMatrix.Inverse.ToXnaMatrix()).ToVector2D(); return worldPosition.Scale(EngineConverterExtensions.screenScale); } public Vector2D WorldToScreenPosition(Vector2D worldPosition) { Vector2D screenPosition = Vector2.Transform(worldPosition.ToVector2(), ViewMatrix.ToXnaMatrix()).ToVector2D(); return screenPosition.Scale(EngineConverterExtensions.screenScale); } public void LastActiveFrame() => Transform = null!; public void FirstActiveFrame() { Graphics = BehaviourController.UniverseObject.Universe.FindRequiredBehaviour().Window.Graphics; Viewport = Graphics.GraphicsDevice.Viewport; Transform = BehaviourController.GetRequiredBehaviour(); } public void PreDraw() { ProjectionMatrix = Matrix4x4.CreateOrthographicViewCentered(Viewport.Width, -Viewport.Height); ViewMatrix = Matrix4x4.CreateTranslation(new Vector3D(-Transform.Position.X, Transform.Position.Y, 0f)) .ApplyRotationZ(Transform.Rotation * Math.DegreeToRadian) .ApplyScale(Transform.Scale.X.Max(Transform.Scale.Y)) .ApplyScale(Zoom); } public void Update() { KeyboardInputs keyboardInputs = Universe.FindRequiredBehaviour(); if (keyboardInputs.IsPressed(Keys.Right)) Transform.Position += Transform.Right * Universe.Time.DeltaTime * 100; if (keyboardInputs.IsPressed(Keys.Up)) Transform.Position += Transform.Up * Universe.Time.DeltaTime * 100; if (keyboardInputs.IsPressed(Keys.Down)) Transform.Position += Transform.Down * Universe.Time.DeltaTime * 100; if (keyboardInputs.IsPressed(Keys.Left)) Transform.Position += Transform.Left * Universe.Time.DeltaTime * 100; } }