Page 1 of 1

Increase x to y withing w milliseconds

Posted: Fri Aug 03, 2012 3:51 pm
by superLED
Just a quick question.

x = 0; y = 10;
w = 10;

I have number x, and I want x to become y withing w seconds, increasing.
That means that each second, I want x to increase with 1. But I want this function to increase x each frame.

Let's say I want an enemy to walk from the top of the screen to the bottom of the screen. And each frame, a function increases the enemy's y position, so he moves evenly from point A to point B.

I have tried to come up with a function that does this for an hour now(wow!), and I'm stuck.

I want the setup to be like this:

Code: Select all

float move(float number, float targetNumber, flaot deadLine);

if(enemy.isWalkingFromTopToBottom) {
  enemy.y += move(enemy.yPosition, enemy.targetPos, enemy.timeToBeAt_TargetPos); // Value to be changed, The number we are aiming to get to, When we want to be at 'targetPos'
}

float move(float number, float targetNumber, flaot deadLine) {
  float i = 0;  
  /*
  Calculate stuff so 'i' contains the number we should increase with in this frame
  */
  return i;
}
So, what can I put into that function?

Re: Increase x to y withing w milliseconds

Posted: Fri Aug 03, 2012 3:59 pm
by bbguimaraes
If you are going from 0 to 10 in 5 seconds, you increase 2 each second. There are many ways to move the equation around, depending on the values you have. If you are using the standard approach of storing the position and velocity, you need to calculate the displacement from the current position to the target and set the velocity. Then you loop, increasing position according to the velocity until the target position is reached.

Just remember to decrease the time to account for the previous steps. Your functions calls should look like:

Code: Select all

move(0, 10, 5);
move(2, 10, 4);
move(4, 10, 3);
move(6, 10, 2);
move(8, 10, 1);

Re: Increase x to y withing w milliseconds

Posted: Fri Aug 03, 2012 6:27 pm
by Nokurn
A common approach I've seen to doing something like this (which is also the approach I use) is to have a position and a velocity (and usually an acceleration as well, for smooth movement):

Code: Select all

float x, y; // position
float vx, vy; // velocity [units / sec]
Calculate the velocity to move from <x,y> to <xf,yf> in t seconds, assuming constant velocity:

Code: Select all

void pointVelocity(float x, float y, float xf, float yf, float t, float& vx, float& vy)
{
    float dx = xf - x;
    float dy = yf - y;
    vx = dx / t;
    vy = dy / t;
}
Call an update function on every tick/frame, which increases your position by your velocity times the previous frame time:

Code: Select all

float update(float ft)
{
    if (x < xf) {
        x += vx * ft;
        if (x > xf)
            x = xf;
    }
    if (y < yf) {
        y += vy * ft;
        if (y > yf)
            y = yf;
    }
}
The part that needs explanation is the frame time (ft). This is the time that the previous frame took from start to finish, in seconds. In Allegro 5, you'd use a main loop like this:

Code: Select all

float ft = 0.0f; // first update will do nothing
while (running) {
    float t0 = (float)al_get_time();

    ALLEGRO_EVENT ev;
    while (al_get_next_event(evq, &ev))
        handleEvent(ev);
    update(ft);
    render();

    ft = (float)al_get_time() - t0;
}
You multiply your velocity [unit / sec] by time [sec] to obtain [unit], which is compatible with the units of position [unit] and can be added. This has the bonus of being frame rate independent--the technique is a form of interpolation to ensure that movement will take place at the same speed on every computer. On a slow computer with a high frame time, the object might move to the destination in the span of one frame. On a fast computer, it might take thousands of frames. But it will never arrive earlier than expected, and as long as you compensate for extremely high values of ft, it will never move farther than desired.

I don't know the exact specifics of how you want things to be set up, but you can probably make this fit if you like the idea. For milliseconds, you'd just divide the number of milliseconds by 1000 to get t.

There are other ways to achieve something similar by using absolute time offsets that are stored slightly more locally, but then you have to worry about accumulators and such. Of course, you could use an accumulator with this technique instead of multiplying by ft, but you would lose the frame rate independence.

Hope this helps.

Re: Increase x to y withing w milliseconds

Posted: Sun Aug 05, 2012 6:35 pm
by superLED
Thanks so much for the replies! It will be really helpful.
I'll see what I can make out of this ^^

Re: Increase x to y withing w milliseconds

Posted: Sun Aug 05, 2012 7:38 pm
by XianForce
Here's a helpful article on a reusable implementation: http://www.rivermanmedia.com/programmin ... -functions Hope that helps :)

Re: Increase x to y withing w milliseconds

Posted: Tue Aug 07, 2012 6:42 am
by bbguimaraes
There are some really nice concepts on that text.

Re: Increase x to y withing w milliseconds

Posted: Thu Aug 09, 2012 11:00 am
by superLED
I was able to find a really easy solution for this problem.

I keep track of the starting time(when the number start increasing) and the ending time(when the number is supposed to reach the goal), and the current time.
I also keep track of the starting number and the end number(what the number should become).

Then, I have startTime(100), endTime(200) and currentTime(150). I find out that currentTime is 50% between startTime and endTime.
From there, I find the number at the 50% position between startNumber(0) and endNumber(500).

Then I know that at this moment, the number should be 250.

You guys had some very interesting idea on how to do this, and how to have a more stable and powerful setup. I sure will try to implement some of that into my system!