框架独立运动


11

我还阅读了有关运动的其他两个主题: 基于时间的运动与基于帧频的运动?什么时候应该使用固定或可变时间步长?

但是我认为我对框架独立运动缺乏基本的了解,因为我不了解这些线程在说什么。

我跟着lazyfoo的SDL教程一起学习了框架无关的课程。http://lazyfoo.net/SDL_tutorials/lesson32/index.php

我不确定代码的运动部分在说什么,但是我想是这样的(如果我错了,请纠正我):为了使帧独立运动,我们需要找出一个物体有多远(例如精灵)在特定时间范围内移动,例如1秒。如果点以每秒200像素的速度移动,那么我需要通过将200 pps乘以1/1000秒来计算该点在该秒内移动了多少。

那正确吗?本课说:

“速度(以每秒像素数为单位*自上一帧以来的时间,以秒为单位。因此,如果程序以每秒200帧的速度运行:200 pps * 1/200秒= 1像素”)

但是...我以为我们将200 pps乘以1/1000秒。每秒帧数是什么业务?

如果有人可以给我一些关于框架独立运动如何工作的详细解释,我将不胜感激。

谢谢。

加成:

SDL_Rect posRect;
posRect.x = 0;
posRect.y = 0;

float y, yVel;
y = 0;
yVel = 0;

Uint32 startTicks = SDL_GetTicks();

bool quit = false;
SDL_Event gEvent;

while ( quit == false )
{
    while ( SDL_PollEvent( &gEvent ) )
    {
        if ( gEvent.type == SDL_QUIT )
            quit = true;
    }

    if ( y <= 580 )
    {
        yVel += DOT_VEL;
        y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
        posRect.y = (int)y;
    }

    startTicks = SDL_GetTicks();
    SDL_BlitSurface( bg, NULL, screen, NULL );
    SDL_BlitSurface( dot, NULL, screen, &posRect );
    SDL_Flip( screen );
}

该代码将点向下移动到屏幕上。我想到目前为止,我一切都正确。它在屏幕上向下移动,但是有些奇怪的事情发生了,我无法解释。当该点大于该y值时,应将其停留在y = 580处。但是,每次我运行该程序时,该点都会在不同的位置结束,这意味着要多于580,所以该点位于屏幕的一半或一半以上(点是20像素,尺寸800x600)。如果我单击并按住程序的标题栏,然后再松开,则点将从屏幕上消失。每次如何变化?至于标题栏问题,我认为这是因为当我按住标题栏时,计时器仍在运行,并且经过的时间变长了,导致点在下一帧中移动的距离更大。那正确吗?


您添加的内容实际上是另一个问题。您应该将其作为第二个问题,而不是将其添加到现有问题中。不过,可以很容易地回答:只需计算y移动,例如。yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);然后做:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack 2011年

Answers:


10

注意:所有分数均应为浮点数。

独立于框架的运动是根据时间的推移进行的。您可以获得自上一帧以来花费的时间(因此,如果一秒内有60帧,则如果所有帧都花费相同的时间,则每帧将花费1.0 / 60.0秒),并找出移动了​​多少转换成。

如果您希望您的实体在指定的时间单位内移动一定量的空间(我们将说每秒100像素),则可以通过乘以每个单位的移动量来找出每帧应移动多少像素秒(100像素),以秒为单位的时间(1.0 / 60.0),以计算当前帧中应发生的移动量。

它通过使用经过的时间量和以某个时间单位(最好是秒或毫秒)定义的速度来确定每帧应执行多少移动,从而起作用。因此您的计算可能如下所示:movementPerSecond * (timeElapsedInMilliseconds / 1000.0)

我希望这对您有意义。

我想将我的家伙每秒向右移动200像素。如果当前帧在前一帧之后50毫秒运行,那么我应该将我的家伙移动到先前指定的速度的一部分(即200像素)。我应该将他移至距离的50/1000,因为只有1/20(50/1000 = 1/20)的时间过去了。因此,仅将他移动10个像素是有意义的(如果又发生了19帧,彼此相隔50毫秒,则该秒的移动总量将是200像素,即我们想要的数量)。

独立于帧的运动的工作方式是,帧通常以可变的时间步长发生(后续帧之间发生的时间不同)。如果我们每帧不断移动实体恒定距离,则移动基于帧速率。如果两帧之间有很多时间,则游戏似乎运行得太慢,而两帧之间没有太多时间,则游戏似乎会变快。(两帧之间的时间太少=许多帧=更多的运动)为了克服这一点,我们在时间方面使用速度,并跟踪两帧之间的时间。这样一来,我们便知道自上次更新职位以来已经过去了多长时间,以及我们应该移动实体多远。

每秒的帧数:这是每秒发生的帧数。通常,帧速率是每秒绘制/渲染游戏多少次或每秒完成游戏循环多少次。

Fixed Verse Variable Time Step:这是指帧之间的时间量。通常,帧之间的时间将不是恒定的。某些系统/核心(例如物理学)将需要一些时间单位才能模拟/运行某些东西。通常,如果时间步长固定,则物理系统更稳定/更易于扩展。固定/可变时间步长之间的差异在名称中。固定时间步长听起来像:以固定时间速率发生的时间步长。可变时间步长是以不同/不同的时间速率发生的时间步长。


在您给出的示例中,每帧的时间是50毫秒,对吗?那是按1000 / FPS计算的?因此,您需要使每一帧的运动是每秒像素* 50/1000?
ShrimpCrackers 2011年

嗯,我意识到尽管每个时间段的毫秒数可能都是可变的,不是吗?诸如getTicks()-startTicks之类的东西始终是不同的,并且不是恒定的。
ShrimpCrackers 2011年

@Omnion:如果您以“每秒像素数”指定距离,则不能使用毫秒...它应该是1.0 / 60.0而不是1000/60,这将导致完全不同。
bummzack 2011年

@ShrimpCrackers是的,经过时间会改变。想象一下一台无法渲染60 fps的旧PC。您仍然希望游戏在这样的机器上以相同的速度(但不以相同的fps)运行。
bummzack 2011年

因此,那么在lazyfoo教程中,deltaticks / 1000.f中的1000是什么意思?FPS?1000毫秒?我现在有点困惑。在确定每一帧所需的时间时,FPS似乎是必需的,但实际上并没有计入运动。
ShrimpCrackers 2011年

7

在框架动态中,您用于(例如)移动实体的代码如下所示:

x = x + speedPerFrame

如果要独立于帧,则可能看起来像这样:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

谢谢,这很有意义。我上面还有另一个问题。
ShrimpCrackers 2011年

1

关于其他问题。

您的点每次都停在不同的位置,因为在移动边界时不会检查边界(y> 580)。一旦它过去580,您就不再停止对其进行进一步更新。

在越过580之前的最后一帧上,您可能从579开始,或者您可能在570,或者您可能在100。您还可以向前移动1像素或1000像素,具体取决于最后一帧执行的时间。

只需将您的IF条件更改为这样,您就可以了。

if ( y <= 580 )
{
    yVel += DOT_VEL;
    y += (yVel * (SDL_GetTicks() - startTicks)/1000.f);
    if( y > 580 )
    {
        y = 580;
    }
    posRect.y = (int)y;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.