Відтворення привидів - зберігання та терміни


11

Я працюю над грою на гоночній машині і просто запровадив привид-привид для відтворення минулих гонок. Я використовую двигун фізики і після багатого прочитання я прийшов до висновку, що найкращим способом зберігання даних привидів для повтору є записування положення та обертання автомобіля в задані часові точки, як, наприклад, описано тут: https: // gamedev. stackexchange.com/a/8380/26261 .

Але який би був хороший спосіб знайти ці моменти часу під час повтору? Прикладом може бути запис із цими даними:

time: +3.19932 (seconds since race start)
position:  180,40 (position at that time)
rotation: 30.4 (rotation at that time)

Але у мене є кілька проблем з цим:

  1. Коли я повторююсь, навряд чи я знову досягну точної точки часу в 3.19932 - швидше за все, у мене з’явиться часова точка близько 3.1 і доведеться знайти найближчий збіг відповідних записів. При інтерполяції навіть найближче співпадання зверху та знизу. Це звучить дуже неефективно і забирає багато часу?

  2. У якій структурі списку я можу зберігати ці записи для подальшого перегляду? Масив? Чи це не означає, що час пошуку записів, що відповідають певному часу, збільшуватиметься, чим довше буде гонка?

  3. Яку частоту слід використовувати для часових точок? Кожен кадр був би - я здогадуюсь - надмірним, а я повинен зберігати, тобто, кожен n-й кадр та інтерполювати між ними, що ускладнює питання зберігання у 2. ще складніше.

Тож ця ідея навіть правильний підхід? Якщо так, то як я можу ефективно зберігати та отримувати дані? Зауважте, що я, як правило, хотів би використовувати структуру даних вище, а не детерміновані іграшки та запис користувачів, тощо.

Дякуємо за будь-яку допомогу!

EDIT: Я розумію, що я повинен описати середовище, яке я використовую: Cocos2D для iPhone. Існує метод update:(ccTime)delta. В ідеалі цей метод називатиметься кожні 1/60 секунд, але немає гарантії - deltaчи минув фактичний час з моменту останньої гри та може бути набагато більше або менше 1/60. Саме в цьому методі я хотів би зберігати поточний іграт.


2
Відмінне запитання. Як показує це, точне повторення складніше, ніж ви могли спочатку подумати, і мені цікаво подивитися, які рішення тут придумали люди.
Крістіан

Відповіді:


8

Чи це не означає, що час пошуку записів, що відповідають певному часу, збільшуватиметься, чим довше буде гонка?

Нія :)

Скажімо, ви зберігаєте його як масив (зверніть увагу, що знімки у хронологічному порядку, але не рівномірно розташовані):

snapshots = [
    {time: 0.0, position: {x,y,z}},
    {time: 0.41,    position: {x,y,z}},
    {time: 0.57,    position: {x,y,z}},
    {time: 1.10,    position: {x,y,z}},
    {time: 1.67,    position: {x,y,z}},
    {time: 2.05,    position: {x,y,z}},
    {time: 3.24,    position: {x,y,z}},
    {time: 3.86,    position: {x,y,z}},
    {time: 3.91,    position: {x,y,z}},
    {time: 5.42,    position: {x,y,z}},
    ...]

Потім, коли починається повтор / гра, ви отримуєте перший і другий елемент з масиву:

nextIdx = 1
previousSnapshot = snapshots[nextIdx-1]
nextSnapshot = snapshots[nextIdx]

Потім у кожному кадрі ( currentTimeпоточний час у цій новій грі):

if currentTime > nextSnapshot.time
    nextIdx++
    previousSnapshot = snapshots[nextIdx-1]
    nextSnapshot = snapshots[nextIdx]

# Do your magic here, e.g.:
snapshotPairGap = nextSnapshot.time - previousSnapshot.time
ratio = (currentTime - previousSnapshot.time) / snapshotPairGap
ghostPosition = {
    x: previousSnapshot.position.x + ratio*(nextSnapshot.position.x - previousSnapshot.position.x)
    y: previousSnapshot.position.y + ratio*(nextSnapshot.position.y - previousSnapshot.position.y)
    z: previousSnapshot.position.z + ratio*(nextSnapshot.position.z - previousSnapshot.position.z)
}

Звичайно, це можна оптимізувати, кешуючи деякі розрахунки. Немає пошуку через масив, просто шукаємо конкретні показники.


ТАК! Я мушу спробувати це пізніше, але це, здається, саме те, що я шукав. Дякую!!
марімба

15

Це не надто важко. Ви можете зберігати свої дані в довільні моменти часу (чим більше, тим краще), а також можете інтерполювати значення даних на основі потрібної часової позначки та даних з двох найближчих записаних часових позначок, наприклад:

N | Time | Position | Rotation
1 | 0.05 | 1, 1, 1  | 0
2 | 0.15 | 1, 2, 1  | 0
3 | 0.25 | 1, 3, 2  | 30

Тепер уявіть, що ви хочете отримати позицію та обертання за час 0.10. Оскільки 0,10 знаходиться між точками '1' (що означає 0,05 разу) і '2' (що означає 0,15 разу), їх потрібно інтерполювати.

timestamp = 0.10
factor = (timestamp - Time[1]) / (Time[2] - Time[1])
position = Lerp(Position[1], Position[2], factor)
rotation = Lerp(Rotation[1], Rotation[2], factor)

Lerpце просто лінійна інтерполяція .

Тож давайте заповнимо прогалини деякими прикладами (*).

N | Time  | Position    | Rotation
1 | 0.05  | 1, 1,    1  | 0
* | 0.075 | 1, 1.25, 1  | 0
* | 0.10  | 1, 1.5,  1  | 0
2 | 0.15  | 1, 2,    1  | 0
* | 0.20  | 1, 2.5,  2  | 15
3 | 0.25  | 1, 3,    2  | 30

HTH.


5
+1. Інтерполяція - це проста і ефективна відповідь. Може бути правдою, що кубічна інтерполяція може дати дещо кращі результати при повороті транспортного засобу, але лінійна буде працювати добре, якщо інтервали досить малі.
Kylotan

Дякуємо, що показали, як інтерполювати! Це буде дуже корисно для моєї гри. Але скажімо, я хотів би отримати час в 41.15, глибоко всередині масиву. Чи почнете ви шукати весь масив, поки не знайдете запис> 41.15?
марімба

1
Простий лінійний пошук може допомогти вам, але двійковий пошук кращий, якщо у вас є відсортований масив: en.wikipedia.org/wiki/Binary_search_algorithm
Marcin Seredynski
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.