बड़े खेलों में इनपुट प्रबंधन तकनीक


16

क्या बड़े खेलों में इनपुट के प्रबंधन के लिए एक मानक तकनीक है। वर्तमान में, मेरी परियोजना में, सभी इनपुट हैंडलिंग गेम लूप में किया जाता है, जैसे:

while(SDL_PollEvent(&event)){
            switch(event.type){
                case SDL_QUIT:
                    exit = 1;
                    break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym){
                        case SDLK_c:
                            //do stuff
                            break;
                    }
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    switch(event.button.button){
                        case SDL_BUTTON_MIDDLE:
                                //do stuff
                                break;
                            }
                    }
                    break;
            }

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


एक इवेंट मैनेजर के साथ, आप इनपुट में आग लगा सकते हैं और अपने गेम के अन्य सभी हिस्सों को उनके पास रजिस्टर कर सकते हैं।
दानीझार २२'१३ को ११:११

@danijar क्या आप वास्तव में एक घटना प्रबंधक से क्या मतलब है, क्या यह संभव है कि आप कुछ कंकाल छद्म कोड प्रदान कर सकें यह दिखाने के लिए कि आप किस तरह की बात कर रहे हैं?
w4etwetewtwet


1
मैंने इवेंट मैनेजरों के बारे में विस्तार से उत्तर लिखा, जो मेरे लिए इनपुट से निपटने का तरीका है।
danijar

जवाबों:


12

थ्रेड स्टार्टर द्वारा पूछे जाने के बाद, मैं इवेंट मैनेजरों के बारे में विस्तार से बताता हूं। मुझे लगता है कि यह एक गेम में इनपुट को संभालने का एक अच्छा तरीका है।

एक इवेंट मैनेजर एक वैश्विक वर्ग है जो कॉलबैक फ़ंक्शन को कुंजियों में रजिस्टर करने और उन कॉलबैक को बंद करने की अनुमति देता है। इवेंट मैनेजर ने अपनी कुंजी द्वारा समूहीकृत एक निजी सूची में पंजीकृत कार्यों को संग्रहीत किया। जब भी कोई कुंजी निकाल दी जाती है, सभी पंजीकृत कॉलबैक निष्पादित हो जाते हैं।

कॉलबैक std::functionऑब्जेक्ट्स हो सकते हैं जो लैम्ब्डा पकड़ सकते हैं। कुंजी तार हो सकता है। चूंकि प्रबंधक वैश्विक है, इसलिए आपके एप्लिकेशन के घटक अन्य घटकों से निकाल दी गई कुंजियों पर पंजीकरण कर सकते हैं।

// in character controller
// at initialization time
Events->Register("Jump", [=]{
    // perform the movement
});

// in input controller
// inside the game loop
// note that I took the code structure from the question
case SDL_KEYDOWN:
    switch(event.key.keysym.sym) {
    case SDLK_c:
        Events->Fire("Jump");
        break;
    }
    break;

आप अतिरिक्त ईवेंट के रूप में पासिंग मानों को अनुमति देने के लिए इस ईवेंट मैनेजर का विस्तार भी कर सकते हैं। C ++ टेम्प्लेट इसके लिए बहुत अच्छे हैं। आप इस तरह की प्रणाली का उपयोग, कह सकते हैं, के लिए कर सकते हैं"WindowResize" घटना के लिए नई विंडो आकार पास करें, ताकि सुनने वाले घटकों को इसे स्वयं लाने की आवश्यकता न हो। यह कोड निर्भरता को काफी कम कर सकता है।

Events->Register<int>("LevelUp", [=](int NewLevel){ ... });

मैंने अपने खेल के लिए इस तरह की एक घटना को लागू किया है। यदि आप रुचि रखते हैं, तो मैं यहां कोड का लिंक पोस्ट करूंगा।

एक इवेंट मैनेजर का उपयोग करके, आप आसानी से अपने आवेदन के भीतर इनपुट जानकारी प्रसारित कर सकते हैं। इसके अलावा, यह उपयोगकर्ता को प्रमुख बाइंडिंग को अनुकूलित करने के लिए एक अच्छा तरीका देता है। घटक सीधे कुंजियों के बजाय सिमेंटिक घटनाओं को सुनते हैं ( "PlayerJump"बजाय "KeyPressedSpace")। फिर आपके पास एक इनपुट मैपिंग घटक हो सकता "KeyPressedSpace"है जो उस कुंजी के लिए बाध्य उपयोगकर्ता के लिए सुनता है और ट्रिगर करता है।


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

