I’ve had this problem for a couple of weeks now, I hope someone can help.
I’m making an FPS type game, so I need to get the mouse delta for camera rotation.
I’ve tried many different tutorials for both XNA and monogame, but all of them have the same problem for me.
My input processing is as follows: pretty simple
keystate = Keyboard.GetState(); //get state of input now
mousestate = Mouse.GetState();
Point mouseRelativeToCenter = new Point(mousestate.X - windowCenterX,
mousestate.Y - windowCenterY);
mouseDelta = mouseRelativeToCenter; //how much the mouse moved this frame
if (mousestate.Position != new Point(windowCenterX, windowCenterY))
{
SetMouseToCenter(); //set to center of screen
}
keystatePrevious = keystate; //for other stuff
mousestatePrevious = mousestate;
There’s some weird issue with this, mouse.getstate doesn’t seem to return right values.
The issue is more prominent at lower framerates, it’s just rarer at higher framerates.
Code works like this:
Get current state for mouse. (let’s call this mouse position “X” for now)
Get mouse position relative to center of screen, that’s mouse movement/delta this frame.
Set mouse back to center (so next frame we can get how much the mouse moved away from the center)
Update everything else for the game etc.
Now done, next frame is the same:
Get current state for mouse
Get mouse position relative to center of screen, that’s mouse movement this frame
BUT: now there is a very likely chance (~50%-ish at 60 fps) that instead of returning the expected
position of the mouse the position returned is “X”, the position last frame, before it was set to the center. even if the mouse is not moved at all!
This causes jerky movements because the movement is effectively doubled seemingly randomly over a couple of frames.
…and of course we set the mouse back to the center now and update everything else etc…
But this is a massive issue since I can’t continue doing anything else while such a basic thing is broken.
Im doing the same for OpenGL, and found no problems. Are you sure it isnt just normal frame skipping? That often happens to me when I debug and run some youtube video at the same time.
Side note:
is pretty unessesary code that just complicates the debugging
100% sure.
I’ve also tested a build on another gaming computer. Same issue so it’s probably not hardware related.
Edit: That’s true for the position check. I figured the SetPosition() method was not setting the position fast enough or something, but that changes nothing.
This isn’t my actual project obviously, but a barebones implementation of the input system.
The issue occurs here too: If using the approach I mentioned earlier, the mouse delta is very erratic and jerky.
That doesn’t happen when I use the other method where the mouse position is not reset every frame.
Is there anything wrong with this code? As far as I have understood this is the way to go.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace InputGL
{
/// <summary>
/// This is the main type for your game.
/// </summary>
public class GameTest : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
KeyboardState previouskeystate;
MouseState previousmousestate;
Point mousedelta;
Point screencenter;
Texture2D texture;
Point point;
bool keepMouseLockedToCenter;
public GameTest()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsFixedTimeStep = true;
//TargetElapsedTime = new System.TimeSpan(0, 0, 0, 0, 33);
//at 30 fps it gets really bad, but that's a very realistic framerate
graphics.SynchronizeWithVerticalRetrace = false;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
texture = new Texture2D(GraphicsDevice, 1, 1);
texture.SetData(new Color[] { Color.White });
previouskeystate = Keyboard.GetState();
previousmousestate = Mouse.GetState();
screencenter = new Point(Window.ClientBounds.Width / 2, Window.ClientBounds.Height / 2);
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
if (Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
KeyboardState currentkeystate = Keyboard.GetState();
MouseState currentmousestate = Mouse.GetState();
if (keepMouseLockedToCenter)
{
mousedelta = new Point(currentmousestate.X - screencenter.X, currentmousestate.Y - screencenter.Y);
Mouse.SetPosition(screencenter.X, screencenter.Y);
}
else
{
mousedelta = currentmousestate.Position - previousmousestate.Position;
}
//do stuff here
point += new Point(mousedelta.X * 4, mousedelta.Y * 4);
if (currentkeystate.IsKeyDown(Keys.R))
point = screencenter;
if (currentkeystate.IsKeyDown(Keys.C) && previouskeystate.IsKeyUp(Keys.C))
IsMouseVisible = !IsMouseVisible;
if (currentkeystate.IsKeyDown(Keys.F) && previouskeystate.IsKeyUp(Keys.F))
keepMouseLockedToCenter = !keepMouseLockedToCenter;
//do stuff here
previouskeystate = currentkeystate;
previousmousestate = currentmousestate;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.White);
spriteBatch.Begin();
spriteBatch.Draw(texture, new Rectangle(point, new Point(5, 5)), Color.Red);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
I’ve tested this on DirectX (Windows platform) now instead of Cross platform with OpenGL etc. and it’s actually even worse somehow.
I have to be doing something wrong here:
As far as I’ve checked no one else is having any problems like this.
//get input
KeyboardState keyStateCurrent = Keyboard.GetState();
MouseState mouseStateCurrent = Mouse.GetState();
//get mouse movement
if (keepMouseLockedToCenter)
{
//get delta while keeping mouse at center
//this doesn't work!
mouseDelta = new Point(mouseStateCurrent.X - screenCenter.X, mouseStateCurrent.Y - screenCenter.Y);
Mouse.SetPosition(screenCenter.X, screenCenter.Y);
}
else //if mouse is not locked to center
{
//get delta while mouse is free
//this is totally fine
mouseDelta = mouseStateCurrent.Position - mouseStatePrevious.Position;
}
//do stuff here
//save current state so next update we can get state from last update
keyStatePrevious = keyStateCurrent;
mouseStatePrevious = mouseStateCurrent;
I experienced the problem in DirectX, but the problem may also affect OpenGL versions.
Also, when doing First Person mouse controlled games I’ve always found smoother doing a “cage” around the mouse than setting the mouse to the center every frame… not only on Monogame, for some reason I really don’t grasp they always seem to work smoother, but this is just personal experience and even I don’t understand why I’m experiencing this.
The git link contains an implementation of what I’m saying, and the 4th comment a possible software hack around the bug.
Thanks for the reply. Turns out this seems to be the exact issue I’m having. I suppose I’ll have to use the workaround until it’s fixed on Monogame’s side!