-
|
|
|
EDITED:
You may skip directly to this post
Or real the thread from the start :
Hello,
Below is a really simple Game class that just render a point moving from left to right.
If anyone can test it and tell me if he sees the point "lagging" ?
On my computer the lag happens sometime right away or after a little time.
The point movement is smooth, then it jumps in a jerky way, become smooth again, jumps, etc...
I coded this simple test because I had the same issue on a "real" case.
Does anyone have a good explaination ? Is there any way to get a continious movement ?
Thanks
| public class Game1 : Microsoft.Xna.Framework.Game |
| { |
| GraphicsDeviceManager graphics; |
| SpriteBatch spriteBatch; |
| public int point = 0; |
| Texture2D whiteTexture; |
| |
| public Game1() |
| { |
| graphics = new GraphicsDeviceManager(this); |
| Content.RootDirectory = "Content"; |
| graphics.PreferredBackBufferWidth = 1024; |
| graphics.PreferredBackBufferHeight = 32; |
| InactiveSleepTime = TimeSpan.Zero; |
| TargetElapsedTime = TimeSpan.FromSeconds(1 / 60.0f); |
| } |
| |
| protected override void LoadContent() |
| { |
| whiteTexture = new Texture2D(GraphicsDevice, 1, 1, 1, TextureUsage.None, SurfaceFormat.Color); |
| Color[] pixels = { Color.White }; |
| whiteTexture.SetData(pixels); |
| spriteBatch = new SpriteBatch(GraphicsDevice); |
| } |
| |
| protected override void Update(GameTime gameTime) |
| { |
| if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) |
| { |
| this.Exit(); |
| } |
| |
| // update the position |
| point = (point + 5) % GraphicsDevice.Viewport.Width; |
| |
| base.Update(gameTime); |
| } |
| |
| protected override void Draw(GameTime gameTime) |
| { |
| GraphicsDevice.Clear(Color.Black); |
| spriteBatch.Begin(); |
| spriteBatch.Draw(whiteTexture, new Rectangle(point, GraphicsDevice.Viewport.Height / 2, 2, 2), Color.White); |
| spriteBatch.End(); |
| base.Draw(gameTime); |
| } |
| } |
|
|
-
|
|
|
Works fine here... Not sereing any jumping, or lag. Might look at task man and see how much cpu its taking, or what else is running in the background that might cause it to lag.
The modulous on the window size will make it a few pixels off each time it resets to start from the left again, but besides that did't notice anything wierd or wrong.
|
|
-
|
|
|
To get a smooth movement you should make the movement time-aware something like:
point = (point + gameTime.elapsedGameTime.Milliseconds) % GraphicsDevice.Viewport.Width;
(could be some typo's in it)
|
|
-
|
|
|
@Drel :
Thanks for your feedback. The game uses 100% of a core, 25% of total CPU (I'm on a quad core) No other application take some cpu (except the taskmgr and dwm which is vista window manager but its just 1%)
I'm starting to think i'm crazy :)
|
|
-
|
|
|
The time between two calls of the updatemethod is not guaranteed constant.
So if you correct this by using Gametime in your movement it will look smooth.
|
|
-
|
|
|
Marinus Holkema:To get a smooth movement you should make the movement time-aware something like:
Thanks for your feedback.
I'm using fixed timestep, so gameTime.elapsedGameTime.Milliseconds is constant every frames.
dt : 0,0166667
Even if I use the dt, I can see the lag (I tried)
You gave me the idea to try with a variable time step (see the code below) With this code I don't see any lag.
Any idea how to have a smooth movement using a fixed timestep ?
smooth, variable time step code :
| public class Game1 : Microsoft.Xna.Framework.Game | | { | | GraphicsDeviceManager graphics; | | SpriteBatch spriteBatch; | | public float point = 0; | | Texture2D whiteTexture; | | | | public Game1() | | { | | graphics = new GraphicsDeviceManager(this); | | Content.RootDirectory = "Content"; | | graphics.PreferredBackBufferWidth = 1024; | | graphics.PreferredBackBufferHeight = 32; | | InactiveSleepTime = TimeSpan.Zero; | | IsFixedTimeStep = false; | | } | | | | protected override void LoadContent() | | { | | whiteTexture = new Texture2D(GraphicsDevice, 1, 1, 1, TextureUsage.None, SurfaceFormat.Color); | | Color[] pixels = { Color.White }; | | whiteTexture.SetData(pixels); | | spriteBatch = new SpriteBatch(GraphicsDevice); | | } | | | | protected override void Update(GameTime gameTime) | | { | | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) | | { | | this.Exit(); | | } | | | | float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; | | point = (point + 400 * dt) % GraphicsDevice.Viewport.Width; | | Console.WriteLine("dt : " + dt); | | | | base.Update(gameTime); | | } | | | | protected override void Draw(GameTime gameTime) | | { | | GraphicsDevice.Clear(Color.Black); | | spriteBatch.Begin(); | | spriteBatch.Draw(whiteTexture, new Rectangle((int)Math.Round(point), GraphicsDevice.Viewport.Height / 2, 2, 2), Color.White); | | spriteBatch.End(); | | base.Draw(gameTime); | | } | | } |
|
|
-
|
|
|
Marinus Holkema:The time between two calls of the updatemethod is not guaranteed constant.
In practice, for this sample, it is constant :
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; Console.WriteLine("dt : " + dt);
dt : 0,0166667 dt : 0,0166667 dt : 0,0166667 dt : 0,0166667 dt : 0,0166667 dt : 0,0166667 dt : 0,0166667 dt : 0,0166667
I cannot get a dt with a different value.
By the way I edited my last post in case you read it earlier.
|
|
-
|
|
|
Right now the only way I found to get a smooth movement with this sample is to use a variable time step. Here is how I understand why I get some lags with fixed time step and none with variable:
When using a variable time step with VSync On, the method Update and Draw takes a very little time, and we spend most time waiting for the VSync. Therefore we are (almost) sure to arrive at time for the VSync.
What if your Update + Draw takes less than 1/60 of a second? Also simple. Here we call Update, then call Draw, then look at the clock, notice we have some time left over, so wait around twiddling our thumbs until it is time to call Update again.
So maybe the time passed waiting to get a fixed dt is sometime too long and therefore we miss a VSync. Here is an illustration :
| | | U = Update | | D = Draw | | P = Present (swap buffer) | | V = VSync | | --- = VSync wait | | *** = Xna Gameloop wait | | | | | | Variable Dt VSync On : | | | | V1 V2 V3 V4 | | | | | | | | UDP-----| UDP-----| UDP-------| UDP------| | | | | | | Fixed Dt VSync On : | | | | V1 V2 V3 V4 | | | | | | | | UD*****P| UD****** UD******P--| UD******P| | | | On the 2nd VSync, the Fixed method miss the VSync. It seems plausible because I don't think there is anyway to know when the VSync will happend.
Now, could this hypothesis explain the lag ? I'm really not sure.
|
|
-
|
|
|
It would be nice if I could get more feedbacks about whether people see the point lag or not. To test, you just have to copy paste the code below and run it.
According my test, sometime the point do not jerk, but if you move the game window, it will freeze the game, and after the point will start to lag.
If you think it's lagging you can HOLD Space to switch to a Variable time step and see the difference. The point will become green. On my computer it stops the lag.
I'm also interested in the reason of this behavior. Thanks!
| using System; | | using Microsoft.Xna.Framework; | | using Microsoft.Xna.Framework.Graphics; | | using Microsoft.Xna.Framework.Input; | | | | namespace TestGame | | { | | public class Game1 : Microsoft.Xna.Framework.Game | | { | | GraphicsDeviceManager graphics; | | SpriteBatch spriteBatch; | | public float point = 0; | | Texture2D whiteTexture; | | | | public Game1() | | { | | graphics = new GraphicsDeviceManager(this); | | Content.RootDirectory = "Content"; | | graphics.PreferredBackBufferWidth = 1024; | | graphics.PreferredBackBufferHeight = 32; | | InactiveSleepTime = TimeSpan.Zero; | | IsFixedTimeStep = true; | | } | | | | protected override void LoadContent() | | { | | whiteTexture = new Texture2D(GraphicsDevice, 1, 1, 1, TextureUsage.None, SurfaceFormat.Color); | | Color[] pixels = { Color.White }; | | whiteTexture.SetData(pixels); | | spriteBatch = new SpriteBatch(GraphicsDevice); | | } | | | | protected override void Update(GameTime gameTime) | | { | | if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) | | { | | this.Exit(); | | } | | | | // Hold Space to use a variable timestep | | IsFixedTimeStep = !Keyboard.GetState().IsKeyDown(Keys.Space); | | | | float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; | | point = (point + 400 * dt) % GraphicsDevice.Viewport.Width; | | | | base.Update(gameTime); | | } | | | | protected override void Draw(GameTime gameTime) | | { | | GraphicsDevice.Clear(Color.Black); | | spriteBatch.Begin(); | | spriteBatch.Draw(whiteTexture, new Rectangle((int)Math.Round(point) - 2, GraphicsDevice.Viewport.Height / 2 - 2, 4, 4), IsFixedTimeStep ? Color.White : Color.Lime); | | spriteBatch.End(); | | base.Draw(gameTime); | | } | | } | | } | | |
|
|
-
|
|
|
I'm still not sure but it seems the internal XNA game loop may make the drawing lag (under certains conditions).
I created a small project on codeplex to test this issue.
I would like to understand why this is happening, so I need to get some feedbacks about wether you see the point lag or not. You just need to run the application, follow the steps described below and reply.
To test the lag:
- Launch the game
- Move the window during 1 second to make the game freeze
- Stop moving the window and look at the point movement
At this point you should see the point lag (doing undesire jumps). Then you can change the settings :
- Removing the VSync : should not change anything to the lag but you will see some tearing
- Set IsFixedTimeStep to FALSE : should remove the lag no matter if the VSync in On or Off (if Off you should have a hug framerate, so it's not really a good test case)
- Changing point size : help to see the VSync tearing.
If you have any ideas for the lag reasons...
Thanks!
|
|
-
-
|
|
|
Feedback: This topic has been discussed here so many times, people are probably sick to death of discussing ;)
|
|
-
|
|
|
Thanks for replying. I had searched the forum before, but I couldn't find anything on the subject.
Shawn Hargreaves:So, you have to accept that Windows games will always drop a frame every now and then. The next question is, what should your game do to recover when this happens? You have basically three options: - Do nothing, and just loose some time. Not good, and very obvious to the player.
- In your next update, account for how much time has been lost, and move all your objects slightly further to compensate for it. This is the behavior you get if you set IsFixedTimestep = false. Trouble is, this accounting makes your update logic more complex.
- Use IsFixedTimestep = true, and don't write any special code in your update method. In this case the framework will keep track of how much time has been lost, and once that adds up to enough to make up a whole extra Update, we will call Update an extra time to catch up with where we ought to be.
[...] Because of how the human eye works. The simpler your game, the more obvious the glitching will be.
I agree with that, but seems to me the lags or jumps are also due to the way the xna gameloop try to catchup a drop of framerate. It seems pretty periodic and predictible if you have tested the binary. Instead of lagging one frame (or a little more) and doing the catchup, the lags continue during 20 seconds (more or less) until it stops.
Thanks anyway
|
|
|