Stuttering when moving one sprite in an XNA application

Update: I uploaded a video showing stuttering here: http://intninety.co.uk/xnastutter.mp4 you may have to look carefully at the video if you are not watching it in 1920x1080 format, but you will see that every move For 2 seconds or so, a rather sharp stutter is observed, I would recommend viewing it in Windows Media Player, and not in your web browser, to ensure the video itself is intermittent and thus preventing you from seeing the actual stutter

I recently picked up a project that I started some time ago, however, I'm still trying to solve the problem on which I left it!

I currently have a very simple application that has only one sprite on the screen and is moved using the direction keys. The problem is, every two seconds or so, the game stutters, and the sprite seems to jump back and then back and forth very quickly.

The sprite itself is a 55x33 bitmap, so it is not something big, and the code used is as follows. I hope this is enough to make the ball roll on some ideas as to what might be the problem if a video is needed, to see exactly what the stutter looks like, I can put it together and load it somewhere if necessary.

As you will see in the code, it compensates for the lost time between frames, making the movement larger if this happens, however this fall occurs very consistently, wise, which makes me think that I am doing something wrong somewhere.

I tried on several different machines, but the problem persists for all of them, if anyone has any ideas or you can see where I, I messed it up, would be greatly appreciated if you could point it out.

Thanks:)

Game Designer Configuring the Graphics Device Manager

graphics = new GraphicsDeviceManager(this); graphics.IsFullScreen = true; graphics.SynchronizeWithVerticalRetrace = false; graphics.PreferredBackBufferWidth = 1920; graphics.PreferredBackBufferHeight = 1080; Content.RootDirectory = "Content"; this.IsFixedTimeStep = false; 

Code from the game update method

 KeyboardState keyboard = Keyboard.GetState(); GamePadState gamePad = GamePad.GetState(PlayerIndex.One); if (keyboard.IsKeyDown(Keys.Escape)) { this.Exit(); } if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed)) { this.player.MoveLeft((float)gameTime.ElapsedGameTime.TotalMilliseconds); } else if ((keyboard.IsKeyDown(Keys.Right)) || (gamePad.DPad.Right == ButtonState.Pressed)) { this.player.MoveRight((float)gameTime.ElapsedGameTime.TotalMilliseconds); } if ((keyboard.IsKeyDown(Keys.Up)) || (gamePad.DPad.Up == ButtonState.Pressed)) { this.player.MoveUp((float)gameTime.ElapsedGameTime.TotalMilliseconds); } else if ((keyboard.IsKeyDown(Keys.Down)) || (gamePad.DPad.Down == ButtonState.Pressed)) { this.player.MoveDown((float)gameTime.ElapsedGameTime.TotalMilliseconds); } base.Update(gameTime); 

The Move methods described in the above update method

 public void MoveLeft(float moveBy) { this.position.X -= (moveBy * this.velocity.X); } public void MoveRight(float moveBy) { this.position.X += (moveBy * this.velocity.X); } public void MoveUp(float moveBy) { this.position.Y -= (moveBy * this.velocity.Y); } public void MoveDown(float moveBy) { this.position.Y += (moveBy * this.velocity.Y); } 

Game drawing method

 GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.Draw(this.player.Texture, this.player.Position, null, Color.White, this.player.Rotation, this.player.Origin, 1.0f, SpriteEffects.None, 0.0f); spriteBatch.End(); base.Draw(gameTime); 

Edit: forgot to mention, the speed object used in the Move methods is Vector2

+6
source share
2 answers

I was able to see how this happens once a second, which led me to what I consider a problem. Since you use the original value of ElapsedGameTime.TotalMilliseconds as a factor for your movement, any lag in the computer that your program will experience will be directly applied to the movement. For example, if your computer (OS) does something else for one twentieth of a second, then the elapsed time will accumulate to ~ 50 milliseconds, when it usually is about 0.3 milliseconds. This will result in a frame being 150 times larger than a regular frame.

To make this happen manually, you can do the following:

 // define a frame counter private int mCounter; ... protected override void Update(GameTime pGameTime) { // save the elapsed time value float time = (float)pGameTime.ElapsedGameTime.TotalMilliseconds; ... // force a long frame every 2500th frame (change depending on your framerate) if (mCounter++ > 2500) { mCounter = 0; time = 75; // about 225 times longer frame } ... // use the time value in your move calls if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed)) mPlayer.MoveLeft(time); 

To prevent this from happening (other than setting IsFixedTimeStep = true; which will fix it immediately, but if you want IsFixedTimeStep be false ) you should use the time value as above, but close it, It is up to you to determine share elapsed time for movement and determine how much time is required for passing behind the scenes. Example:

 protected override void Update(GameTime pGameTime) { // save the elapsed time value float time = (float)pGameTime.ElapsedGameTime.TotalMilliseconds; if (time > 1) time = 1; ... if ((keyboard.IsKeyDown(Keys.Left)) || (gamePad.DPad.Left == ButtonState.Pressed)) mPlayer.MoveLeft(time); ... 

Although this will fix the problem for your current program, your frames will only be 0.3 ms each, as there is not much going on. When your game has more time, there will be more time per frame, and you need the cap to be much higher than 1 ms.

EDIT: To be clear, this is the β€œdowntime” of your processor / OS. This is not going to go away *, it is just up to you whether to jump the heap when it happens (which can cause problems if the past has ever done this before 2000 ms, for example), or to close these peaks and allow them to trigger a lag ; in any case, there will be a β€œhole” in your movement that you cannot fill. This is really normal, and it is not as critical as it seems. When your game has more events, it will become less noticeable. At the moment, it is very different in that there are only two graphs, and nothing else happens.

* (In fact, you can look for other applications and processes that you can close so as not to borrow the processor from any other program, but since you are using a multi-tasking OS, you will never be guaranteed to have a processor for yourself.)

+2
source

Refresh again

Just thought. Have you ever checked that (float)gameTime.ElapsedGameTime.TotalMilliseconds does not lead to infinity or a negative number? Elapsed time becoming negative would explain that your sprite will jump back and then forward.

Its a keyboard. You can prove this by changing the left and right left and right mouse buttons. Use keydown and keyup triggers to set state instead of iskeydown.

Update:

There seem to be a few things that stutter XNA. I definitely thought the problem was with the keyboard. However, I can only assume that you also checked your code with GamePad and it suffers from the same.

Another issue with IsFixedTimeStep , but you already set it to false. A quick Google search suggests that there are several people with such problems without any clear fixes.

In the section http://forums.create.msdn.com/forums/t/9934.aspx?PageIndex=6

Other views:

Try to limit the frame rate to 60 frames per second. In any case, there is no reason. One force suggests that a 2d application that does nothing can stop the graphics pipeline with significant throughput.

Check if IsSlowRunning is ever called. Garbage collection and chaos theory can lead to this being established. I

+1
source

Source: https://habr.com/ru/post/912879/


All Articles