Oyunlarda zaman ters mekanizması


10

Oyunlardaki zaman manipülasyon mekanizmalarının tipik olarak nasıl tasarlandığını merak ediyorum. Özellikle zaman tersine çevirme ile ilgileniyorum (en son SSX veya Pers Prensi gibi).

Oyun bir 2D yukarıdan aşağıya shooter.

Tasarlamaya / uygulamaya çalıştığım mekanizmanın aşağıdaki gereksinimleri var:

1) Oyuncu karakteri dışındaki objelerin hareketleri tamamen belirleyicidir.

  • Bir varlığın gerçekleştirdiği işlem, seviye başlangıcından bu yana kaydedilen karelere ve / veya oynatıcının ekrandaki konumuna dayanır.
  • Varlıklar seviye boyunca belirlenen zamanda üretilir.

2) Zaman tersi, gerçek zamanlı olarak geri dönerek çalışır.

  • Oyuncu eylemleri de tersine çevrilir, oyuncunun yaptıklarını tersine oynatır. Oyuncunun ters süre boyunca kontrolü yoktur.
  • Tersine çevirmek için harcanan zamanla ilgili bir sınır yoktur, istenirse seviyenin başlangıcına kadar tersine çevirebiliriz.

Örnek olarak:

Çerçeveler 0-50: Oyuncu bu süre zarfında 20 birim ilerler Düşman 1, çerçeve 20'de ortaya çıkar. Düşman 1, çerçeve 30-40 sırasında 10 birim sola hareket eder. Oyuncu, 45. çerçevede kurşun vurur. Mermi, 5 ileri (45-50) gider ve Düşman 1'i çerçeve 50

Bunu tersine çevirmek gerçek zamanlı olarak tekrar oynayacaktır: Oyuncu bu süre zarfında 20 birim geriye doğru hareket eder. Düşman 1, 50 numaralı karede yeniden canlandırır 50. karede yeniden kurşun Mermi 5 geriye doğru kaybolur ve (50-45) Düşman sola hareket eder 10 (40-30) çerçeve 20.

Harekete baktığımda bunu nasıl başaracağım konusunda bazı fikirlerim vardı, zaman ilerledikçe veya tersine döndüğünde davranışını değiştiren bir arayüze sahip olmayı düşündüm. Bunun gibi bir şey yapmak yerine:

void update()
{
    movement += new Vector(0,5);
}

Böyle bir şey yapardım:

public interface movement()
{
    public void move(Vector v, Entity e);
}

public class advance() implements movement
{
    public void move(Vector v, Entity e)
    {
            e.location += v;
    }
}


public class reverse() implements movement
{
    public void move(Vector v, Entity e)
    { 
        e.location -= v;
    }
}

public void update()
{
    moveLogic.move(new vector(5,0));
}

Bununla birlikte, bunun en iyi performans açısından akıllıca olmayacağını ve daha ileri eylemler için (kavisli yollar boyunca yumuşak hareket gibi) hızla karmaşık hale geleceğini fark ettim.


1
Tüm bunları izlemedim (YouTube titrek kamera, 1.5 saat) , ancak belki Jonathan Blow'ın Braid oyununda bu konuda çalıştığı hakkında bazı fikirler var.
MichaelHouse

Yanıtlar:


9

Komut desenine bir göz atmak isteyebilirsiniz .

Temel olarak, varlıklarınızın gerçekleştirdiği her tersinir işlem bir komut nesnesi olarak uygulanır. Bu nesnelerin tümü en az 2 yöntem uygular: Doğru zamanlama için bir zaman damgası özelliği gibi, Execute () ve Undo () ve ihtiyacınız olan her şey.

Varlığınız geri döndürülebilir bir eylem gerçekleştirdiğinde, önce uygun bir komut nesnesi oluşturursunuz. Bir Geri Al yığınına kaydedin, ardından oyun motorunuza besleyin ve çalıştırın. Zamanı ters çevirmek istediğinizde, yığının en üstünden eylemler açar ve Execute () yönteminin tersini yapan Undo () yöntemini çağırırsınız. Örneğin, A noktasından B noktasına bir sıçrama durumunda, B'den A'ya bir atlama gerçekleştirirsiniz.

Bir eylemi başlattıktan sonra, tıpkı bir metin düzenleyicisindeki veya boyama programındaki geri alma / yineleme işlevi gibi, istediğiniz zaman ileri ve geri gitmek istiyorsanız, işlemi bir Yeniden Yap yığınına kaydedin. Tabii ki, animasyonlarınız geriye doğru oynatmak için "geri sarma" modunu da desteklemelidir.

Daha fazla oyun tasarımı parlaklığı için, her varlığın eylemlerini kendi yığını üzerinde saklamasına izin verin, böylece bunları birbirinden bağımsız olarak geri alabilir / yeniden yapabilirsiniz.

Bir komut paterninin başka avantajları da vardır: Örneğin, yeniden kayıt cihazı oluşturmak oldukça önemlidir, çünkü yığınlardaki tüm nesneleri bir dosyaya kaydetmeniz gerekir ve tekrar oynatıldığında, onu oyun motoruna tek tek besleyin bir.


2
Bir oyundaki eylemlerin tersine çevrilebilirliğinin, kayan nokta hassasiyeti sorunları, değişken zaman adımları vb.Nedeniyle çok dokunaklı bir şey olabileceğini unutmayın; bu durumu kurtarmak çoğu durumda yeniden inşa etmekten çok daha güvenlidir.
Steven Stadnicki

