Ви хочете розділити показники оновлення (логічний галочок) та намалювати (візуалізувати) ставки.
Ваші оновлення створюють положення всіх об'єктів у світі, які слід намалювати.
Я висвітлю дві різні можливості, ту, яку ви просили, екстраполяцію, а також інший метод, інтерполяцію.
1.
Екстраполяція - це те, коли ми будемо обчислювати (передбачуване) положення об'єкта на наступному кадрі, а потім інтерполювати між поточною позицією об'єктів і позицією, що об'єкт буде знаходитись у наступному кадрі.
Для цього кожен об’єкт, який буде намальований, повинен мати пов'язані velocity
та position
. Щоб знайти позицію, що об'єкт буде знаходитись у наступному кадрі, ми просто додаємо velocity * draw_timestep
до поточного положення об'єкта, щоб знайти передбачуване положення наступного кадру.draw_timestep
- кількість часу, що минув з моменту попереднього галочки візуалізації (aka попередній дзвінок дзвінка).
Якщо ви залишите це на цьому, ви побачите, що об'єкти "мерехтять", коли їх передбачуване положення не відповідає фактичному положенню в наступному кадрі. Щоб видалити мерехтіння, ви можете зберігати передбачувану позицію та перемикатися між попередньо передбачуваною позицією та новою передбачуваною позицією на кожному кроці малювання, використовуючи минулий час з моменту попереднього оновлення галочки як коефіцієнт лерпу. Це все одно призведе до поганої поведінки, коли об'єкти, що швидко рухаються, раптом змінюють місцеположення, і ви, можливо, захочете впоратися з цим особливим випадком. Все, що сказано в цьому пункті, є причинами, чому ви не хочете використовувати екстраполяцію.
2.
Інтерполяція - це те, коли ми зберігаємо стан останніх двох оновлень та інтерполюємо між ними на основі поточного часу, який минув з часу оновлення до останнього. У цій установці кожен об'єкт повинен мати пов'язані position
та previous_position
. У цьому випадку наш малюнок буде представляти в гіршому випадку один галочку оновлення за поточним ігровим статусом, а в кращому випадку - в точно такому ж стані, як і поточний галочок оновлення.
На мою думку, ви, мабуть, хочете інтерполяції, як я це описав, оскільки це простіше здійснити з двох, і намалювати крихітну частку секунди (наприклад, 1/60 секунди) позаду вашого поточного оновленого стану, це добре.
Редагувати:
Якщо вищезазначеного недостатньо, щоб дозволити вам здійснити реалізацію, ось приклад того, як зробити описаний нами метод інтерполяції. Я не буду висвітлювати екстраполяцію, бо не можу придумати жодного реального сценарію, у якому вам слід віддати перевагу.
Коли ви створюєте об'єкт, що малюється, він зберігатиме властивості, необхідні для малювання (тобто інформацію про стан, необхідну для його малювання).
У цьому прикладі ми збережемо положення та обертання. Ви також можете зберігати інші властивості, такі як координатне положення кольору або текстури (тобто, якщо текстура прокручується).
Щоб запобігти зміні даних під час малювання потоку візуалізації (тобто місце розташування одного об'єкта змінюється, коли нитка візуалізації малюється, але всі інші ще не оновлювалися), нам потрібно реалізувати певний тип подвійної буферизації.
Об'єкт зберігає дві його копії previous_state
. Я поміщу їх у масив і позначаю їх як previous_state[0]
і previous_state[1]
. Так само потрібні дві його копії current_state
.
Щоб відслідковувати, яка копія подвійного буфера використовується, ми зберігаємо змінну state_index
, яка доступна як для потоку оновлення, так і для малювання.
Нитка оновлення спочатку обчислює всі властивості об'єкта, використовуючи власні дані (будь-які структури даних, які ви хочете). Потім він копіює current_state[state_index]
в previous_state[state_index]
і копіює нові дані , що відносяться до малювання, position
і rotation
в current_state[state_index]
. Потім це роблять state_index = 1 - state_index
, щоб перевернути поточно використану копію подвійного буфера.
Все, що є у вищевказаному пункті, має бути зроблено із знятим замком current_state
. Теми оновлення та малювання обидва знімають цей замок. Блокування виймається лише на час копіювання інформації про стан, що швидко.
У потоці візуалізації ви робите лінійну інтерполяцію щодо положення та обертання таким чином:
current_position = Lerp(previous_state[state_index].position, current_state[state_index].position, elapsed/update_tick_length)
Де elapsed
кількість часу, що минула в потоці візуалізації, починаючи з останнього галочки оновлення, і update_tick_length
скільки часу займає фіксований показник оновлення на один галочку (наприклад, при оновленнях 20 кадрів в секунду, update_tick_length = 0.05
).
Якщо ви не знаєте, що таке Lerp
функція вище, ознайомтесь із статтею Вікіпедії на тему: Лінійна інтерполяція . Однак якщо ви не знаєте, що таке лерпінг, то, ймовірно, ви не готові реалізувати розв'язане оновлення / малювання з інтерпольованим малюнком.