Oyun mantığını animasyonlardan ve çizim döngülerinden ayırmanın bazı yolları nelerdir?


9

Animasyonlarımı oyun mantığımdan ayırmak için MovieClips ve benzerlerini kullanarak daha önce sadece flash oyunlar yaptım. Şimdi Android için bir oyun yapma konusunda elimi deniyorum, ancak bunları ayırmak hakkındaki oyun programlama teorisi hala beni karıştırıyor. Oyun dışı web uygulamaları geliştirmenin bir arka planından geliyorum, bu yüzden daha fazla MVC deseninde ustalaştım ve oyun programlamasına yaklaşırken bu zihniyete sıkıştım.

Her biri özellikler içeren bir karo sınıfının örneklerine sahip bir karo ızgarasına ilişkin verileri içeren bir oyun tahtası sınıfına sahip olarak oyunumun soyut olması gibi şeyler yapmak istiyorum. Beraberlik döngüme buna erişim verebilir ve oyun tahtasındaki her bir karonun özelliklerine göre oyun tahtasını çizmesini sağlayabilirim, ancak tam olarak animasyonun nereye gitmesi gerektiğini anlamıyorum. Anlayabildiğim kadarıyla, soyutlanmış oyun mantığı (model) ve beraberlik döngüsü (görünüm) arasında animasyon türünde oturur. MVC zihniyetimle animasyonun gerçekten nereye gitmesi gerektiğine karar vermek sinir bozucu. Bir model gibi onunla ilişkili biraz veri olurdu, ancak çerçeveden bağımsız animasyon gibi şeylere sahip olmak için görünüşte beraberlik döngüsüyle çok yakından ilişkili olması gerekiyor.

Bu zihniyetten nasıl çıkabilirim ve oyunlar için daha anlamlı olan kalıpları düşünmeye nasıl başlayabilirim?

Yanıtlar:


6

Animasyon hala mantık ve oluşturma arasında mükemmel şekilde bölünebilir. Animasyonun soyut veri durumu, grafik API'nızın animasyonu oluşturması için gerekli bilgilerdir.

Örneğin 2D oyunlarda, hareketli grafik sayfanızın çizilmesi gereken geçerli bölümünü görüntüleyen alanı işaretleyen bir dikdörtgen alan olabilir (karakterinizin çeşitli adımlarını içeren 30 80x80 çizimden oluşan bir sayfanız varsa atlama, oturma, hareket etme vb.). Ayrıca, oluşturma için ihtiyaç duymadığınız herhangi bir veri türü olabilir, ancak geçerli animasyon adımının süresinin bitmesine kadar kalan süre veya animasyonun adı ("yürüme", "ayakta" gibi animasyon durumlarını kendileri yönetmek için olabilir) vb.) Tüm bunlar istediğiniz şekilde temsil edilebilir. Bu mantık kısmı.

Oluşturma bölümünde, her zamanki gibi yapın, bu dikdörtgeni modelinizden alın ve grafik API'sine çağrı yapmak için oluşturucunuzu kullanın.

Kodda (burada C ++ sözdizimi kullanılarak):

class Sprite //Model
{
    private:
       Rectangle subrect;
       Vector2f position;
       //etc.

    public:
       Rectangle GetSubrect() 
       {
           return subrect;
       }
       //etc.
};

class AnimatedSprite : public Sprite, public Updatable //arbitrary interface for classes that need to change their state on a regular basis
{
    AnimationController animation_controller;
    //etc.
    public:
        void Update()
        {
            animation_controller.Update(); //Good OOP design ;) It will take control of changing animations in time etc. for you
            this.SetSubrect(animation_controller.GetCurrentAnimation().GetRect());
        }
        //etc.
};

Veriler bu. Oluşturucunuz bu verileri alır ve çizer. Hem normal Spritelar hem de animasyonlu olanlar aynı şekilde çizildiğinden, burada polimorfiyi kullanabilirsiniz!

class Renderer
{
    //etc.
    public:
       void Draw(const Sprite &spr)
       {
           graphics_api_pointer->Draw(spr.GetAllTheDataThatINeed());
       }
};

TMV:

Başka bir örnek buldum. Diyelim ki bir RPG'niz var. Örneğin, dünya haritasını temsil eden modelinizin muhtemelen karakterin dünyadaki konumunu harita üzerinde döşeme koordinatları olarak saklaması gerekecektir. Ancak, karakteri taşıdığınızda, bir sonraki kareye birkaç piksel yürürler. Bu "döşemeler arasında" konumunu bir animasyon nesnesinde saklıyor musunuz? Karakter sonunda haritadaki bir sonraki karo koordinatına "ulaştığında" nasıl güncellersiniz?

