Oyun durumu yönetimi teknikleri?


24

Öncelikle, sahne yönetiminden bahsetmiyorum; Oyun durumunu, bir oyunda, kullanıcı girdisinin etkinleştirilip etkinleştirilmeyeceği veya belirli aktörlerin geçici olarak devre dışı bırakılması gerekip gerekmediği konusunda etkileri olan herhangi bir tür durum olarak tanımlamıyorum.

Somut bir örnek olarak, klasik Battlechess'in bir oyunu olduğunu varsayalım. Başka bir oyuncunun parçasını almak için harekete geçtikten sonra kısa bir savaş dizisi çalar. Bu sıralama sırasında oyuncunun parçaları hareket ettirmesine izin verilmemelidir. Peki bu tür devlet geçişini nasıl izlersiniz? Sonlu durumlu bir makine? Basit bir Boole çeki mi? İkincisi, ancak bu tür durum değişikliği çok az olan bir oyun için iyi çalışır gibi görünüyor.

Sonlu durumlu makineler kullanarak bununla başa çıkmanın birçok basit yolunu düşünebilirim, fakat aynı zamanda hızla elden çıktıklarını da görebiliyorum. Oyun durumlarını / geçişlerini takip etmenin daha zarif bir yolu olup olmadığını merak ediyorum.


Eğer kontrol ettiler gamedev.stackexchange.com/questions/1783/game-state-stack ve gamedev.stackexchange.com/questions/2423/... ? Her şey aynı konsept etrafında atlıyor, ancak oyun durumu için bir devlet makinesinden daha iyi bir şey düşünemiyorum.
michael.bartnett

Yanıtlar:


18

Bir keresinde probleminizi oldukça zarif bir şekilde çözen bir makaleye rastladım . Ana döngünüzde adı verilen temel bir FSM uygulamasıdır. Bu cevabın geri kalan kısmında makalenin özetini sıraladım.

Temel oyun durumunuz şöyle görünüyor:

class CGameState
{
    public:
        // Setup and destroy the state
        void Init();
        void Cleanup();

        // Used when temporarily transitioning to another state
        void Pause();
        void Resume();

        // The three important actions within a game loop
        void HandleEvents();
        void Update();
        void Draw();
};

Her oyun durumu, bu arayüzün bir uygulaması ile temsil edilmektedir. Battlechess örneğiniz için bu, şu durumlar anlamına gelebilir:

  • intro animasyonu
  • ana menü
  • satranç tahtası kurulum animasyonu
  • oyuncu taşıma girişi
  • oyuncu taşıma animasyonu
  • rakip hareket animasyonu
  • duraklatma menüsü
  • oyun sonu ekranı

Eyalet motorunda eyaletler yönetilir:

class CGameEngine
{
    public:
        // Creating and destroying the state machine
        void Init();
        void Cleanup();

        // Transit between states
        void ChangeState(CGameState* state);
        void PushState(CGameState* state);
        void PopState();

        // The three important actions within a game loop
        // (these will be handled by the top state in the stack)
        void HandleEvents();
        void Update();
        void Draw();

        // ...
};

Her bir durumun bir noktada CGameEngine için bir işaretçiye ihtiyacı olduğunu unutmayın; böylece yeni bir durumun girilip girilmeyeceğine karar verebilir. Makale, CGameEngine'de HandleEvents, Güncelleme ve Çizim için bir parametre olarak geçirilmesini önermektedir.

Sonunda, ana döngünüz yalnızca durum motoruyla ilgilidir:

int main ( int argc, char *argv[] )
{
    CGameEngine game;

    // initialize the engine
    game.Init( "Engine Test v1.0" );

    // load the intro
    game.ChangeState( CIntroState::Instance() );

    // main loop
    while ( game.Running() )
    {
        game.HandleEvents();
        game.Update();
        game.Draw();
    }

    // cleanup the engine
    game.Cleanup();
    return 0;
}

17
Sınıf için C? Ew. Ancak, bu iyi bir makale - +1.
Komünist Ördek

Toplayabildiğim kadarıyla, bu sorunun açıkça sorulmadığı bir şey. Bu, kesinlikle yapabileceğiniz gibi, bu şekilde başa çıkamayacağınız anlamına gelmez, ancak yapmak istediğiniz tek şey girişi geçici olarak devre dışı bırakmaktıysa, devam edecek yeni bir CGameState alt sınıfı türetmek için bakımın hem aşırı hem de kötü olduğunu düşünüyorum. başka bir alt sınıfa% 99 aynı olmalıdır.
Kylotan

Bunun, kodun nasıl birleştiğine bağlı olduğunu düşünüyorum. Bir parça ve bir varış yeri seçmek (özellikle UI göstergeleri ve giriş işleme) ile satranç taşının bu varış noktasına doğru bir animasyonu (diğer parçaların kendi yolundan çıktığı bir bütün tahta animasyonu, hareketli ile etkileşime girmesi arasında temiz bir ayrım olduğunu hayal edebiliyorum. parça vb), devletlerin özdeş olmaktan uzaklaşması. Bu, sorumluluğu ayırır, kolay bakım ve hatta tekrar kullanılabilirlik sağlar (tanıtım demo, tekrar modu). Bunun bir FSM kullanmanın güçlük olması gerekmediğini gösteren soruyu yanıtladığını da düşünüyorum.
hayalet

