using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace LunaLightXMG { public class Camera2D { // Fields private readonly Viewport viewport; private float zoom; private float rotation; private Vector2 position; private Rectangle levelBounds; private readonly float camSpeed = 0.1f; // Screen Shake private float shakeTimeRemaining = 0f; private float shakeMagnitudeCurrent = 0f; private bool shaking = false; // Util Utilities util; // Getters and setters public Vector2 Position { get => position; set => position = value; } public float Zoom { get => zoom; set => zoom = (int)Math.Floor(MathHelper.Clamp(value, 1f, 2f)); } public float Rotation { get => rotation; set => rotation = value; } // constructor public Camera2D(int width, int height) { viewport = new Viewport(0, 0, width, height); levelBounds = new Rectangle(0, 0, 320, 180); // Default zoom = 1f; rotation = 0f; position = Vector2.Zero; util = new Utilities(); } public Matrix GetViewMatrix() { return Matrix.CreateTranslation(new Vector3(-position, 0f)) * Matrix.CreateRotationZ(rotation) * Matrix.CreateScale(zoom, zoom, 1f) * Matrix.CreateTranslation(new Vector3(viewport.Width * 0.5f, viewport.Height * 0.5f, 0f)); } public void SetLevelBounds(Rectangle bounds) { levelBounds = bounds; } public void Follow(Vector2 targetPostion) { position += (targetPostion - position) * camSpeed; if (Math.Abs(position.X - targetPostion.X) < 0.1f) { position.X = targetPostion.X; } if (Math.Abs(position.Y - targetPostion.Y) < 0.1f) { position.Y = targetPostion.Y; } ClampToBounds(); } public void ScreenShake(float shakeTime, float shakeMagnitude) { shakeTimeRemaining = shakeTime; shakeMagnitudeCurrent = shakeMagnitude; shaking = true; } public void UpdateScreenShake(GameTime gameTime) { if (!shaking) return; if (shakeTimeRemaining > 0) { float shakeX = util.ChooseFromRange(-shakeMagnitudeCurrent, shakeMagnitudeCurrent); float shakeY = util.ChooseFromRange(-shakeMagnitudeCurrent, shakeMagnitudeCurrent); position.X += shakeX; position.Y += shakeY; shakeTimeRemaining -= (float)gameTime.ElapsedGameTime.TotalSeconds; shakeMagnitudeCurrent *= 0.9f; } else { shaking = false; shakeTimeRemaining = 0f; shakeMagnitudeCurrent = 0f; } } private void ClampToBounds() { // Calculate the cam's half viewport size var halfViewportWidth = viewport.Width * 0.5f / zoom; var halfViewportHeight = viewport.Height * 0.5f / zoom; // Clamp cam to level bounds float minX = levelBounds.Left + halfViewportWidth; float maxX = levelBounds.Right - halfViewportWidth; float minY = levelBounds.Top + halfViewportHeight; float maxY = levelBounds.Bottom - halfViewportHeight; // Set cam position within level bounds position.X = MathHelper.Clamp(position.X, minX, maxX); position.Y = MathHelper.Clamp(position.Y, minY, maxY); } } }