Кадрний незалежний рух


11

Я читав дві інші теми тут про рух: Рух на основі часу Vs Частота руху на основі частоти? , і коли я повинен використовувати фіксований або змінний крок часу?

але я думаю, що мені бракує базового розуміння кадрового незалежного руху, тому що я не розумію, про що йдеться в будь-якій з цих ниток.

Я слідую за підручниками SDL від lazyfoo і натрапив на самостійний урок кадрів. http://lazyfoo.net/SDL_tutorials/lesson32/index.php

Я не впевнений, що намагається сказати частина руху в коді, але я вважаю, що це (будь-ласка, виправте мене, якщо я помиляюся). напр. спрайт) рухається протягом певного часового періоду, наприклад, 1 секунди. Якщо крапка рухається зі швидкістю 200 пікселів в секунду, то мені потрібно обчислити, скільки вона рухається за ту секунду, множивши 200 пікселів на 1/1000 секунди.

Це так? Урок говорить:

"швидкість у пікселях в секунду * час з моменту останнього кадру в секундах. Отже, якщо програма працює зі швидкістю 200 кадрів в секунду: 200 pps * 1/200 секунд = 1 піксель"

Але ... я думав, що ми множимо 200 пікселів на 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 = 580, коли вона досягне більшого, ніж значення y. Однак кожного разу, коли я запускаю програму, крапка виявиться в іншому місці, тобто трохи більше, ніж 580, тому точка знаходиться на півдорозі або більше, ніж на півдорозі від екрана (крапка - 20 пікселів, екран розміри 800х600). Якщо я щось на зразок натискаю і тримаю заголовок програми, а потім відпускаю, точка зникає з екрана. Як це змінювати кожен раз? Щодо проблеми з заголовком, я думаю, це тому, що коли я тримаюсь за заголовком, таймер все ще працює, а час, що минув, збільшується, в результаті на великій відстані точка рухається в наступному кадрі. Це так?


Ваше доповнення насправді інше питання. Вам слід зробити це другим питанням, а не додавати його до наявного. На це можна легко відповісти: Просто обчисліть рух y, наприклад. yMovement = (yVel * (SDL_GetTicks() - startTicks)/1000.f);тоді робіть:if(y + yMovement <= 580){ y += yMovement; } else { y = 580; }
bummzack

Відповіді:


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 пікселів, сума, яку ми хотіли).

Те, як працює незалежний рух кадру, полягає в тому, що кадри зазвичай трапляються з різними часовими кроками (між наступними кадрами існує різна кількість часу). Якщо ми постійно переміщаємо сутність на постійній відстані до кожного кадру, то рух заснований на частоті кадрів. Якщо між кадрами буде багато часу, гра, здається, рухатиметься занадто повільно, і якщо між кадрами не буде багато часу, гра, здається, буде швидко проходити. (занадто мало часу між кадрами = багато кадрів = більше руху) Щоб подолати це, ми використовуємо швидкість за часом і відстежуємо час між кадрами. Таким чином ми знаємо, скільки часу минуло з часу останнього оновлення позиції та наскільки далі ми повинні рухати організацію.

Кадри в секунду: це кількість кадрів, що проходять за секунду. Зазвичай частота кадрів - це кількість разів, коли гра проводиться / рендерується секунду, або скільки разів цикл гри завершується секундою.

Крок виправленої строкової змінної: Це стосується кількості часу між кадрами. Зазвичай час між кадрами не буде постійним. Деяким системам / кернам, як фізика, знадобиться певна одиниця часу, щоб імітувати / запускати щось. Зазвичай фізичні системи є більш стійкими / масштабованими, якщо крок часу фіксований. Різниця між фіксованими / змінними етапами часу полягає в назвах. Фіксовані етапи часу - це те, що вони звучать: кроки часу, які відбуваються з фіксованою швидкістю часу. Змінні кроки часу - це часові етапи, які відбуваються з різною / різною швидкістю часу.


У наведеному прикладі 50 мілісекунд - це час для кожного кадру, правильно? І що було обчислено 1000 / FPS? І тому рух, який потрібно зробити для кожного кадру, - це пікселі в секунду * 50/1000?
ShrimpCrackers

Хм, я зрозумів, що мілісекунди для кожного часового періоду, ймовірно, будуть змінними, чи не так? Щось на зразок getTicks () - startTicks завжди був би іншим і не постійним.
ShrimpCrackers

@Omnion: Якщо вказати відстань у "пікселях на секунду", ви не можете використовувати мілісекунди ... це повинно бути 1,0 / 60,0, а не 1000/60, що призведе до зовсім іншого.
bummzack

@ShrimpCrackers так, час, що минув, змінюється. Уявіть собі старший ПК, який не здатний відтворювати 60 кадрів в секунду. Ви все ще хочете, щоб гра на такій машині працювала з однаковою швидкістю (але не з тією ж fps).
bummzack

тож тоді в підручнику для ледачих, що означає 1000 в дельтатиках / 1000.f? FPS? 1000 мілісекунд? Я зараз трохи розгублений. Здається, що FPS необхідний для визначення часу, необхідного для кожного кадру, але він насправді не обчислює рух.
ShrimpCrackers

7

У динаміці кадру ваш код для (наприклад) переміщення об'єкта виглядатиме так:

x = x + speedPerFrame

Якщо ви хочете бути незалежними від кадру, це може виглядати приблизно так:

x = x + speedPerSecond * secondsElapsedSinceLastFrame

дякую, це має сенс. У мене є ще одне питання вище.
ShrimpCrackers

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;
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.