Delta time drives me crazy

Hey folks,

I’m porting my Windows Phone game to Android and unfortunatelly it runs slower (like 3x) than on WP, but rather it’s not problem with high resources usage etc. but with delta time. As per Monogame samples, frame rate for WP is 30 FPS by default.

#if WINDOWS_PHONE
            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
#endif

On my android device, it runs with ~16 elapsed game time (total milliseconds) per update call. So about 60 FPS. I tried also set target elapsed time for android the same as for WP, but it was running still slower. Well, maybe the problem is with how I understand delta time. Here is piece of code, how I update enemy and some scroll:

rectangle.X -= (int)(SPEED_X * bulletTime * gameTime.ElapsedGameTime.TotalMilliseconds);
...
float deltaTime = (float)gameTime.ElapsedGameTime.TotalMilliseconds;
scrollGround -= (int)(playerSpeed * bulletTime * deltaTime);

I tried to debugg this, for example scrollGround calculation is

  • x on WP

  • 0.5x on Android

but on Android update is called 2x times more frequently, so it should result with the same speed. Am I missing something ? WP device has smaller screen (like 800x480) and Android has HD.

It doesn’t seem like your timing things properly.

I see a couple things wrong though.
First i want to say i suggest you use totalseconds, working in milliseconds is not intuitive.
When you use total seconds its straight forward you set times as a division of 60 if that’s the targeted smooth frame rate. so that things are based on actual time passed 1/60 = the fraction of a second to delay;

As well and i think this is the real problem your running into.
I would use TotalGameTime which to me makes things much simpler.

While you can use GameTime ElapsedTime and the Update method. Its much more confusing in many ways. You have to remember certain specific things, which seems to me to be the trouble here.

Ill just give you a example and word the variables to explain it really quick.

