Replay sistemi nasıl tasarlanır?


75

Peki bir yeniden oynatım sistemini nasıl tasarlarım?

Warcraft 3 veya Starcraft gibi bazı oyunlardan, oyunu zaten oynandıktan sonra tekrar izleyebileceğinizden bildiğiniz gibi.

Göreceli olarak küçük bir yeniden oynatım dosyası ile bitirdiniz. Yani benim sorularım:

  • Veriler nasıl kaydedilir? (özel biçim?) (küçük dosya boyutu)
  • Ne kurtulacak?
  • Diğer oyunlarda bir zaman periyodu kaydetmek için kullanılabilir (ve örneğin tam bir eşleşme değil), nasıl jenerik hale getirilir?
  • İleri ve geri sarmayı mümkün kıl (WC3 hatırladığım kadarıyla geri saramadı)

3
Her ne kadar aşağıdaki cevaplar çok değerli bilgiler sunsa da, amacınıza ulaşmak için şart olduğu için oyununuzu / motorunuzu geliştirmenin önemini çok belirleyici olmak için vurguladım ( en.wikipedia.org/wiki/Deterministic_algorithm ).
Ari Patrick,

2
Ayrıca fizik motorlarının deterministik olmadığına da dikkat edin (Havok öyle olduğunu iddia ediyor ...) bu nedenle, oyununuz fizik kullanıyorsa, girişleri ve zaman damgalarını yalnızca kaydetmenin çözümü farklı sonuçlar doğuracaktır.
Samaursa

5
Çoğu fizik motoru, yine de yapmanız gereken sabit bir zaman aralığı kullandığınız sürece belirleyicidir. Havok olmasa çok şaşırırdım. Belirsizlik

4
Deterministik, aynı girişler = aynı çıkışlar anlamına gelir. Bir platformda yüzerseniz ve diğerinde ikiye katlarsanız (örneğin) veya IEEE kayar nokta standart uygulamanızı isteyerek devre dışı bırakırsanız, bu aynı girdilerle çalışmamanız anlamına gelir, belirleyici değil.

3
Bana mı öyle geliyor, yoksa bu soru her hafta bir ödül alıyor mu?
Komünist Ördek

Yanıtlar:


39

Bu mükemmel makale birçok konuyu kapsamaktadır: http://www.gamasutra.com/view/feature/2029/developing_your_own_replay_system.php

Makalenin bahsettiği ve iyi yaptığı birkaç şey:

  • oyununuz deterministik olmalı.
  • Oyun sistemlerinin başlangıç ​​durumunu ilk karede ve sadece oyun sırasında oyuncu girişini kaydeder.
  • bit sayısını azaltmak için girdileri ölçün. Yani. çeşitli aralıklardaki yüzdeleri temsil eder (örneğin [0, 1] veya [-1, 1] daha az bit içindeki aralık). Gerçek oyun sırasında da sayısallaştırılmış girdilerin elde edilmesi gerekir.
  • Bir giriş akışının yeni veri olup olmadığını belirlemek için tek bir bit kullanın. Bazı akışlar sık ​​sık değişmeyeceğinden bu, girdilerde zamansal tutarlılığı kullanır.

Çoğu durumda sıkıştırma oranını daha da iyileştirmenin bir yolu, tüm girdi akışlarınızı ayırmak ve tüm çalışma uzunluğu onları bağımsız olarak kodlamak olacaktır. Eğer koşunuzu 8-bit olarak kodlarsanız ve koşunun kendisi 8 kareyi aşarsa (oyununuz gerçek bir düğme ezici olmadığı sürece büyük olasılıkla) bu delta kodlama tekniğine göre bir kazanç olacaktır. Bu teknikte bir yarış oyununda, 2 oyuncudan 8 dakikalık bir girişi, bir parçadan aşağıya yüzlerce bayta kadar sıkıştırırken kullandım.

Bu tür bir sistemi tekrar kullanılabilir hale getirme açısından, yeniden oynatma sistemini genel girdi akışlarıyla uğraşırken, aynı zamanda oyuna özgü mantığın bu akarsulara klavyeyle / gamepad / fare girişine izin vermesi için kancalar sağladım.

Hızlı geri alma veya rastgele arama yapmak istiyorsanız, her N karede bir denetim noktası (tam oyun alanınız) kaydedebilirsiniz. Tekrar oynatım dosya boyutunu en aza indirmek için N seçilmeli ve durum seçilen noktaya tekrar oynatılırken oynatıcının beklemesi gereken sürenin makul olduğundan emin olun. Bunu aşmanın bir yolu, rastgele aramaların yalnızca bu kesin kontrol noktası konumlarına yapılabilmesini sağlamaktır. Geri sarma, söz konusu kareden hemen önce oyun durumunu kontrol noktasına getirip ardından mevcut kareye ulaşana kadar girişleri tekrarlamaktan ibarettir. Ancak, N çok büyükse, her birkaç karede otostop çekebilirsiniz. Bu aksaklıkları düzeltmenin bir yolu, geçerli kontrol noktası bölgesinden önbelleğe alınmış bir kareyi oynatırken önceki 2 kontrol noktası arasındaki kareleri eşzamansız olarak önbelleğe almaktır.