Bu gerçekten harika, teşekkür ederim. Yaptığın kilit nokta, son yorumunda oldu: "Bir FSM kullanmanın zor olması gerekmez." Yanlışlıkla bir FSM kullanmanın mutlaka doğru olmayan switch ifadelerini kullanmayı içerdiğini hayal etmiştim. Diğer bir önemli onay, her bir durumun oyun motoruna referans gerektirmesidir; Bunun nasıl işe yarayacağını merak ettim.
Vargon

2

Bu tür şeyleri mümkün olan en basit şekilde ele alarak başlıyorum.

bool isPieceMoving;

Sonra ilgili yerlerde bu Boolean bayrağına karşı çek ekleyeceğim.

Daha sonra bulursam bundan daha fazla özel davaya ihtiyacım olur - ve sadece o - daha iyi bir şeyi yeniden ele alırım. Genelde uygulayacağım 3 yaklaşım var:

  • Özel alt durum-temsil eden bayrakların enums olarak yeniden düzenlenmesi. Örneğin. enum { PRE_MOVE, MOVE, POST_MOVE }ve geçişleri gereken yere ekleyin. Daha sonra boolean bayrağını kontrol etmek için kullandığım bu enuma karşı kontrol edebilirim. Bu basit bir değişiklik ancak kontrol etmeniz gereken şey sayısını azaltan, davranışı etkin bir şekilde yönetmek için anahtar ifadeleri kullanmanızı sağlar.
  • İhtiyacınız olan bireysel alt sistemleri kapatın. Savaş sırasındaki tek fark, parçaları hareket ettirememeniz pieceSelectionManager->disable()ise, dizinin başlangıcında arayabilir veya benzerini yapabilirsiniz ve pieceSelectionManager->enable(). Hala temelde bayraklarınız var, ama şimdi kontrol ettikleri nesneye daha yakın bir yerde duruyorlar ve oyun kodunuzda fazladan bir durum belirtmenize gerek yok.
  • Önceki bölüm, bir PieceSelectionManager'ın varlığını ima eder: daha genel olarak, oyun durumunuzun bölümlerini ve davranışını, genel durumun bir alt kümesini tutarlı bir şekilde ele alan daha küçük nesnelere ayırabilirsiniz. Bu nesnelerin her biri, davranışını belirleyen kendi durumuna sahip olacak, ancak diğer nesnelerden izole edildiği için yönetimi kolaydır. Oyun alanı nesnesinin ya da ana döngünün sözde dünyalar için boşa giden bir zemin haline gelmesine ve ortaya çıkan etkenlere neden olma dürtüsüne karşı durma!

Genel olarak konuşursak, özel durumdaki sübvansiyonlar söz konusu olduğunda bundan daha ileri gitmem gerekmiyor, bu yüzden 'çabucak elden çıkma' riski olmadığını düşünüyorum.


1
Evet, devletlerle tamamen dışarı çıkmak ile sadece uygun olduğunda bir bool / enums kullanmak arasında bir çizgi olduğunu hayal ediyorum. Fakat bilgiçlik eğilimlerimi bildiğim için, neredeyse her devleti kendi sınıfı haline getirmeye başlayacağım.
vargonian

Alternatif gibi derslerden daha doğru bir sınıf gibi ses çıkarıyorsunuz ama bunun öznel olduğunu unutmayın. Diğer dil yapılarıyla daha kolay temsil edilebilecek şeyler için çok küçük sınıflar oluşturmaya başlarsanız, kodun amacını gizleyebilir.
Kylotan

1

http://www.ai-junkie.com/architecture/state_driven/tut_state1.html , oyun yönetimi için çok iyi bir eğitim! Oyun varlıkları için veya yukarıdaki gibi bir menü sistemi için kullanabilirsiniz.

Devlet Tasarım Örüntüsü hakkında öğretmeye başlar ve daha sonra bir uygulamaya geçmeye devam eder State Machineve ardışık olarak daha da genişletir. Çok güzel bir okuma! Tüm konseptin nasıl çalıştığını ve bunu yeni sorun türlerine nasıl uygulayacağınızı sağlam bir şekilde anlatacağım!


1

Devlet makinesi ve booleans'ı bu amaç için kullanmamaya çalışıyorum çünkü ikisi de ölçeklendirilemiyor. Devlet sayısı arttıkça her ikisi de karışır.

Ben genellikle oyunu bir dizi eylem ve sonuç olarak tasarlarım, herhangi bir oyun durumu doğal olarak ayrı ayrı tanımlanmasına gerek kalmadan ortaya çıkar.

Örneğin, oynatıcı girişini devre dışı bırakma durumunda: bazı kullanıcı girişi işleyiciniz ve bazı girişlerin devre dışı bırakıldığına dair görsel bir bilgi işleminiz var, bunları tek bir nesne veya bileşen yapmalısınız, böylece girişi devre dışı bırakmak için tüm nesneyi devre dışı bırakmanıza gerek kalmaz Bunları bir durum makinesinde senkronize edin veya bir miktar boole göstergesine tepki verin.

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.