Take a look at the below this is one way to do it as ive described this way it doesn’t matter what your update speed is your draw speed or anything else it will only fire when the set time passes.

  // this is your timing value it can be anything as long as it stays constant and never changes
  public const float STANDARD_UNIT_TIME_IN_SECONDS = 60f;
  
  // the 1f is the only value you need to change its how you set what you want
  float desiredTimedAmount = 1f;
  
  float timenow = 0f;
  float pausetimeset = 0f;
  float pauseDurationInSeconds = 0f; 
  
  public Game1(...){
         pauseDurationInSeconds = desiredTimedAmount / STANDARD_UNIT_TIME_IN_SECONDS;
     // ....

  Update(...)
  {
    timenow = (float)gameTime.TotalGameTime.TotalSeconds;
    if (pausetimeset < timenow)
    {
       // ... execute code
       // ....
       
       // ....
       // ... when done ...
       //
       // Set the timer to the specified duration;
       pausetimeset = timenow + pauseDurationInSeconds;
    }

Now you can extend this to also find elapsed time your self directly by adding a time last variable

Edit:
Here is a working class.

public class MgTimer2
    {
        // this is your timing value it can be anything as long as it stays constant and never changes
        public const float STANDARD_UNIT_TIME_IN_SIXTIETH_SECONDS = 60f;

        // the 1f is the only value you need to change its how you set what you want
        float desiredTimedAmount = 1f;

        float timenow = 0f;
        float pausetimeset = 0f;
        float pauseDurationInSixtiethSeconds = 0f;

        float timelast = 0f;
        float elapsedTimeSinceLastwasChecked = 0f;
        bool triggered = false;

        public MgTimer2(float desiredTiming)
        {
            desiredTimedAmount = desiredTiming;
            pauseDurationInSixtiethSeconds = desiredTimedAmount / STANDARD_UNIT_TIME_IN_SIXTIETH_SECONDS;
        }

        public bool IsTriggered
        {
            get { return triggered; }
        }

        /// <summary>
        /// returns the rate of change to the desiredTime at or after the desired time interval. 
        /// </summary>
        public float Update(GameTime gameTime)
        {
            timenow = (float)gameTime.TotalGameTime.TotalSeconds;
            if (pausetimeset < timenow)
            {
                // ... execute code
                // ....
                triggered = true;
                // ....
                // ... when done ...
                //
                elapsedTimeSinceLastwasChecked = timenow - timelast;
                timelast = timenow;
                // set result if we are running slowly this elapsed time will be greater then normal
                float result = (float)(elapsedTimeSinceLastwasChecked / pauseDurationInSixtiethSeconds) * pauseDurationInSixtiethSeconds;
                // Set the pausetimer to the specified duration;
                pausetimeset = timenow + pauseDurationInSixtiethSeconds;
                return result;
            }
            else
            {
                triggered = false;
                return 0f;
            }
        }
    }

You should probably save the time. Return a triggered bool, then use that.
I just re-scribble it out as i just saw i had a bug writing this reply.

Hope this helps.

This looks very complicated for me … Like 6 variables to handle delta time. Almost in all examples I saw people are using ElapsedGameTime with TotalSeconds or TotalMilliseconds. This is piece od code from MonoGame.Samples project available on github, from Platformer2D game

public void ApplyPhysics(GameTime gameTime)
        {
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;
            // Base velocity is a combination of horizontal movement control and
            // acceleration downward due to gravity.
            velocity.X += movement * MoveAcceleration * elapsed;
...
}

and I think this is fine because it should work with the same speed on every device, on lower FPS you will notice “jumps”, when FPS will be higher it should be more smooth. But generally I think this piece of code is fine.

Any other suggestions ? I have no idea at this moment. You think I should replace TotalMilliseconds with TotalSeconds ? I don’t think so that’s actually the problem.

Well here is my point.

How many ticks are in a second ?

// Frame rate is 30 fps by default for Windows Phone.
TargetElapsedTime = TimeSpan.FromTicks(333333);

I dunno i suppose it can get confusing.

Extra variables maybe but this is how i set it

g.TargetElapsedTime = TimeSpan.FromSeconds((double)(1.0d / desiredframerate));`

Well, what I’ve observed that ElapsedGameTime.TotalMilliseconds is about 32 millis on WP, and about 16 millis on Android. It makes sense for me.

  • 1000 / 32 millis ~ 30 FPS on WindowsPhone
  • 1000 / 16 millis ~ 60 FPS on Android

so, if I update my objects 2x more frequently on Android, but with 2x smaller delta time value than on WP, it should be running with the same speed. I must be missing something or I’m just stupid :smile: In theory it should work …

You mean if you update half as much on android
You will be going the same speed as on windows phone.

and

If you simply multiply the elapsed time by 2 on android at 30fps to get a result.
you will get a result thats the same as the elapsed time on windows phone at 60 fps without multiplying.

The code for windows and android should look the same, since the physics depend on delta.

So if you just use

delta = elapsed time * something

it should be correct for both platforms, since delta will be double for wp by default. No need to change anything.

Obviously it makes no difference whether you use seconds or milliseconds, it’s just a factor behind that.

If you didn’t use time-dependent delta before - here is an easy trick.

double delta = gameTime.ElapsedGameTime.TotalSeconds*60;

The default framerate is 60, so your default delta is 1. You don’t have to change any other code and if your framerate is halfed delta will be doubled and it works again.

A question remains:

This has no effect by the way unless you tell it to apply that with
IsFixedTimeStep = true

Just in case.

He’s saying the faster device is running his game slower unless im misunderstanding i probably am.

Actually from the beginning it sounded like it should be working but hes using both ticks and milliseconds worse he has multiple calls to get the elapsed time in just a few shown lines of code.

Each call is going to give a different value and its going to be a comparatively smaller value in two separate multiplications which is going to accumulate. That should just be called one time per update im not sure that will even return the same value the second time…

So im guessing its a bug in his code or rather is his code the way hes timing things.

but you might have just hit the nail on the head.

I understand nothing now. Well, I have Scene Manager, that updates, draws etc. current scene.

public static void UpdateScene(GameTime gameTime)
        {
            touchCollection = TouchPanel.GetState();
            if (currentScene != null)
            {
                currentScene.Update(gameTime);
            }
        }

I pass gameTime through my scene’s components, it’s all the time single instance during update of whole scene. I pass this instance to my Scene Manager on Game.Update call. So, I think elapsedGameTime.TotalMilliseconds is constant during update of scene.

It was light in tunnel for me, but I verified it both on WP and Android, this is true by default.
Couldn’t figure out what’s wrong with my code. I try now to debug this with manual calculations on paper :slight_smile:

EDIT:
Maybe the clue is to take device’s scale factor ? For example, when player moves, I always update it let’s say x += speed * deltaTime. So, for both small and big screen device it will add for ex. x += 1. Pixels density factor ? Couldn;t see any bug in my code. Debugger says that values are equal on WP and Android, for example player’s speed. Only difference is delta time. I scale every graphics object in my game with Vector2 scale and it scales object properly

private const float RESOLUTION_W = 1280;
        private const float RESOLUTION_H = 720;

float scaleW = graphics.GraphicsDevice.Viewport.TitleSafeArea.Width / RESOLUTION_W;
            float scaleH = graphics.GraphicsDevice.Viewport.TitleSafeArea.Height / RESOLUTION_H;
            scale = new Vector2(scaleW, scaleH);

Do you handle this somehow?
One possibility is that at some places you operate on screen space (move spaceship by X pixels) while at other places you operate at world space (measure distances as X meters)

Exacly, that was the problem and I figured it out yesterday evening. So it wasn’t problem with delta time. I always operate on screen space. If I move player with x += 2 on every screen resolution it will take different time to for example go from left side of screen to right side.

  • For screen width = 1000 it will take 1000 / 2 = 500 units of time
  • For screen width = 500 it will take 500 / 2 = 250 units of time

etc. So the solution is to not only use delta to calculate objects movement but also scale.X and scale.Y properties, as I mentioned in earlier posts. But now game’s code is beginning more complex. I think I’m not doing it right way. I propagate scale object to my components, and during creation of objects I use it like this rectangle = new Rectangle(x, y, width * scale.X, height * scale.Y) etc. Is it correct approach in Monogame ? I scale fonts with spriteBatch.drawString similiar way. It works but I’m curious how do that professionals :slight_smile:

.Net:
TimeSpan.TicksPerSecond = The value of this constant is 10 million; that is, 10,000,000.

Do android or windowsphone have a different tickspersecond value ?

It sounds right to me.
You could as well pass a scale matrix to SpriteBatch.Begin() instead of scale each sprite individually. (plus you can do other cool stuff with it, for example zoom, pan and shake the camera from a single point in your code)

The documentation of Farseer physics engine will give you a good direction on how to work on KMS system and then how to scale and draw the world in screen coordinates.