rng sonra katılan sonuçlarını içerir varsa akışlarında rng bahsedilen
ucube mandal

1
@ cırcır ucube: PRNG'nin deterministik kullanımıyla, kontrol noktasında yalnızca tohumlarını saklayarak elde edebilirsiniz.
Nümerik olmayan

22

Şaşırtıcı derecede zor olabilen "tuş vuruşlarının tekrarlanabilir olduğundan emin olun" çözümünün yanı sıra, tüm oyun durumunu her kareye kaydedebilirsiniz. Biraz akıllıca sıkıştırma ile önemli ölçüde sıkabilirsiniz. Braid, zaman geri sarma kodunu bu şekilde ele alıyor ve oldukça iyi çalışıyor.

Geri sarmak için yine de kontrol noktasını işaretlemeniz gerekeceğinden, işleri karmaşık hale getirmeden önce basit bir şekilde uygulamayı denemek isteyebilirsiniz.


2
+1 Akıllıca bir sıkıştırma ile saklamanız gereken veri miktarını gerçekten aşağı çekebilirsiniz (örneğin, mevcut nesne için sakladığınız son duruma göre değişmediyse durumu saklamayın) . Bunu zaten fizikle denedim ve gerçekten iyi çalışıyor. Fizikle yoktur ve tam bir oyun geri sarma istemiyorsanız bu mümkün olan en küçük dosyaları üretecek çünkü ben siz de geri sarma istiyorsanız, yalnızca son saklayabilirsiniz bu durumda Joe'nun solüsyonu ile gider nsaniyesini oyun.
Samaursa

@Samaursa - Eğer standart bir sıkıştırma kütüphanesi kullanırsanız (örneğin, gzip), durumun değişip değişmediğini görmek için kontrol etmek gibi şeyleri manuel olarak yapmak zorunda kalmadan aynı (muhtemelen daha iyi) sıkıştırma elde edersiniz.
Justin,

2
@ Kragen: Gerçekten doğru değil. Standart sıkıştırma kitaplıkları kesinlikle iyidir ancak genellikle alana özgü bilgilerden yararlanamazlar. Bunlara biraz yardımcı olabilirseniz, benzer verileri yan yana koyarak ve gerçekten değişmeyen şeyleri çıkararak, şeyleri büyük ölçüde azaltabilirsiniz.
ZorbaTHut

1
@ZorbaTHut Teoride evet, ama pratikte gerçekten çabaya değer mi?
Justin,

4
Çabaya değip değmeyeceği, tamamen sizin ne kadar veriniz olduğuna bağlıdır. Yüzlerce veya binlerce üniteye sahip bir RTS'niz varsa, muhtemelen önemlidir. Tekrarları Braid gibi bir hafızada saklamanız gerekirse, büyük olasılıkla önemlidir.

21

Sisteminizi bir dizi durum ve işlevden oluşuyormuş gibi görüntüleyebilirsiniz f[j]; girişli bir işlev x[j]sistem durumunu duruma s[j]dönüştürür s[j+1], şöyle:

s[j+1] = f[j](s[j], x[j])

Bir devlet, tüm dünyanızın açıklamasıdır. Oyuncunun yerleri, düşmanın yeri, skor, kalan cephane vb. Oyununun bir çerçevesini çizmek için gereken her şey.

Bir fonksiyon dünyayı etkileyebilecek herhangi bir şeydir. Bir çerçeve değişikliği, bir tuşa basma, bir ağ paketi.

Giriş, işlevin aldığı verilerdir. Bir kare değişikliği, son karenin geçmesinden bu yana geçen süreyi alabilir, tuşa basılması, basılan tuşun yanı sıra, üst karakter tuşuna basılıp basılmayacağını da içerebilir.

Bu açıklama uğruna aşağıdaki varsayımları yapacağım:

Varsayım 1:

Oyunun belirli bir çalışması için durum miktarı, fonksiyonların miktarından çok daha fazladır. Muhtemelen yüz binlerce devlete sahipsiniz, ancak sadece birkaç düzine işlev (çerçeve değişikliği, tuşa basma, ağ paketi, vb.). Tabii ki, girdilerin miktarı eksi bir devletlerin miktarına eşit olmalıdır.

Varsayım 2:

Tek bir durumu kaydetmenin uzaysal maliyeti (bellek, disk), bir işlevin ve bunun girişinin kaydedilmesinden çok daha büyüktür.

Varsayım 3:

Bir devlet sunmanın zamansal maliyeti (zamanı) benzerdir ya da bir devlet üzerindeki bir işlevi hesaplamaktan yalnızca bir ya da iki büyüklük emri alır.

Yeniden oynatma sisteminizin gereksinimlerine bağlı olarak, bir yeniden oynatma sistemini uygulamanın birkaç yolu vardır, böylece en basitinden başlayalım. Ayrıca kağıda kaydedilmiş olan satranç oyununu kullanarak küçük bir örnek yapacağım.

Yöntem 1:

Mağaza s[0]...s[n]. Bu çok basit, çok basit. 2. varsayım nedeniyle, bunun uzaysal maliyeti oldukça yüksektir.

Satranç için, bu her hamle için bütün tahtayı çizerek başarılabilirdi.

Yöntem 2:

Yalnızca ileriye tekrar oynatmaya ihtiyacınız varsa, basitçe saklayabilir s[0]ve sonra saklayabilirsiniz f[0]...f[n-1](unutmayın, bu sadece işlevin kimliği olan isimdir) ve x[0]...x[n-1](bu işlevlerin her birinin girişi neydi). Tekrarlamak için, basitçe başlamak s[0]ve hesaplamak

s[1] = f[0](s[0], x[0])
s[2] = f[1](s[1], x[1])

ve bunun gibi...

Burada küçük bir açıklama yapmak istiyorum. Diğer bazı yorumcular oyunun "deterministik" olması gerektiğini söyledi. Bunun Computer Computer 101'i tekrar alması gerektiğini söyleyen herkes, çünkü oyununuz kuantum bilgisayarlarda çalıştırılmak istenmediği sürece, TÜM BİLGİSAYAR PROGRAMLARI TESPİT EDER. Bilgisayarları bu kadar harika yapan da bu.

Ancak, programınız büyük olasılıkla kütüphanelerden işlemcinin fiili uygulamasına kadar uzanan harici programlara bağlı olduğundan, işlevlerinizin platformlar arasında aynı şekilde davranmasını sağlamak oldukça zor olabilir.

Sözde rasgele sayılar kullanırsanız, oluşturulan sayıları girişinizin bir parçası olarak xveya prng işlevinin durumunu durumunuzun bir parçası olarak sve bunun işlevinin bir parçası olarak uygulayabilirsiniz f.

Satranç için bu, ilk tahtanın (bilinen) çizilmesi ve sonra hangi parçanın nereye gittiğini söyleyerek her hareketi açıklamakla başarılabilir. Bu arada, bunu gerçekten yapıyorlar.

Yöntem 3:

Şimdi, büyük olasılıkla tekrarınızı arayabilmek isteyeceksiniz. Yani, s[n]keyfi bir şekilde hesaplayın n. Yöntem 2'yi kullanarak, hesaplama s[0]...s[n-1]yapmadan önce hesaplamanız gerekir s[n], bu varsayım 2'ye göre oldukça yavaş olabilir.

Bu uygulamak için, yöntem 3 yöntem 1 ve 2 arasında bir genellemedir: mağaza f[0]...f[n-1]ve x[0]...x[n-1]sadece yöntem 2 gibi, ama aynı zamanda depolamak s[j]için tüm, j % Q == 0sabit verilen için Q. Daha kolay bir ifadeyle, bu, bir yer işaretini her Qeyaletten birinde sakladığınız anlamına gelir . Örneğin Q == 100, sizin içins[0], s[100], s[200]...

Hesaplayabilmek için s[n]keyfi bir için n, önce önceden depolanan yük s[floor(n/Q)]ve ardından gelen tüm fonksiyonları hesaplamak floor(n/Q)için n. En fazla, Qfonksiyonları hesaplayacaksınız . Küçük değerleri Qhesaplamak için daha hızlıdır ancak çok daha fazla alan tüketirken, daha büyük değerleri Qdaha az alan tüketir, ancak hesaplaması daha uzun sürer.

Yöntem 3 ile Q==1yöntem 1 ile aynı iken yöntem 3 ile yöntem 2 ile Q==infaynıdır.

Satranç için bu, her hareketin yanı sıra (her) her 10 tahtadan birini çizerek gerçekleştirilebilir Q==10.

Yöntem 4:

Eğer tekrarını tersine çevirmek istiyorsanız, yöntemin 3. küçük varyasyon Varsayalım yapabilir Q==100ve Hesaplamak istediğiniz s[150]aracılığıyla s[90]tersten. Değiştirilmemiş yöntem 3 ile, elde etmek için 50 s[150], sonra elde etmek için 49 hesaplama daha yapmanız gerekir s[149]. Ancak s[149]almak için zaten hesapladığınızdan beri , ilk defa hesaplarken s[150]bir önbellek oluşturabilirsiniz ve sonra onu görüntülemek istediğinizde zaten önbellekte olacaksınız.s[100]...s[150]s[150]s[149]

