简体   繁体   中英

What's the best way to move a sprite faster than the update rate in a simple 2d game?

At the moment, I have a sprite that I have arbitrarily set to move 1 pixel per second. The code is basically this (The code isn't optimised at all, I could do it much nicer but it is the principle I am trying to solve first:):

private const long MOVEMENT_SPEED = 10000000; // Ticks in 1 second
private long movementTimeSpan = MOVEMENT_SPEED;


protected void PerformMovement(GameTime gameTime)
{
    movementTimeSpan -= gameTime.ElapsedGameTime.Ticks;

    if (movementTimeSpan <= 0)
    {
       // Do the movement of 1 pixel in here, and set movementTimeSpan back to MOVEMENT_SPEED
    }
}

Perform movement is called in a loop as you'd expect, and it equates to updating around 10 times per second. So if I lower the MOVEMENT_SPEED, my sprite speeds up, but it never gets any faster than 10 pixels per second. For projectiles and other stuff I obviously want it to update much faster than this.

If I alter the movement to 2 pixels or more, it creates issues with calculating collisions and suchlike, but these might be possible to overcome.

The other alternative is to store x and y as a float rather than an int, and increase the values as a fraction of the number of elapsed ticks. I am not sure if this will create smooth movement or not as there still has to be some rounding involved.

So my question is, does anyone know the standard way?

Should I increase the amount to more than 1 pixel and update my collision detection to be recursive, should I store X,Y as floats and move as a % of elapsed time, or is there a 3rd better way of doing it?

The standard way is to not count down a timer to move, but instead the opposite:

private const float MOVEMENT_SPEED = 10.0f; //pixels per second
private float time;

protected void PerformMovement(GameTime gameTime)
{
    time = (float)gameTime.ElapsedGameTime.TotalSeconds;

    character.X += MOVEMENT_SPEED * time;
}

Make the movement based on the time elapsed. The reason floats are commonly used is to get the fractional value of motion. Fixed-point is another common fractional representation but uses int s instead.

As for collision, collision can be very tricky but in general you don't absolutely need to do it once per pixel of motion (as you suggested with recursion); that's overkill and will lead to terrible performance in no time. If you are currently having trouble with 2-pixel motion, I would reevaluate how you're doing your collisions. In general, it becomes problematic when you're moving very fast to the point of skipping over thin walls, or even passing over to the "wrong side" of a wall, depending on how your collision is set up. This is known as "tunnelling". There are many ways of solving this. Look here and scroll down to "Preventing Tunnelling". As the article states many people just cap their speed at a safe value. But another common method is to "step" through your algorithm in smaller time steps than is currently being passed in. For example, if the current elapsed time is 0.1, you could step by 0.01 within a loop and check each small step.

A way to do what you request, although not very recommended, is to increase your game's update frequency to a higher value than the usual 30 or 60 fps, but only draw to the screen every N frames. You can do it by just having your graphics engine ignore Draw calls until a count or timer reaches the desired value.

Of course, this solution should be avoided unless it is specifically desired, because performance can degrade quite fast as the number of updated elements increases.

For example, Proun (not an XNA game) uses this trick for exactly your reasons.

With the default of IsFixedTimeStep = true , XNA behaves in a similar fashion , skipping calls to Draw if Update takes too long.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM