Files
LunaLightXMG/Camera2D.cs
T
2025-03-30 14:55:16 -07:00

123 lines
3.9 KiB
C#

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 = 5.0f;
// Screen Shake
private float shakeTimeRemaining = 0f;
private float shakeMagnitudeCurrent = 0f;
private bool shaking = false;
// Util
readonly 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(GameTime gameTime, Vector2 targetPostion)
{
float smoothSpeed = camSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
position = Vector2.Lerp(position, targetPostion, smoothSpeed);
if (Vector2.Distance(position, targetPostion) < 1.0f)
{
position = targetPostion;
}
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.RandomFromRange(-shakeMagnitudeCurrent, shakeMagnitudeCurrent);
float shakeY = util.RandomFromRange(-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);
}
}
}