Yalnızca önbelleğe sen hesaplamak gerekir her zaman yenilenmeye ihtiyacı s[j]için, j==(k*Q)-1verilen herhangi k. Bu sefer, arttırmak Qdaha küçük boyutta (sadece önbellek için), daha uzun zamanlarla (sadece önbelleği yeniden oluşturmak için) sonuçlanacaktır. QDurumları ve fonksiyonları hesaplamak için gereken boyutları ve süreleri biliyorsanız, optimal bir değer hesaplanabilir.

Satranç için, bu her hamle ve her 10 panodan birinde (for Q==10) birer çizim yaparak başarılabilir , ancak hesapladığınız son 10 panodan ayrı bir kağıda çizilmesi gerekir.

Yöntem 5:

Durumlar çok fazla yer kaplarsa veya işlevler çok fazla zaman harcarsa, gerçekte ters oynatmayı uygulayan (sahte değil) bir çözüm oluşturabilirsiniz. Bunu yapmak için, sahip olduğunuz işlevlerin her biri için ters işlevler oluşturmalısınız. Ancak bu, her bir fonksiyonunuzun bir enjeksiyon olmasını gerektirir. Eğer bu yapılabilir ise, o zaman f'fonksiyonun tersini belirtmek için fhesaplama s[j-1]yapmak basittir.

s[j-1] = f'[j-1](s[j], x[j-1])

Burada, işlev ve girişin ikisinin de j-1olmadığını unutmayın j. Bu aynı işlev ve girdi, hesaplarsanız kullanmış olacağınız şeyler olurdu.

s[j] = f[j-1](s[j-1], x[j-1])

Bu fonksiyonların tersini oluşturmak zor olan kısımdır. Bununla birlikte, genellikle bir oyunda her işlevden sonra bazı durum verileri genellikle kaybolduğundan, yapamazsınız.

Bu yöntem, olduğu gibi, hesaplamayı tersine çevirebilir s[j-1], ancak yalnızca siz varsa s[j]. Bu, tekrar oynatmaya karar verdiğiniz noktadan başlayarak tekrar oynatmayı izleyebileceğiniz anlamına gelir. İsteğe bağlı bir noktadan geriye doğru oynatmak istiyorsanız, bunu yöntem 4 ile karıştırmanız gerekir.

Satranç için, bu uygulanamaz, çünkü belirli bir tahta ve önceki hamle ile, hangi taşın taşındığını, ancak taşının nerden hareket ettiğini bilemezsiniz.

Yöntem 6:

Son olarak, tüm fonksiyonlarınızın enjeksiyon olduğunu garanti edemezseniz, bunu yapmak için küçük bir numara yapabilirsiniz. Her işlevin yalnızca yeni bir durum döndürmesini sağlamak yerine, attığı verileri de geri göndermesini sağlayabilirsiniz:

s[j+1], r[j] = f[j](s[j], x[j])

r[j]Atılan veriler nerede . Ve sonra ters fonksiyonlarınızı yaratın, böylece atılan verileri alıp, şöyle:

s[j] = f'[j](s[j+1], x[j], r[j])

Ek olarak f[j]ve x[j], ayrıca saklamanız gerekir r[j]her fonksiyon için. Bir kez daha, arayabilmek istiyorsanız, yöntem 4'deki gibi yer imlerini saklamanız gerekir.

Satranç için, bu yöntem 2 ile aynı olacaktır, ancak yalnızca hangi parçanın nereye gittiğini söyleyen yöntem 2'den farklı olarak, aynı zamanda her bir parçanın nereden geldiğini saklamanız gerekir.

Uygulama:

Bu her türlü devlet için, her türlü fonksiyon için, belirli bir oyunda çalıştığından, uygulanmasını kolaylaştıracak çeşitli varsayımlar yapabilirsiniz. Aslında, 6 yöntemini tüm oyun durumuyla uygularsanız, sadece verileri tekrar izleyemezsiniz, aynı zamanda zamanda geri dönüp herhangi bir andan itibaren oynamaya devam edebilirsiniz. Bu harika olurdu.

Tüm oyun durumunu kaydetmek yerine, belirli bir durumu çizmeniz için gereken minimum değeri saklayabilir ve bu verileri her sabit zamanda seri hale getirebilirsiniz. Durumlarınız bu serileştirmeler olacak ve girişiniz şimdi iki serileştirme arasındaki fark olacaktır. Bunun çalışması için anahtar, dünya devletinin de az değişmesi durumunda serileştirmenin az değişmesi gerektiğidir. Bu fark tamamen tersinirdir, bu yüzden imleri içeren yöntem 5 kullanmak çok mümkündür.

