首页 > 解决方案 > Modulate the speed of the object in a while loop using delta time

问题描述

int i = 0;
void Car_Animation::update(float delta_time)
{
    glm::tvec3<float> tar = { 0,0,0 };
    tar = curve->curve_points_pos[(i+1) % (curve->points_pos.size())] -
        curve->curve_points_pos[(i) % (curve->points_pos.size())];

    m_model_mat = glm::translate(m_model_mat, tar);
    i++;

}

The above function gets called in a while loop where delta_time is the difference between the previous frame and current frame;

while (!glfwWindowShouldClose(window))
    {
            animation->update(delta_time);
}

Right now, in the update function, I am translating my model to a set of points in the curve->points_pos. curve->points_pos contains an array of points close to each other which gives an illusion of the model moving continuously.But the problem is, I want to modulate the speed of the model. How could I do it? I have delta_time. Can I use that? I am using only glfw, glew and glm, not using glut.

标签: game-physics

解决方案


Correct me if I'm wrong, but it looks like you currently have: * curve->curve_points_pos, which is an array of locations that you want your model to pass through; * m_model_mat which is the current transformation matrix for your model; and * i, which is the current index into curve->curve_points_pos.

The model then takes integral steps from one entry in curve->curve_points_pos to the next, although you apply them as offsets from each other, rather than taking them as absolutes.

In that case what you basically have is a function of time, f(t) evaluated at integral steps of t and stored in curve->curve_points_pos.

So, first: stop thinking in terms of updating m_model_mat, and calculate it entirely per position. E.g.

m_model_mat = glm::translate(glm::mat4(1.f), 
                             curve->curve_points_pos[(i) % (curve->points_pos.size())]);

If you have some other transform you also want to apply — e.g. if you want to move it away from the origin, compose that as an additional step.

Second: convert i to a floating point number, and interpolate between entries in curve->curve_points_pos. So:

const int i_integral = int(i) % curve->points_pos.size();
const int next_i_integral = int(i+1) % curve->points_pos.size();
const float i_fractional = fmodf(i, 1.f);
const auto curve_point = 
    curve->curve_points_pos[i_integral] * (1.f - i_fractional) + 
    curve->curve_points_pos[next_i_integral] * i_fractional;

m_model_mat = glm::translate(glm::mat4(1.f), curve_point);

There are a few bits to unpack there:

  • i is now a floating point number, so it may describe a position between entries in curve->points_pos;
  • I've assumed linearly interpolation (the model will walk a straight line between each pair of listed points), so:
    • each position can be broken down into an integral part and a fractional part; where:
    • the integral part identifies the two points the model is currently walking between — the integer itself will identify the one it has most recently departed from and, implicitly, it is walking towards whatever point comes next; and
    • the fractional part identifies how far it has travelled between those two points, e.g. if the fractional part is .0 then the model hasn't actually left its origin yet, if it's .9999 then the model is very nearly at the next point, if it's .5 then the model is exactly halfway between the two, etc;
  • the curve_point calculation then models that logic.

Aside observations:

  • linear interpolation is not necessarily the best interpolation, but it's easy to understand and compute, and if your points are reasonably close together it is likely acceptable; but
  • if your points are really close together, you might even be able to ditch interpolation all together, and just use the integral part as a direct point lookup. Then your model will warp from listed point to point after spending the correct amount of time at each, but if your points are very close together then that still may be acceptable.

推荐阅读