खेल राज्य प्रबंधन तकनीक?


24

सबसे पहले, मैं दृश्य प्रबंधन की बात नहीं कर रहा हूँ; मैं गेम स्टेट को शिथिल रूप से परिभाषित कर रहा हूं क्योंकि किसी गेम में किसी भी तरह का स्टेट है, जिसके बारे में निहितार्थ हैं कि उपयोगकर्ता इनपुट सक्षम होना चाहिए या नहीं, या कुछ एक्टर्स अस्थायी रूप से अक्षम होने चाहिए, आदि।

एक ठोस उदाहरण के रूप में, मान लीजिए कि यह क्लासिक बैटलचेज़ का खेल है। जब मैं किसी अन्य खिलाड़ी के टुकड़े को लेने के लिए कदम बढ़ाता हूं, तो एक छोटा युद्ध क्रम चलता है। इस क्रम के दौरान, खिलाड़ी को टुकड़ों को स्थानांतरित करने की अनुमति नहीं दी जानी चाहिए। तो आप इस प्रकार के राज्य संक्रमण को कैसे ट्रैक करेंगे? एक परिमित राज्य मशीन? एक साधारण बूलियन जांच? ऐसा लगता है कि उत्तरार्द्ध केवल इस तरह के बहुत कम राज्य परिवर्तनों के साथ एक खेल के लिए अच्छी तरह से काम करेगा।

मैं परिमित राज्य मशीनों का उपयोग करके इसे संभालने के बहुत से सरल तरीकों के बारे में सोच सकता हूं, लेकिन मैं उन्हें जल्दी से हाथ से निकलते हुए भी देख सकता हूं। मैं उत्सुक हूँ अगर खेल राज्यों / संक्रमण का ट्रैक रखने के लिए एक और अधिक सुंदर तरीका है।


क्या आपने gamedev.stackexchange.com/questions/1783/game-state-stack और gamedev.stackexchange.com/questions/2423/ ... चेक किया है ? यह सभी एक ही अवधारणा के आसपास कूद रहा है, लेकिन मैं कुछ भी नहीं सोच सकता जो खेल राज्य के लिए एक राज्य मशीन से बेहतर होगा।
michael.bartnett

संभावित डुप्लिकेट: gamedev.stackexchange.com/questions/12664/…
Tetrad

जवाबों:


18

मैं एक बार एक लेख में आया था, जो आपकी समस्या को काफी शान से हल करता है। यह एक मूल FSM कार्यान्वयन है, जिसे आपके मुख्य लूप में कहा जाता है। मैंने इस उत्तर के बाकी हिस्सों में लेख के मूल आधार को रेखांकित किया है।

आपका मूल खेल राज्य इस तरह दिखता है:

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

प्रत्येक खेल राज्य को इस इंटरफ़ेस के कार्यान्वयन द्वारा दर्शाया जाता है। आपके युद्ध के उदाहरण के लिए, इसका मतलब ये हो सकता है:

  • परिचय एनीमेशन
  • मुख्य मेनू
  • शतरंज बोर्ड सेटअप एनीमेशन
  • खिलाड़ी चाल इनपुट
  • खिलाड़ी चाल एनीमेशन
  • प्रतिद्वंद्वी चाल एनीमेशन
  • ठहराव मेनू
  • एंडगेम स्क्रीन

राज्य आपके राज्य इंजन में प्रबंधित होते हैं:

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();

        // ...
};

ध्यान दें कि प्रत्येक राज्य को किसी बिंदु पर CGameEngine के लिए एक संकेतक की आवश्यकता होती है, इसलिए राज्य खुद तय कर सकता है कि एक नया राज्य दर्ज किया जाना चाहिए या नहीं। लेख का सुझाव है कि CGEEngine में हैंडल, अपडेट और ड्रा के पैरामीटर के रूप में पास किया जाए।

अंत में, आपका मुख्य लूप केवल राज्य इंजन से संबंधित है:

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
सी क्लास के लिए? Ew। हालाँकि, यह एक अच्छा लेख है - +1।
कम्युनिस्ट डक