Bunun bazı büyük oyunlarda uygulandığını, çoğunlukla bir olay (fps'de bir fragman veya spor oyunlarında bir skor) meydana geldiğinde en son verilerin anında oynatılması için uygulandığını gördüm.

Umarım bu açıklama çok sıkıcı değildi.

¹ Bu, bazı programların deterministik olmadığı gibi davrandığı anlamına gelmez (örneğin, MS Windows ^^ gibi). Şimdi ciddi olarak, deterministik bir bilgisayarda deterministik olmayan bir program yapabilirseniz, eşzamanlı olarak Fields madalyası, Turing ödülü ve muhtemelen bir Oscar ve Grammy'yi kazanacağınızdan emin olabilirsiniz.


"TÜM BİLGİSAYAR PROGRAMLARI BELİRLEYİCİDİR" ifadesinde, iş parçacığına dayanan programları göz önünde bulundurmayı ihmal ediyorsunuz. Diş çekme, çoğunlukla kaynakları yüklemek için veya oluşturma döngüsünü ayırmak için kullanılsa da, bunun istisnaları vardır ve bu noktada, determinizmi uygulama konusunda yeterince katı olmadığınız sürece, gerçek determinizmi talep edemeyebilirsiniz. Kilitleme mekanizmaları tek başına yeterli olmaz. Ekstra bir çalışma yapmadan HERHANGİ BİR değişken veri paylaşamazsınız. Pek çok senaryoda, bir oyun kendi iyiliği için bu katılık seviyesine ihtiyaç duymaz, ama tekrarlar gibi şeyler için olabilir.
krdluzni

1
@krdluzni Gerçek rastgele kaynaklardan tehdit, paralellik ve rastgele sayılar, programları deterministik yapmaz. İplik zamanlamaları, kilitlenmeler, başlatılmamış bellek ve hatta yarış koşulları programınızın aldığı ek girdilerdir. Bu girişleri atma ya da hiç dikkate almama seçiminiz (herhangi bir sebepten dolayı) programınızın tam olarak aynı girişler göz önüne alındığında tamamen aynı şekilde çalışacağını etkilemeyecektir. “deterministik olmayan” çok kesin bir Bilgisayar Bilimi terimidir, bu yüzden ne anlama geldiğini bilmiyorsanız lütfen kullanmaktan kaçının.

@oscar (Biraz titiz, meşgul olabilir, daha sonra düzenleyebilir): Bazı kesin, teorik anlamda girdi zamanları vb. girişler olarak iddia etseniz de, genel olarak gözlemlenemediklerinden, bu herhangi bir pratik anlamda kullanışlı değildir. Programın kendisi veya tamamen geliştirici tarafından kontrol edilir. Ayrıca, deterministik olmayan bir program, deterministik olmayan (durumsal makine anlamında) belirgin bir şekilde farklıdır. Terimin anlamını anlıyorum. Keşke önceden var olan bir terimi aşırı yüklemek yerine başka bir şey seçmişlerdi.
krdluzni

@krdluzni İplik zamanlamaları gibi önceden tahmin edilemeyen elemanlarla tekrarlama sistemleri tasarlamadaki amacım (eğer bir tekrarlamayı doğru bir şekilde hesaplama yeteneğinizi etkilerlerse), onları tıpkı kullanıcı girişi gibi, diğer herhangi bir giriş kaynağı gibi ele almaktır. Bir programdan şikayetçi kimsenin "deterministik" olmadığını görmüyorum, çünkü bu tamamen öngörülemeyen bir kullanıcı girişi gerektiriyor. Terim gelince, bu yanlış ve kafa karıştırıcı. "Tahmin edilemez" gibi bir şey ya da onun gibi bir şey kullanmalarını tercih ederim. Ve hayır, imkansız değil, VMWare'in tekrar hata ayıklamasını kontrol edin.

9

Diğer cevapların henüz ele almadığı şeylerden biri de yüzmek tehlikesi. Şamandıraları kullanarak tamamen deterministik bir uygulama yapamazsınız.

Şamandıraları kullanarak tamamen deterministik bir sisteme sahip olabilirsiniz, ancak yalnızca:

  • Tam olarak aynı ikili dosyayı kullanma
  • Tam olarak aynı CPU’yu kullanma

Bunun nedeni şamandıraların dahili gösteriminin bir CPU'dan diğerine - en belirgin şekilde AMD ve intel CPU'lar arasında değişmesidir. Değerler FPU kayıtlarında olduğu sürece, C tarafından göründüğünden daha doğrudurlar, bu nedenle ara hesaplamalar daha yüksek hassasiyetle yapılır.

Bunun AMD vs intel bit'i nasıl etkileyeceği oldukça açık - diyelim ki biri 80 bit yüzer, diğeri 64 kullanıyor - diğeri neden aynı ikili gereksinime?

Dediğim gibi, değerler FPU kayıtlarında olduğu sürece daha yüksek hassasiyet kullanılır . Bu, ne zaman derleyerseniz derleyici optimizasyonunuzun FPU kayıtlarının içindeki ve dışındaki değerleri değiştirebileceği ve çok farklı sonuçlara yol açabileceği anlamına gelir.

Mümkün olan en düşük hassasiyeti kullanmak için _control87 () / _ controlfp () bayraklarını ayarlayarak bu konuda yardımcı olabilirsiniz . Bununla birlikte, bazı kütüphaneler de buna dokunabilir (en azından d3d'nin bir sürümü yaptı).


3
GCC ile değerleri kayıt dışı bırakmak ve kontrol bayraklarınızla uğraşan diğer kütüphaneler için endişelenmenize gerek kalmadan 32/64 bit hassasiyete kadar kesmek için -ffloat-store kullanabilirsiniz. Açıkçası, bu sizin hızınızı olumsuz yönde etkileyecektir (fakat başka herhangi bir miktar belirlemesi de olacaktır).

8

Rasgele sayı üreteçlerinizin başlangıç ​​durumunu kaydedin. Sonra her girişi (fare, klavye, ağ, her neyse) zaman damgalı kaydedin. Ağa bağlı bir oyununuz varsa, muhtemelen zaten hepsine sahip olmalısınız.

RNG'leri tekrar ayarlayın ve girişi oynatın. Bu kadar.

Bu, baştan başlayabildiğiniz kadar hızlı oynamanın dışında, genel bir çözüm bulunmayan yeniden sarma işlemini çözmez. Her X saniyede bir tüm oyun durumunu kontrol ederek bunun için performansı artırabilirsiniz, o zaman sadece o kadarını tekrar etmeniz gerekecektir, ancak oyun durumunun tamamı aynı zamanda alması da çok pahalı olabilir.

Dosya formatının özellikleri önemli değil, ancak çoğu motorun komutları seri hale getirme ve halihazırda ağ oluşturma, kaydetme veya her neyse durumu belirtme yolu vardır. Sadece onu kullan.


4

Deterministik tekrarlamaya karşı oy kullanırdım. Her varlığın durumunu saniyede bir / 1'de bir kaydetmek, FAR basittir ve FAR daha az hataya meyillidir.

Oynatma sırasında göstermek istediğiniz şeyi saklayın - yalnızca konum ve başlıksa, iyi, istatistikleri de göstermek istiyorsanız, bunu da kaydedin, ancak genel olarak mümkün olduğunca az tasarruf edin.

Kodlamayı düzenleyin. Her şey için mümkün olduğunca az bit kullanın. Tekrar oynat, yeterince iyi göründüğü sürece mükemmel olmak zorunda değildir. Örneğin için bir kayan nokta kullanıyor olsanız bile, bayt olarak kaydedebilir ve 256 olası değer elde edebilirsiniz (1,4º hassasiyet). Özel probleminiz için bu yeterli veya hatta çok fazla olabilir.

Delta kodlamasını kullanın. Kurumlarınız ışınlanmadıkça (ve yaparlarsa, davayı ayrı ayrı ele alın), pozisyonları yeni pozisyon ile eski pozisyon arasındaki fark olarak kodlayın - kısa hareketler için, tam pozisyonlara ihtiyaç duyduğunuzdan çok daha az bit ile kurtulabilirsiniz .

Kolay geri alma yapmak istiyorsanız, her N karede ana kareler (tam veri, delta yok) ekleyin. Bu şekilde deltalar ve diğer değerler için daha düşük hassasiyetle kurtulursunuz, periyodik olarak "doğru" değerlere sıfırlarsanız, yuvarlama hataları o kadar problemli olmayacaktır.

Sonunda, her şeyi gzip :)


1
Bu olsa oyun tipine biraz bağlıdır.
Jari Komppa

Bu ifadeye çok dikkat ederdim. Özellikle 3. parti bağımlılığı olan daha büyük projeler için devleti kurtarmak imkansız olabilir. Sıfırlama ve tekrar oynatırken giriş her zaman mümkündür.
TomSmartBishop 17:18

2

Zor. Öncelikle ve çoğu Jari Komppa cevaplarını okudu.

Şamandıra sonucu tamamen farklı olduğundan, bilgisayarımda yapılan bir yeniden oynatma bilgisayarınızda çalışmayabilir. Bu büyük bir anlaşma.

Ancak bundan sonra, rastgele sayılarınız varsa, tohum değerini tekrarda saklamaktır. Ardından tüm varsayılan durumları yükleyin ve rasgele sayıyı o çekirdeğe ayarlayın. Oradan sadece geçerli anahtar / fare durumunu ve bunun bu şekilde kaldığı süreyi kaydedebilirsiniz. Ardından bütün olayları giriş olarak kullanarak çalıştırın.

Dosyaları atlamak (daha zordur) için BELLEK'i terk etmeniz gerekir. Mesela, her birimin olduğu yerde, para, zamanın uzunluğu geçiyor, tüm oyun durumu. Sonra hızlı ileri sarma ancak her şeyi tekrar çalma ancak istediğiniz zaman hedefine gelene kadar oluşturma, ses vb. Bu, ilerlemenin ne kadar hızlı olduğuna bağlı olarak her dakika veya 5 dakikada bir gerçekleşebilir.

Ana noktalar - Rastgele sayılarla uğraşmak - Kopyalama girişi (oyuncu (lar) ve uzak oyuncu (lar)) - Dosyaların etrafından atlamak için boşaltma durumu ve ... - YERLEŞTİRİLMEYEN BANT


2

Bu seçeneğin kimseden bahsetmemesine biraz şaşırdım, ancak oyununuzun çok oyunculu bir bileşeni varsa, bu özellik için gerekli olan çok fazla çalışmayı yapmış olabilirsiniz. Ne de olsa, çok oyunculu olan nedir ama başkasının hareketlerini kendi bilgisayarınızda (biraz) farklı bir zamanda tekrar oynatmaya çalışmak?

Bu aynı zamanda, bant genişliği dostu ağ kodu üzerinde çalıştığınızı varsayarak, daha küçük bir dosya boyutunun avantajlarından yararlanır.

Birçok yönden, hem "son derece belirleyici ol" hem de "her şeyin kaydını tut" seçeneklerini birleştiriyor. Yine de determinizme ihtiyacınız olacak - eğer yeniden oynamanız oyunu ilk başta tam olarak oynadığınız şekilde tekrar oynamaktan hoşlanıyorsa, rastgele sonuçlara sahip olabilecek her hangi bir eylemin aynı sonucu alması gerekir.

Veri formatı ağ trafiğinin bir dökümü kadar basit olabilir, ancak biraz temizlemenin bir zararı olmayacağını hayal ediyorum (sonuçta, yeniden oynatmada gecikme konusunda endişelenmenize gerek yok). Diğer insanların bahsettiği kontrol noktası mekanizmasını kullanarak oyunun sadece bir bölümünü yeniden oynayabilirsiniz - genellikle çok oyunculu bir oyun zaten her seferinde oyun güncellemesinin tam durumunu gönderir, bu yüzden zaten bu işi yapmış olabilirsiniz.


0

Mümkün olan en küçük tekrar oynatım dosyasını elde etmek için oyununuzun deterministik olduğundan emin olmanız gerekir. Genellikle bu, rastgele sayı üreticinize bakmaktan ve oyun mantığında nerede kullanıldığını görmekten ibarettir.

GUI, parçacık efektleri, sesler gibi şeyler için bir oyun mantığı RNG'sine ve RNG'ye sahip başka bir şeye ihtiyacınız olacak. Bunu yaptıktan sonra, oyun mantığı RNG'nin başlangıç ​​durumunu kaydetmeniz gerekir, ardından oyun her oyuncu için tüm oyuncuların komutlarını verir.

Birçok oyun için, giriş ile girişin komutlara çevrildiği oyun mantığı arasında bir soyutlama seviyesi vardır. Örneğin, denetleyici üzerindeki A düğmesine basmak, "atlama" dijital komutunun true olarak ayarlanmasıyla sonuçlanır ve oyun mantığı, denetleyiciyi doğrudan denetlemeden komutlara tepki verir. Bunu yaparak, yalnızca oyun mantığını etkileyen komutları kaydetmeniz gerekecektir (“Duraklat” komutunu kaydetmenize gerek yoktur) ve büyük olasılıkla bu veriler kontrolör verilerinin kaydedilmesinden daha küçük olacaktır. Ayrıca, oynatıcının düğmeleri yeniden eşleştirmeye karar vermesi durumunda, kontrol planının durumunu kaydetme konusunda endişelenmenize gerek yoktur.

Geri alma, deterministik metodu kullanarak ve oyun durumunun anlık görüntüsünü kullanmaktan başka bir şey kullanmaktan ziyade, zamana bakmak istediğiniz noktaya hızlı ileri sarmak, her karenin bütün durumunu kaydetmek için yapabileceğiniz pek bir şey değildir.

Öte yandan, hızlı ileri sarma kesinlikle yapılabilir. Oyun mantığınız renderinize bağlı olmadığı sürece, oyun mantığını oyunun yeni bir çerçevesini oluşturmadan önce istediğiniz kadar çalıştırabilirsiniz. Hızlı ileri sarma hızı sadece makineniz tarafından bağlanacaktır. Büyük artışlarla ileri atlamak istiyorsanız, geri sarma için gereken aynı anlık görüntü yöntemini kullanmanız gerekir.

Muhtemelen determinizme dayanan bir replay sistemi yazmanın en önemli kısmı, bir hata ayıklama veri akışını kaydetmektir. Bu hata ayıklama akışı, her karenin (RNG tohumları, varlık dönüşümleri, animasyonlar, vb.) Mümkün olduğunca fazla bilgi görüntüsünü içerir ve bu kaydedilen hata ayıklama akışını tekrar oynatım sırasında oyunun durumuna karşı test edebilir. Bu, herhangi bir çerçevenin sonunda uyuşmazlıkları hızlı bir şekilde size bildirmenizi sağlar. Bu sayede saatlerce bilinmeyen deterministik böceklerden saçınızı çıkarmak isteyebilirsiniz. Başlatılmamış bir değişken kadar basit olan bir şey 11. saatte her şeyi mahveder.

NOT: Oyununuz dinamik içerik akışı içeriyorsa veya birden fazla iş parçacığında ya da farklı çekirdeklerde oyun mantığınız varsa ... iyi şanslar.


0

Hem kaydı hem de geri sarmayı etkinleştirmek için tüm olayları kaydedin (kullanıcı tarafından oluşturulan, zamanlayıcı tarafından oluşturulan, iletişim oluşturulan, ...).

Her olay için olayın kayıt süresi, neyin değiştirildiği, önceki değerler, yeni değerler.

Hesaplamanın rastgele olmadığı sürece hesaplanan değerlerin kaydedilmesine gerek yoktur
(Bu durumlarda, hesaplanmış değerleri de kaydedebilir veya her rastgele hesaplamanın ardından tohumdaki değişiklikleri kaydedebilirsiniz).

Kaydedilen veriler bir değişiklik listesidir.
Değişiklikler çeşitli biçimlerde (binary, xml, ...) kaydedilebilir.
Değişiklik varlık kimliği, özellik adı, eski değer, yeni değerden oluşur.

Sisteminizin bu değişiklikleri oynatabildiğinden emin olun (istediğiniz öğeye erişin, istenen özelliği yeni durumuna ileri ya da eski durumuna geri çevirin).

Örnek:

  • başlangıç ​​zamanı = t1, varlık = oyuncu 1, özellik = konum, a'dan b'ye değiştirildi
  • başlangıç ​​zamanı = t1, varlık = sistem, özellik = oyun modu, c'den d'ye değiştirildi
  • başlangıç ​​zamanı = t2, varlık = oyuncu 2, özellik = durum, e'den f'ye değiştirildi
  • Daha hızlı geri sarma / hızlı ileri alma veya yalnızca belirli zaman aralıklarında
    kayıt yapabilmek için , anahtar kareler gereklidir - eğer her zaman, her zaman kayıt yapıyorsanız ve ardından tüm oyun durumunu kaydedin.
    Sadece belirli bir zaman aralığında kayıt yapıyorsanız, başlangıçta başlangıç ​​durumunu kaydedin.


    -1

    Yeniden oynatma sisteminizi nasıl uygulayacağınıza ilişkin fikirlere ihtiyacınız varsa , bir uygulamada geri alma / geri alma işleminin nasıl uygulanacağı hakkında google'da arama yapın . Bazıları için açık olabilir, ama belki de herkes için geri alma / yineleme kavramının oyunlar için tekrarlama ile aynı olduğu açıktır. Sadece geri sarabileceğiniz ve uygulamaya bağlı olarak, zaman içinde belirli bir noktaya gelebileceğiniz özel bir durumdur.

    Belirlemeyen / yineleyen hiç kimsenin deterministik / deterministik olmayan, değişken değişkenler veya belirli CPU'lardan şikayet ettiğini göreceksiniz.


    Geri alma / yineleme, kendileri temelde deterministik, olay odaklı ve durum ışığı olan uygulamalarda gerçekleşir (örneğin, bir kelime işlemci belgesinin durumu yalnızca yeniden hesaplanabilen tüm mizanpajın değil, yalnızca metin ve seçimdir).

    Öyleyse, CAD / CAM uygulamalarını, devre tasarım yazılımını, hareket izleme yazılımını ya da bir kelime işlemcisinden daha sofistike olan geri al / yineleme uygulamalarını kullanmadığınız açıktır. Geri alma kodunun bir oyunda tekrar oynatılmak üzere kopyalanabileceğini söylemiyorum, sadece kavramsal olarak aynı (durumları kaydedin ve daha sonra tekrarlayın). Bununla birlikte, ana veri yapısı bir sıra değil, bir yığındır.
    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.