खेल राज्य प्रबंधन (खेल, मेनू, टाइटलस्क्रीन, आदि)


11

मूल रूप से, मैंने अब तक किए गए हर एक खेल में, मेरे पास हमेशा "current_state" जैसा एक चर है, जो "गेम", "टाइटलस्क्रीन", "गेमस्क्रीन", आदि हो सकता है।

और फिर मेरे अपडेट फ़ंक्शन पर मेरे पास बहुत बड़ा है:

if current_state == "game" 
  game stuf
  ...
else if current_state == "titlescreen"
  ...

हालाँकि, मुझे ऐसा नहीं लगता कि यह राज्यों को संभालने का एक पेशेवर / स्वच्छ तरीका है। यह कैसे बेहतर तरीके से करने के लिए कोई विचार? या यह मानक तरीका है?


आप किस भाषा, रूपरेखा, आदि का उपयोग कर रहे हैं?
पेट्र अब्दुलिन

आमतौर पर लुआ + लव। मुझे यह भी पता चला कि विभिन्न रूपरेखाओं के पास इसे संभालने के विभिन्न तरीके हैं। लगता है SFML एक बहुत अच्छा स्क्रीन वर्ग है।
डेविड गोम्स

1
क्या आपने राज्य मशीनों में देखा है?
दरकरा

1
आप ऊपरी दाईं ओर खोज बार में गेमस्टेट्स भी देख सकते हैं। कुछ परिणाम देना चाहिए।
ट्रैविसग

दूसरा दरकार होना चाहिए - यह वही है जो राज्य मशीनों के लिए उपयोग किया जाता है।
बालजेकर

जवाबों:


14

चूंकि आप स्क्रीन के बारे में बात कर रहे हैं, इसलिए मुझे लगता है कि उस तर्क को अलग-अलग स्क्रीन में अलग करना सबसे अच्छा है। मैं सामान्य रूप से क्या करता हूं:

स्क्रीन नामक एक इंटरफेस को परिभाषित करें, और इसे लागू करने के लिए कई स्क्रीन हैं। जैसे LoadingScreen, MainMenuScreen, GameScreen, GameOverScreen, HighScoreScreen आदि। अपने खेल में आप एक वैरिएबल रखते हैं जो कि वर्तमान स्क्रीन को धारण करता है। प्रत्येक लूप, आप screen.update () कहते हैं और वर्तमान स्क्रीन को प्रस्तुत करते हैं। यह आपको बहुत सारे "यदि यह राज्य करता है" तो आपके राज्य को वर्तमान स्क्रीन द्वारा परिभाषित किया गया है।

यह आपके तर्क को बहुत अच्छी तरह से अलग कर देगा।

उदाहरण कोड:

### Screen interface ###
public interface Screen {

    public void show();

    public void update(float delta);

    public void render(float delta);

    public void hide ();
}

### An implementation of screen ###
public class MainMenuScreen implements Screen {

    private Game game;

    public MainMenuScreen(Game game) {
        this.game = game;
    }

    public void show() {
        // init stuff
    }

    public void update(float delta) {
        // react to clicks, update animations etc.
        if (buttonwasclicked) {
            game.setScreen(new GameScreen(game)); // change the screen
        }
    }

    public void render(float delta) {
        // draw everything
    }

    public void hide() {
        // release all resources, as the screen is being hidden
    }
}

### Game, drawing the appropriate screen ###
public class Game {

    public Screen screen;

    public void update() {
        screen.update(getDeltaTime);
        screen.render();
    }

    public void setScreen(Screen screen) {
        this.screen.hide();

        this.screen = screen;
        this.screen.show();
    }
}

या आपके गेम सेटअप के आधार पर, आपके गेम के रूप में आपके पास अनंत लूप हो सकता है।

while(true) {
    calculatetimesincelastframe()
    screen.update(time);
    screen.render(time);
}

5

यदि आप पहले से ही मिडिलक्लास का उपयोग कर रहे हैं, तो स्टेटफुल नामक इसके साथ जाने के लिए एक उत्कृष्ट राज्य-मशीन पुस्तकालय है । मात्सेमन्न ने जिन विचारों को प्रस्तावित किया था, उन्हीं विचारों का उपयोग करना और उसकी पुष्टि करना आसान है।


2

यदि आपका current_stateचर एक स्ट्रिंग है, तो यह वास्तव में Lua में आसान है:

game_states = {}
function game_states.game()
    -- game stuff
end
function game_states.titlescreen()
    -- title screen stuff
end

-- then, inside the Update function:
game_states[current_state]()

1

मैं जो कुछ करता हूं वह इस प्रकार है:

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

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


यह उत्तर एक अलग प्रश्न का एक अच्छा उत्तर है ।
मात्सेमन्न

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

1

यहाँ मैं अपने राज्यों को Lua + Love2d में कैसे व्यवस्थित करूँ। यह लंबे समय तक बचता है अगर / फिर बयान करता है।

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

states = {}
states["title"] = title   -- Where title implements Stage class.
states["game"] = game     -- You could create the instance of 'game' lazily too.
currentState = "title"

function love.update(dt)
    if states[currentState] ~= nil then
       states[currentState]:update(dt) 
    end
end

-1

खैर, हालांकि यह सुंदर नहीं है, इस तरह से आईएमओ को संभालना ठीक है। आप प्रत्येक राज्य के कार्यों का उपयोग करके इसे बहुत अधिक स्वच्छ बना सकते हैं, जैसे:

if current_state == "game" 
  game()
else if current_state == "titlescreen"
  titlescreen()

या इस दृष्टिकोण में कुछ और आपको परेशान करता है (मेरा मतलब है कि अपडेट विधि को छोड़कर बहुत लंबा है)?

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