Dünya haritası oyuncuların konumunu doğrudan bilmiyor (Vector2f veya oyuncuların konumunu doğrudan saklayan buna benzer bir şey yok = bunun yerine oyuncu nesnesinin kendisine doğrudan bir referansı var, bu da AnimatedSprite'den geliyor böylece oluşturucuya kolayca iletebilir ve gerekli tüm verileri ondan alabilirsiniz.

Genel olarak, tilemap sadece her şeyi yapmak mümkün olmamalı - Ben tüm karoları yönetmek ilgilenen bir sınıf "TileMap" olurdu ve belki de ben teslim nesneleri arasında çarpışma algılama yapar ve harita üzerinde fayans. Daha sonra, başka bir "RPGMap" sınıfım olacaktı ya da onu aramak istersiniz, bu da hem tilemap'ınıza hem de oynatıcıya referansa sahiptir ve oynatıcınıza ve bilgisayarınıza gerçek Update () çağrılarını yapar. tilemap.

Oynatıcı hareket ettiğinde modeli nasıl güncellemek istediğiniz, ne yapmak istediğinize bağlıdır.

Oynatıcınızın karolar arasında bağımsız olarak hareket etmesine izin veriliyor mu (Zelda stili)? Sadece girişi tutun ve oynatıcıyı her kareye göre hareket ettirin. Yoksa oyuncunun "sağ" tuşuna basmasını ve karakterinizin otomatik olarak bir döşemeyi sağa hareket ettirmesini mi istiyorsunuz? RPGMap sınıfınızın, hedefine ulaşana kadar oyuncuların konumunu enterpole etmesine izin verin ve bu arada tüm hareket tuşu giriş işlemlerini kilitleyin.

Her iki durumda da, kendiniz için daha kolay hale getirmek istiyorsanız, tüm modelleriniz kendilerini güncellemek için gerçekten bir mantığa ihtiyaç duyuyorlarsa (sadece değişkenlerin değerlerini değiştirmek yerine) Update () yöntemlerine sahip olacaklar - Denetleyiciyi vermiyorsunuz MVC modelinde bu şekilde, kodu "yukarıdaki bir adım" dan (kontrolör) modele indirirsiniz ve tüm kontrolör modelin bu Update () yöntemini çağırır (Bizim durumumuzdaki kontrolör RPGMap). Mantık kodunu kolayca kolayca değiştirebilirsiniz - sadece sınıfın kodunu doğrudan değiştirebilirsiniz veya tamamen farklı bir davranışa ihtiyacınız varsa, sadece model sınıfınızdan türetebilir ve sadece Update () yöntemini geçersiz kılabilirsiniz.

Bu yaklaşım yöntem çağrılarını ve bunun gibi şeyleri çok azaltır - bu, saf MVC deseninin ana dezavantajlarından biri olmuştur (sonuç olarak GetThis () GetThat () çok sık çağrılır) - kodu hem daha uzun hem de küçük bir parça daha zor ve aynı zamanda daha yavaş - bunun gibi bir çok şeyi optimize eden derleyiciniz tarafından halledilmesine rağmen.


Animasyon verilerini oyun mantığını içeren sınıfta, oyun döngüsünü içeren sınıfta veya her ikisinden ayrı tutar mısınız? Ayrıca, animasyon verilerinin ekranı çizmeye nasıl dönüştürüleceğini anlamak tamamen döngüye veya döngüyü içeren sınıfa bağlıdır, değil mi? Genellikle, hareketli grafik sayfasının bir bölümünü temsil eden bir rekt elde etmek ve bunu hareketli grafik sayfasından bir bitmap çizimi kırpmak için kullanmak kadar basit olmazdı.
TMV

Başka bir örnek buldum. Diyelim ki bir RPG'niz var. Örneğin, dünya haritasını temsil eden modelinizin muhtemelen karakterin dünyadaki konumunu harita üzerinde döşeme koordinatları olarak saklaması gerekecektir. Ancak, karakteri taşıdığınızda, bir sonraki kareye birkaç piksel yürürler. Bu "döşemeler arasında" konumunu bir animasyon nesnesinde saklıyor musunuz? Karakter sonunda haritadaki bir sonraki karo koordinatına "ulaştığında" nasıl güncellersiniz?
TMV

Yorumlar bunun için yeterli karaktere izin vermediğinden, sorunuzun cevabında düzenledim.
TravisG

Her şeyi doğru
anlarsam

Görünümünüzün içinde bir "Animatör" sınıfının bir örneğine sahip olabilirsiniz ve görünümün her karesi olarak adlandırılan genel bir "güncelleme" yöntemine sahip olabilirsiniz. Güncelleme yöntemi, içinde çeşitli animasyon nesneleri türlerinin "güncelleme" yöntemlerini çağırır. Animatör ve içindeki animasyonlar, bir animasyonu değiştirirse model verilerini güncelleyebilmeleri için Model'e (yapıcılarından geçerek) bir referansa sahiptir. Ardından, çizim döngüsünde, animatör içindeki animasyonlardan Görünüm tarafından anlaşılabilecek ve çizilebilecek şekilde veri alırsınız.
TMV

2

İsterseniz bunu geliştirebilirim, ama döngüde çizilmesi söylenen merkezi bir oluşturucum var. Ziyade

handle input

for every entity:
    update entity

for every entity:
    draw entity

Daha çok benzeyen bir sistemim var

handle input (well, update the state. Mine is event driven so this is null)

for every entity:
    update entity //still got game logic here

renderer.draw();

Oluşturucu sınıfı, nesnelerin çekilebilir bileşenlerine bir referans listesi tutar. Bunlar basitlik için yapıcılara atanmıştır.

Örneğin, bir dizi Döşeme içeren bir GameBoard sınıfım olacaktı. Her kutucuk açık bir şekilde pozisyonunu biliyor ve bir tür animasyon olduğunu varsayıyorum. Karonun sahip olduğu bir tür Animasyon sınıfına giren ve kendisinin bir Renderer sınıfına referans vermesini sağlayan faktör. Orada, hepsi ayrıldı. Döşemeyi güncellediğinizde, animasyonda Güncelleme'yi çağırır .. veya kendisini günceller. Ne zaman Renderer.Draw()denir, bu animasyonu çizer.

Kare bağımsız animasyonun, çizim döngüsü ile çok fazla ilgisi olması gerekmez.


0

Son zamanlarda paradigmaları kendim öğreniyorum, bu yüzden eğer bu cevap eksikse, eminim birisi buna ekleyecektir.

Oyun tasarımı için en anlamlı yöntem, mantığı ekran çıktısından ayırmaktır.

Çoğu durumda, çok iş parçacıklı bir yaklaşım kullanmak istersiniz, bu konuyu bilmiyorsanız, bu tamamen kendi başına bir soru, burada wiki'nin astarı . Temel olarak oyun mantığınızın tek bir iş parçacığında yürütülmesini ve veri bütünlüğünü sağlamak için erişmesi gereken değişkenleri kilitlemesini istersiniz . Mantık döngünüz inanılmaz derecede hızlıysa (süper mega animasyonlu 3d pong?), İpliğin küçük süreler için uyuyarak döngünün yürüttüğü frekansı düzeltmeyi deneyebilirsiniz (bu forumda oyun fizik döngüleri için 120 hz önerilmiştir). Eşzamanlı olarak, diğer iş parçacığı ekranı güncellenen değişkenlerle yeniden çiziyor (diğer konularda 60 hz önerildi) ve yine değişkenlere erişmeden önce bir kilit istemektedir.

Bu durumda, animasyonlar veya geçişler, vb., Çizim iş parçacığına gider, ancak oyun mantığı iş parçacığının hiçbir şey yapmaması (veya farklı bir şey yapması gerekir) yeni harita parametreleri olabilir).

Kafanı eşzamanlılık etrafında bulduktan sonra, geri kalanı oldukça anlaşılabilir. Eşzamanlılık konusunda deneyiminiz yoksa, akışın nasıl gerçekleştiğini anlayabilmeniz için birkaç basit test programı yazmanızı şiddetle tavsiye ederim.

Bu yardımcı olur umarım :)

Çoklu düzenlemeyi desteklemeyen sistemlerde, animasyon yine de çizim döngüsüne girebilir, ancak durumu mantığa farklı bir şeyin oluştuğunu ve işleme devam etmediğini bildirecek şekilde ayarlamak istersiniz. mevcut seviye / harita / vs ...


1
Buraya katılmıyorum. Çoğu durumda, özellikle küçük bir oyunsa, çok iş parçacığı yapmak istemezsiniz.
Komünist Ördek

@TheCommunistDuck Fair, çoklu kullanım için ek yük ve karmaşıklık kesinlikle aşırıya kaçabilir, ayrıca oyun küçükse, hızlı bir şekilde güncelleyebilmelidir.
Stephen
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.