मैं जो इकट्ठा कर सकता हूं, वह इस प्रकार का है कि प्रश्न स्पष्ट रूप से-के बारे में पूछ रहा है। यह कहने के लिए नहीं है कि आप इसे इस तरह से नहीं संभाल सकते हैं, जैसा कि आप निश्चित रूप से कर सकते हैं, लेकिन अगर आप सभी करना चाहते थे तो अस्थायी रूप से इनपुट को निष्क्रिय कर दिया गया था, मुझे लगता है कि यह रखरखाव के लिए सीकेमस्टेट के एक नए उपवर्ग को प्राप्त करने के लिए ओवरकिल और खराब दोनों है। एक और उपवर्ग के समान 99% हो।
काइलोटन

मुझे लगता है कि यह बहुत कुछ इस बात पर निर्भर करता है कि कोड एक साथ कैसे जोड़ा जाता है। मैं एक टुकड़ा और एक गंतव्य (मुख्य रूप से यूआई संकेतक और इनपुट से निपटने) का चयन करने के बीच एक साफ जुदाई की कल्पना कर सकता हूं, और उस गंतव्य की ओर शतरंज के टुकड़े का एक एनीमेशन (एक पूरा बोर्ड एनीमेशन जहां अन्य टुकड़े अपने रास्ते से हटते हैं, चलती के साथ बातचीत करते हैं टुकड़ा आदि), राज्यों को समान से दूर बनाते हैं। यह जिम्मेदारी को अलग करता है, आसान रखरखाव और यहां तक ​​कि पुन: प्रयोज्य (इंट्रो डेमो, रीप्ले मोड) के लिए अनुमति देता है। मुझे लगता है कि यह यह दिखाने में भी सवाल का जवाब देता है कि एफएसएम का उपयोग करने के लिए परेशानी की आवश्यकता नहीं है।
भूत

यह वास्तव में बहुत अच्छा है, धन्यवाद। आपके द्वारा बनाया गया एक महत्वपूर्ण बिंदु आपकी नवीनतम टिप्पणी में था: "FSM का उपयोग करने के लिए परेशानी की आवश्यकता नहीं है।" मैंने गलत तरीके से कल्पना की थी कि एफएसएम का उपयोग स्विच स्टेटमेंट का उपयोग करना होगा, जो जरूरी नहीं कि सच है। एक अन्य प्रमुख पुष्टि यह है कि प्रत्येक राज्य को खेल इंजन के संदर्भ की आवश्यकता है; मैंने सोचा कि यह कैसे काम करेगा।
वार्गोनियन

2

मैं इस तरह की चीज को सबसे सरल तरीके से संभालना शुरू करता हूं।

bool isPieceMoving;

फिर मैं संबंधित स्थानों पर उस बूलियन ध्वज के खिलाफ जांच जोड़ूंगा।

अगर मुझे बाद में पता चलता है कि मुझे इससे अधिक विशेष मामलों की आवश्यकता है - और केवल यह - मैं कुछ बेहतर में फिर से कारक। आमतौर पर 3 दृष्टिकोण हैं जिन्हें मैं ले जाऊंगा:

  • किसी विशेष विशेष-निरूपण झंडे को Enums में रिफलेक्टर करें। जैसे।enum { PRE_MOVE, MOVE, POST_MOVE }और जहां भी जरूरत हो वहां संक्रमण जोड़ें। तब मैं इस दुश्मनी के खिलाफ जाँच कर सकता हूँ जहाँ मैं बूलियन झंडे के खिलाफ जाँच करता था। यह एक साधारण परिवर्तन है, लेकिन एक ऐसी चीज है जो आपके खिलाफ जांचने के लिए चीजों की संख्या को कम कर देती है, जिससे आप व्यवहार को प्रभावी ढंग से प्रबंधित करने के लिए स्विच स्टेटमेंट का उपयोग कर सकते हैं, आदि।
  • अलग-अलग उपप्रणालियों को स्विच करें जैसा आपको आवश्यक है। अगर लड़ाई के अनुक्रम के दौरान एकमात्र अंतर यह है कि आप टुकड़ों को स्थानांतरित नहीं कर सकते हैं, तो आप pieceSelectionManager->disable()अनुक्रम की शुरुआत में कॉल या समान कर सकते हैं , औरpieceSelectionManager->enable() । आपके पास अभी भी अनिवार्य रूप से झंडे हैं, लेकिन अब वे उस वस्तु के करीब जमा हो गए हैं जिसे वे नियंत्रित करते हैं, और आपको अपने गेम कोड में किसी भी अतिरिक्त स्थिति को बनाए रखने की आवश्यकता नहीं है।
  • पिछले भाग का तात्पर्य है एक पीससेलेमेंजर का अस्तित्व: अधिक सामान्यतः, आप अपने खेल राज्य के कुछ हिस्सों और व्यवहार को छोटी वस्तुओं में बदल सकते हैं जो एक सुसंगत तरीके से समग्र राज्य के सबसेट को संभालते हैं। इन वस्तुओं में से प्रत्येक की अपनी कुछ अवस्था होगी जो इसके व्यवहार को निर्धारित करती है लेकिन इसे प्रबंधित करना आसान है क्योंकि यह अन्य वस्तुओं से अलग है। अपने गेमस्टेट ऑब्जेक्ट या मुख्य लूप को छद्म ग्लोबल्स और फैक्टर आउट के लिए डंपिंग ग्राउंड बनने की अनुमति देने का आग्रह करें!