मैंने अभी कुछ सोचा है, क्या मैं इस तरह से किसी भी सदस्य फ़ंक्शन को पास कर सकता हूं, या रजिस्टर फ़ंक्शन को AClass नहीं लेना होगा :: func, इसे एक वर्ग के सदस्य कार्यों तक सीमित करना
w4etwetewtwet

C ++ में लैम्ब्डा एक्सप्रेशन के बारे में यह बहुत अच्छी बात है, आप एक कैप्चर क्लॉज़ को निर्दिष्ट कर सकते हैं [=]और लैम्ब्डा से एक्सेस किए गए सभी स्थानीय वेरिएबल्स के संदर्भों को कॉपी किया जाएगा। तो आप इस सूचक या इस तरह से कुछ पारित करने की जरूरत नहीं है। लेकिन ध्यान दें कि आप पुराने सी फंक्शन पॉइंट्स में कैप्चर क्लॉज के साथ लैम्ब्डा स्टोर नहीं कर सकते हैं । हालाँकि, C ++ std::functionठीक काम करता है।
डनिजर

std :: फ़ंक्शन बहुत धीमा है
TheStatehz

22

इसे कई परतों में विभाजित करें।

सबसे निचली परत पर आपके पास OS से कच्चे इनपुट ईवेंट हैं। SDL कीबोर्ड इनपुट, माउस इनपुट, जॉयस्टिक इनपुट, आदि आपके पास कई प्लेटफ़ॉर्म हो सकते हैं (उदाहरण के लिए SDL कम से कम सामान्य-भाजक है, जिसमें कई इनपुट फॉर्म होते हैं, जिन्हें आप बाद में देख सकते हैं)।

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

इनपुट सिस्टम में अब निम्न-स्तरीय इनपुट को उच्च-स्तरीय तार्किक घटनाओं में बदलने का काम है। खेल तर्क बिल्कुल ध्यान नहीं देता है कि SPACE दबाया गया था। यह परवाह करता है कि JUMP को दबाया गया था। इनपुट प्रबंधक का काम इन निम्न-स्तरीय इनपुट घटनाओं को इकट्ठा करना और उच्च-स्तरीय इनपुट घटनाओं को उत्पन्न करना है। यह जानने के लिए जिम्मेदार है कि तार्किक कमांड जंप के लिए स्पेसबार और 'ए' गेमपैड बटन दोनों मैप करते हैं। यह गेमपैड बनाम माउस लुक कंट्रोल आदि से संबंधित है। यह उच्च-स्तरीय तार्किक घटनाओं का उत्सर्जन करता है जो निम्न-स्तर के नियंत्रणों से जितना संभव हो उतना सार है (यहां कुछ सीमाएं हैं, लेकिन आप चीजों को पूरी तरह से सामान्य मामले में दूर कर सकते हैं)।

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

खेल तर्क पर निर्भर कुछ भी खिलाड़ी नियंत्रक में चला जाता है। कुछ भी ओएस आश्रित प्लेटफॉर्म परत में चला जाता है। बाकी सब इनपुट मैनेजमेंट लेयर में चला जाता है।

इसका वर्णन करने के लिए यहां कुछ शौकिया ASCII कला है:

-----------------------------------------------------------------------
Platform Abstraction | Collect and forward OS input events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
    Input Manager    | Translate OS input events into logical events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
Character Controller | React to logical events and affect game play
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
      Game Logic     | React to player actions and provides feedback
-----------------------------------------------------------------------

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

1
@danijar: एह, मैं प्रयोग कर रहा था, पहले कभी कोई उत्तर निकालने की कोशिश नहीं की थी। इसकी तुलना में अधिक काम लायक था, लेकिन पेंट कार्यक्रम से निपटने की तुलना में बहुत कम काम। :)
शॉन मिडिलडाइच

ठीक है, समझ में आता है :-)
danijar

8
व्यक्तिगत रूप से, मैं एक उबाऊ क्रमांकित सूची से अधिक ASCII कला तरीका पसंद करता हूं।
जेसी इमोंड

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