LADXHD/InGame/Map/Camera.cs
2023-12-14 17:21:22 -05:00

147 lines
4.9 KiB
C#

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ProjectZ.InGame.Things;
namespace ProjectZ.InGame.Map
{
public class Camera
{
public Matrix TransformMatrix => Matrix.CreateScale(Scale) *
Matrix.CreateTranslation(new Vector3(-RoundX, -RoundY, 0)) *
Matrix.CreateTranslation(new Vector3((int)(_viewportWidth * 0.5f), (int)(_viewportHeight * 0.5f), 0)) *
Game1.GameManager.GetMatrix;
public Vector2 Location;
public Vector2 MoveLocation;
// this is needed so there is no texture bleeding while rendering the game
public float RoundX => (int)Math.Round(Location.X + ShakeOffsetX * Scale, MidpointRounding.AwayFromZero);
public float RoundY => (int)Math.Round(Location.Y + ShakeOffsetY * Scale, MidpointRounding.AwayFromZero);
public float Scale = 4;
public float ShakeOffsetX;
public float ShakeOffsetY;
public float CameraFollowMultiplier = 1;
public int X => (int)Math.Round(Location.X + ShakeOffsetX * Scale);
public int Y => (int)Math.Round(Location.Y + ShakeOffsetY * Scale);
private Vector2 _cameraDistance;
private int _viewportWidth;
private int _viewportHeight;
public void SetBounds(int viewportWidth, int viewportHeight)
{
_viewportWidth = viewportWidth;
_viewportHeight = viewportHeight;
}
public Rectangle GetCameraRectangle()
{
var rectangle = new Rectangle(
(int)RoundX - _viewportWidth / 2,
(int)RoundY - _viewportHeight / 2,
_viewportWidth, _viewportHeight);
return rectangle;
}
public Rectangle GetGameView()
{
var rectangle = new Rectangle(
(int)(RoundX / Scale) - (int)(_viewportWidth / 2 / Scale),
(int)(RoundY / Scale) - (int)(_viewportHeight / 2 / Scale),
(int)(_viewportWidth / Scale), (int)(_viewportHeight / Scale));
return rectangle;
}
public Rectangle GetGameViewBig()
{
var rectangle = new Rectangle(
(int)(RoundX / Scale) - Values.MinWidth,
(int)(RoundY / Scale) - Values.MinHeight,
Values.MinWidth * 2, Values.MinHeight * 2);
return rectangle;
}
public void Center(Vector2 position, bool moveX, bool moveY)
{
if (!GameSettings.SmoothCamera)
{
Location = position;
return;
}
var direction = position - MoveLocation;
if (direction != Vector2.Zero)
{
var distance = direction.Length() / Scale * CameraFollowMultiplier;
var speedMult = CameraFunction(distance / 12.5f);
direction.Normalize();
var cameraSpeed = direction * speedMult * Scale * Game1.TimeMultiplier;
if (moveX)
MoveLocation.X += cameraSpeed.X;
if (moveY)
MoveLocation.Y += cameraSpeed.Y;
if (distance <= 0.1f * Game1.TimeMultiplier)
MoveLocation = position;
}
// this is needed so the player does not wiggle around while the camera is following him
if (moveX)
_cameraDistance.X = position.X - MoveLocation.X;
if (moveY)
_cameraDistance.Y = position.Y - MoveLocation.Y;
Location = new Vector2((int)Math.Round(position.X), (int)Math.Round(position.Y)) - _cameraDistance;
}
private float CameraFunction(float x)
{
var y = MathF.Atan(x);
if (x > 2)
y += (x - 2) / 2;
return y + 0.1f;
}
public void ForceUpdate(Vector2 lockPosition)
{
MoveLocation = lockPosition;
Location = lockPosition;
}
public void SoftUpdate(Vector2 position)
{
MoveLocation = position - _cameraDistance;
Location = position;
}
public void OffsetCameraDistance(Vector2 offset)
{
_cameraDistance += offset;
}
public void Draw(SpriteBatch spriteBatch)
{
if (!Game1.DebugMode)
return;
var size = 10;
spriteBatch.Draw(Resources.SprWhite, new Rectangle(
Game1.WindowWidthEnd / 2 - (int)(size * Scale),
Game1.WindowHeightEnd / 2 - (int)(size * Scale),
(int)(size * Scale * 2),
(int)(size * Scale * 2)), Color.Pink * 0.25f);
}
}
}