आम तौर पर बोलते हुए मुझे कभी भी इससे आगे जाने की आवश्यकता नहीं होती है जब यह विशेष-मामले के विकल्प के रूप में आता है, इसलिए मुझे नहीं लगता कि इसका कोई जोखिम है 'जल्दी से हाथ से निकल जाना'।


1
हां, मुझे लगता है कि राज्यों के साथ बाहर जाने और उचित होने पर बस एक बूल / एनम का उपयोग करने के बीच एक रेखा है। लेकिन मेरी पांडित्य की प्रवृत्ति को जानकर, मैं शायद लगभग हर राज्य को अपना वर्ग बनाने की कोशिश कर रहा हूं।
वार्गोनियन

आप इसे ध्वनि की तरह लगाते हैं कि एक वर्ग विकल्पों की तुलना में अधिक सही है, लेकिन याद रखें कि यह व्यक्तिपरक है। यदि आप उन चीजों के लिए बहुत छोटी कक्षाएं बनाना शुरू करते हैं जिन्हें अन्य भाषा निर्माणों द्वारा अधिक आसानी से दर्शाया जा सकता है तो यह कोड के इरादे को अस्पष्ट कर सकता है।
काइलोटन

1

http://www.ai-junkie.com/architecture/state_driven/tut_state1.html गेम प्रबंधन के लिए एक प्यारा ट्यूटोरियल है! आप इसे खेल संस्थाओं के लिए या ऊपर की तरह मेनू सिस्टम के लिए उपयोग कर सकते हैं।

वह राज्य डिजाइन पैटर्न के बारे में पढ़ाना शुरू करता है , और फिर एक को लागू करने के लिए State Machineआगे बढ़ता है, और क्रमिक रूप से इसे और आगे बढ़ाता है। बहुत अच्छा पढ़ा है! आपको एक ठोस समझ देगा कि पूरी अवधारणा कैसे काम करती है और इसे नए प्रकार की समस्याओं पर कैसे लागू किया जाता है!


1

मैं इस उद्देश्य के लिए राज्य मशीन और बूलियन का उपयोग नहीं करने की कोशिश करता हूं, क्योंकि दोनों स्केलेबल नहीं हैं। राज्यों की संख्या बढ़ने पर दोनों गड़बड़ हो जाते हैं।

मैं आमतौर पर गेमप्ले को कार्यों और परिणामों के अनुक्रम के रूप में डिज़ाइन करता हूं, किसी भी खेल राज्य को स्वाभाविक रूप से इसे अलग से परिभाषित करने की आवश्यकता के बिना आता है।

उदाहरण के लिए खिलाड़ी इनपुट को अक्षम करने के साथ आपके मामले में: आपके पास कुछ उपयोगकर्ता इनपुट हैंडलर और कुछ ingame दृश्य संकेत है कि इनपुट अक्षम है, आपको उन्हें एक ऑब्जेक्ट या घटक बनाना चाहिए, इसलिए इनपुट को अक्षम करने के लिए आपको बस पूरी ऑब्जेक्ट को अक्षम करना होगा, कोई ज़रूरत नहीं है उन्हें कुछ राज्य मशीन में सिंक्रनाइज़ करें या कुछ बूलियन संकेतक पर प्रतिक्रिया करें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.