@StevenStadnicki Belki, ama kesinlikle mümkün. Başımın üstünden, C&C Generals bunu böyle yapıyor. En fazla 8 yüz kB ağırlığında, 8 oyuncuya kadar saatlerce oynatma süresine sahiptir ve tüm RTS oyunları çok oyunculu değilse, çoğu oyunun tamamını potansiyel olarak yüzlerce iletemezsiniz. Her karede birimler varsa, motorun güncellemeyi yapmasına izin vermelisiniz. Yani evet, kesinlikle uygulanabilir.
Hackworth

3
Tekrarlama, geri sarmadan çok farklı bir şeydir, çünkü sürekli olarak ileriye doğru tekrarlanabilir işlemler (örneğin, x, 0 = 0 ile başlayıp her adım için v_n deltalarını ekleyerek n, x_n karesinde konumu bulma) mutlaka geri çoğaltılamaz ; (x + v_n) -v_n, kayan nokta matematiğinde sürekli olarak x değerine eşit değildir. Ve 'etrafında çalışın' demek kolaydır, ancak birçok harici kütüphaneyi kullanmamak da dahil olmak üzere potansiyel olarak tam bir revizyondan bahsediyorsunuz.
Steven Stadnicki

1
Bazı oyunlar için yaklaşımınız mümkün olabilir, ama bir tamirci gibi zaman ters kullanmak AFAIK en oyunlar daha yakın ilgili devlet OriginalDaemon en Memento yaklaşımına şey kullanıyor olan her kare için kurtardı.
Steven Stadnicki

2
Adımları yeniden hesaplayarak ancak her birkaç saniyede bir anahtar kareyi kaydederek geri sarmaya ne dersiniz? Kayan nokta hatalarının sadece birkaç saniye içinde önemli bir fark yaratması olası değildir (elbette karmaşıklığa bağlı olarak). Ayrıca video sıkıştırmada da çalışıyor: P
Tharwen

1

Memento Paternine bir göz atabilirsiniz; birincil amacı nesne durumunu geri alarak geri alma / yineleme işlemlerini uygulamaktır, ancak bazı oyun türleri için yeterli olmalıdır.

Gerçek zamanlı bir döngüdeki bir oyun için, işlemlerinizin her karesini bir durum değişikliği olarak değerlendirebilir ve saklayabilirsiniz. Bu, uygulanması basit bir yaklaşımdır. Alternatif, bir nesnenin durumu değiştiğinde bindirmektir. Örneğin, rijit bir cisme etkiyen kuvvetlerin ne zaman değiştiğinin tespiti. Değişkenleri almak ve ayarlamak için özellikler kullanıyorsanız, bu nispeten düz bir ileri uygulama da olabilir, zor kısım durumu ne zaman geri alacağınızı tanımlamaktır, çünkü bu her nesne için aynı zaman olmayacaktır ( sistemin başlangıcından itibaren kare sayısı olarak geri alma süresi).


0

Özel durumunuzda, hareketi geri sararak geri alma işleminin iyi çalışması gerekir. AI birimleriyle herhangi bir yol bulma yöntemi kullanıyorsanız, çakışan birimleri önlemek için geri alma işleminden sonra yeniden hesapladığınızdan emin olun.

Sorun, hareketi kendiniz ele alma şeklinizdir: Geçmiş adımların (konum, net kuvvet vb. Dahil) bilgilerini takip eden iyi bir fizik motoru (2D yukarıdan aşağıya doğru atıcı çok basit bir şekilde iyi olacaktır) katı bir baz. Ardından, bir geri alma ve geri alma adımları için bir ayrıntı düzeyi belirleyerek istediğiniz sonucu elde etmelisiniz.


0

Bu ilginç bir fikir olsa da. Ben buna karşı tavsiye ediyorum.

Oyunu ileriye doğru tekrarlamak iyi çalışır, çünkü bir işlem oyun durumu üzerinde her zaman aynı etkiye sahip olacaktır. Bu, ters işlemin size orijinal durumu verdiği anlamına gelmez. Örneğin, herhangi bir programlama dilinde aşağıdaki ifadeyi değerlendirin (optimizasyonu kapatın)

(1.1 + 3 - 3) == 1.1

En azından C ve C ++ 'da false değerini döndürür. Fark küçük olsa da, 10 saniyede 60fps'de ne kadar hata birikebileceğini hayal edin. Bir oyuncunun sadece bir şeyi kaçırdığı, ancak oyun geriye doğru oynatılırken vurduğu durumlar olacaktır.

Anahtar kareleri her yarım saniyede bir saklamanızı tavsiye ederim. Bu çok fazla bellek kaplamaz. Daha sonra anahtar kareler arasında enterpolasyon yapabilir veya daha da iyisi, iki anahtar kare arasındaki süreyi simüle edebilir ve sonra geri oynatabilirsiniz.

Oyununuz çok karmaşık değilse, oyun durumunun ana karelerini saniyede 30 kez saklayın ve bunu geriye doğru oynatın. Her biri 2B konuma sahip 15 nesneniz varsa, MB olmadan sıkıştırılmadan 1,5 dakikaya kadar iyi bir süre geçmesi gerekir. Bilgisayarların gigabayt belleği vardır.

Bu yüzden aşırı karmaşık olmayın, bir oyunu geri oynatmak kolay olmayacak ve birçok hataya neden olacaktı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.