Ghost replay - depolama ve zamanlama


11

Bir araba yarışı oyunu üzerinde çalışıyorum ve geçmiş yarışları tekrarlamak için bir hayalet sprite uyguladım. Bir fizik motoru kullanıyorum ve çok fazla okuduktan sonra hayalet verilerini tekrar oynatmak için saklamanın en iyi yolunun, örneğin burada açıklandığı gibi verilen zaman noktalarında aracın konumunu ve dönüşünü kaydetmek olduğu sonucuna vardım : https: // gamedev. stackexchange.com/a/8380/26261 .

Ancak, tekrar oynatma sırasında bu zaman noktalarını bulmak için iyi bir yol ne olurdu? Örnek olarak bu verilerle bir kayıt verilebilir:

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

Ama bununla ilgili birkaç problemim var:

  1. Tekrar oynattığımda, 3.19932'deki tam zaman noktasına ulaşmam pek olası değil - daha büyük olasılıkla, 3.1 civarında bir zaman noktasına sahip olacağım ve en yakın eşleşen kaydı bulmam gerekecek. İnterpolasyon yaparken, yukarı ve aşağı en yakın eşleşme bile. Kulağa çok verimsiz ve zaman alıcı geliyor?

  2. Daha sonraki bir tekrar için bu liste yapısında hangi kayıtları saklayabilirim? Bir dizi mi? Bu, belirli bir zamanla eşleşen kayıtlar için arama süresinin, yarış ne kadar uzun olursa artacağı anlamına gelmez mi?

  3. Zaman noktaları için hangi frekansı kullanmalıyım? Her kare-sanırım aşırıya kaçabilir, daha çok yani her n. Kareyi kaydetmeli ve aralarında enterpolasyon yapmalıyım, bu da 2. depolama sorularını daha da zorlaştırır.

Peki bu fikir doğru yaklaşım mı? Evetse, verileri nasıl verimli bir şekilde saklayabilir ve alabilirim? Lütfen belirleyici oyun siteleri ve kullanıcı girişlerini kaydetmemek yerine yukarıdaki veri yapısını kullanmak istediğimi unutmayın.

Herhangi bir yardım için teşekkürler!

EDIT: Kullandığım ortamı tanımlamam gerektiğini fark ettim: iPhone için Cocos2D. Bir yöntem var update:(ccTime)delta. İdeal olarak, bu yöntem her 1/60 saniyede bir çağrılır, ancak garanti yoktur - deltason oyundan bu yana geçen gerçek süredir ve 1/60'tan çok veya daha az olabilir. Şu anki oyun kasasını saklamak istediğim bu yöntemde.


2
Mükemmel soru. Bu gösterdiği gibi, kesin bir tekrar ilk başta düşündüğünüzden daha karmaşıktır ve insanların burada hangi çözümleri bulduğunu merak ediyorum.
Christian

Yanıtlar:


8

Bu, belirli bir zamanla eşleşen kayıtlar için arama süresinin, yarış ne kadar uzun olursa artacağı anlamına gelmez mi?

Hayır :)

Bir dizi olarak sakladığınızı varsayalım (anlık görüntülerin kronolojik sırada olduğunu, ancak eşit aralıklı olmadığını unutmayın):

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}},
    ...]

Ardından, tekrar / oyun başladığında, dizideki birinci ve ikinci öğeyi alırsınız:

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

Sonra her karede ( currentTimebu yeni oyunda şu anki saat):

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)
}

Tabii ki bu bazı hesaplamaların önbelleğe alınmasıyla optimize edilebilir. Dizide arama yapılmaz, sadece belirli endeksleri arar.


EVET! Bunu daha sonra denemek zorundayım, ama aradığım şey bu gibi görünüyor. Teşekkürler!!
marimba

15

Çok zor değil. Verilerinizi rasgele noktalarda (daha fazla, daha iyi) saklayabilir ve aradığınız zaman damgasına ve kaydedilen en yakın iki zaman damgasındaki verilere göre verilerin değerlerini enterpolasyon yapabilirsiniz, örneğin:

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

Şimdi 0.10'da pozisyon ve dönüş almak istediğinizi düşünün. 0.10 '1' (0.05 zaman anlamına gelir) ve '2' (0.15 zaman anlamına gelir) noktaları arasında olduğundan, bunları enterpolasyon yapmanız gerekir.

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)

Lerpsadece doğrusal enterpolasyondur .

Şimdi boşlukları bazı örneklerle (*) dolduralım.

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. İnterpolasyon burada basit ve etkili bir cevaptır. Kübik enterpolasyonun araç dönerken biraz daha iyi sonuçlar verebileceği doğru olabilir, ancak aralıklar yeterince küçükse lineer iyi çalışacaktır.
Kylotan

Nasıl enterpolasyon yapacağınızı gösterdiğiniz için teşekkürler! Bu benim oyunum için çok faydalı olacak. Ama diyelim ki 41.15 zamanında, dizinin derinliklerinde almak istiyorum. > 41,15'lik bir kayıt bulana kadar dizinin tamamında arama yapmaya başlar mısınız?
marimba

1
Basit bir doğrusal arama sizin için işe yarayabilir, ancak sıralı bir diziniz olduğunda ikili arama daha iyidir: en.wikipedia.org/wiki/Binary_search_algorithm
Marcin Seredynski
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.