ARTICLE AD BOX
I have some trouble getting this code to work. I have a debug screen where I can see the player and the mouse position, but if they don't match even though the cursor is above the player.
Here is the relevant code:
using System; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using TheCore.Entities.Characters; using TheCore.Entities.Components.Core; using TheCore.Utils.Geometry; namespace TheCore.World; public class Camera { private readonly float _cameraHeight = 720f; // Virtual camera size private readonly float _cameraWidth = 1280f; private Vector2 _mapSize; private Player _player; private int _tileSize; private Viewport _viewport; private Vector2 _targetPosition; private float _followSpeed = 8f; public Vector2 Position; public Camera() { Transform = Matrix.Identity; } public Vector2 ClampedPosition { get; private set; } public Matrix Transform { get; private set; } public void SetTarget(Player player) { _player = player; } /// <summary> /// Provides the camera with map size so it never moves outside the map /// </summary> public void SetMapAndTiles(Vector2 mapSize, int tileSize) { _mapSize = mapSize; _tileSize = tileSize; } public void Update() { _viewport = Globals.CoreServices.WindowManager.ScaledViewport; _targetPosition = _player.GetComponent<Transform>().Position; float delta = Globals.DeltaTime; Position = Vector2.Lerp( Position, _targetPosition, 1f - MathF.Exp(-_followSpeed * delta)); CalculateTransform(); } /// <summary> /// Creates the final world-to-screen transformation matrix /// </summary> private void CalculateTransform() { // Scales the camera base size based on the scaled viewport var scaleX = _viewport.Width / _cameraWidth; var scaleY = _viewport.Height / _cameraHeight; var scale = Math.Min(scaleX, scaleY); // Clamp camera center inside the map boundaries var posX = Math.Clamp(Position.X, _cameraWidth / 2, _mapSize.X * _tileSize - _cameraWidth / 2); var posY = Math.Clamp(Position.Y, _cameraHeight / 2, _mapSize.Y * _tileSize - _cameraHeight / 2); ClampedPosition = new Vector2(posX, posY); Transform = Matrix.CreateTranslation(new Vector3(-posX, -posY, 0f)) * Matrix.CreateTranslation(new Vector3(_cameraWidth / 2f, _cameraHeight / 2f, 0f)) * Matrix.CreateScale(scale, scale, 1f); } public RectangleF GetWorldViewBounds() { return new RectangleF( ClampedPosition.X - _cameraWidth / 2f, ClampedPosition.Y - _cameraHeight / 2f, _cameraWidth, _cameraHeight ); } public Vector2 RenderToWorld(Vector2 renderPos) { Matrix inverseTransform = Matrix.Invert(Transform); Vector2 mouseInWorld = Vector2.Transform(renderPos, inverseTransform); return mouseInWorld; /*Vector2 renderCenter = new Vector2( Globals.CoreServices.WindowManager.RenderWidth / 2f, Globals.CoreServices.WindowManager.RenderHeight / 2f ); return ClampedPosition + (renderPos - renderCenter);*/ } } using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using System; namespace TheCore.Services { public class WindowManager { private readonly Game _game; private readonly GraphicsDeviceManager _graphics; // Base resolution public int RenderWidth = 1920; public int RenderHeight = 1080; // public RenderTarget2D RenderTarget {get; set;} // private int _windowWidth; private int _windowHeight; // The resolution will be scaled on these values given the window size of the player private int _scaledWidth; private int _scaledHeight; public bool IsFullsize = false; public GraphicsDevice GraphicsDevice => _graphics.GraphicsDevice; public Viewport ScaledViewport { get; private set; } // This matrix is important for the spritebatches to scale everything public Matrix ScaledMatrix { get { float scaleX = (float)_scaledWidth / RenderWidth; float scaleY = (float)_scaledHeight / RenderHeight; float scale = Math.Min(scaleX, scaleY); return Matrix.CreateScale(scale, scale, 1f); } } public WindowManager(Game game, GraphicsDeviceManager graphics) { _game = game; _graphics = graphics; _graphics.HardwareModeSwitch = false; game.IsFixedTimeStep = false; _graphics.SynchronizeWithVerticalRetrace = true; SetupWindow(); } /// <summary> /// Setups the window when the game starts /// </summary> private void SetupWindow() { // _windowWidth = RenderWidth; _windowHeight = RenderHeight; _game.Window.AllowUserResizing = true; _game.Window.ClientSizeChanged += OnWindowResize; _graphics.IsFullScreen = IsFullsize; UpdateScaledViewport(); CreateRenderTarget(); } /// <summary> /// Calls the viewport update function if player resizes the window /// </summary> private void OnWindowResize(object sender, EventArgs e) { UpdateScaledViewport(); } /// <summary> /// Updates the visible viewport based on the window size of the player /// </summary> private void UpdateScaledViewport() { int windowW = _graphics.GraphicsDevice.PresentationParameters.BackBufferWidth; int windowH = _graphics.GraphicsDevice.PresentationParameters.BackBufferHeight; float targetAspect = (float)RenderWidth / RenderHeight; float windowAspect = (float)windowW / windowH; int vpWidth, vpHeight, vpX, vpY; if (windowAspect > targetAspect) { // Window higher --> backgroundcolour visible left/right vpHeight = windowH; vpWidth = (int)(vpHeight * targetAspect); vpX = (windowW - vpWidth) / 2; vpY = 0; } else { // Window higher --> backgroundcolour visible up/down vpWidth = windowW; vpHeight = (int)(vpWidth / targetAspect); vpX = 0; vpY = (windowH - vpHeight) / 2; } ScaledViewport = new Viewport(vpX, vpY, vpWidth, vpHeight); _graphics.GraphicsDevice.Viewport = ScaledViewport; _scaledWidth = vpWidth; _scaledHeight = vpHeight; } public void ChangeFullsize() { IsFullsize = !IsFullsize; _graphics.IsFullScreen = IsFullsize; _graphics.ApplyChanges(); } public void SetFullScreen(bool enable) { if (enable == IsFullsize) return; IsFullsize = enable; _graphics.IsFullScreen = enable; if (!enable) { _graphics.PreferredBackBufferWidth = _windowWidth; _graphics.PreferredBackBufferHeight = _windowHeight; } if (enable) { _windowWidth= _graphics.PreferredBackBufferWidth; _windowHeight= _graphics.PreferredBackBufferHeight; } _graphics.ApplyChanges(); UpdateScaledViewport(); } public void SetResolution(int index) { var resolutions = new (int width, int height)[] { (1280, 720), (1600, 900), (1920, 1080) }; index = MathHelper.Clamp(index, 0, resolutions.Length - 1); var res = resolutions[index]; RenderWidth = res.width; RenderHeight = res.height; CreateRenderTarget(); UpdateScaledViewport(); } private void CreateRenderTarget() { if(RenderTarget != null) { RenderTarget.Dispose(); RenderTarget = null; } RenderTarget = new RenderTarget2D(_graphics.GraphicsDevice, RenderWidth, RenderHeight); } // To transform mouseclicks public Vector2 MouseWindowToRender(Vector2 mouseWindow) { float x = (mouseWindow.X - ScaledViewport.X) * RenderWidth / ScaledViewport.Width; float y = (mouseWindow.Y - ScaledViewport.Y) * RenderHeight / ScaledViewport.Height; return new Vector2(x, y); } public void f11FullScreen() { SetFullScreen(!IsFullsize); } } }My Input Manager:
var rawMouse = currMouseState.Position.ToVector2(); var gameMouse = Globals.CoreServices.WindowManager.MouseWindowToRender(rawMouse); return new InputState(gameMouse, activeActions);With the gameMouse I then apply
worldManager.Camera.RenderToWorld(gameMouse);but this position does not seem to be right.
Is there something wrong with the way I am scaling my mouse position or where else could the code be wrong?
