एक बारी आधारित खेल में विश्व राज्य और एनीमेशन का पृथक्करण


9

आप बारी आधारित गेम के भीतर विश्व राज्य से एनीमेशन के अलगाव को कैसे संभालते हैं? मैं वर्तमान में एक 2D ग्रिड आधारित खेल पर काम कर रहा हूँ। नीचे दिए गए कोड को बेहतर तरीके से समझाया गया है।

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

मैंने जो किया है वह दो प्रकार के एनिमेशन का परिचय है, जिसे मैं अवरुद्ध एनिमेशन और गैर-अवरुद्ध एनिमेशन कहता हूं। जब खिलाड़ी हिलना चाहता है, तो कोड निष्पादित हो जाता है

class Actor {
    void move(PositionInfo oldPosition, PositionInfo newPosition) {
        if(isValidMove(oldPosition, newPosition) {
             getGame().pushBlockingAnimation(new MoveAnimation(this, oldPosition, newPosition, ....));
             player.setPosition(newPosition);
        }
    }
}

फिर मुख्य अपडेट लूप करता है:

class Game {
    void update(float dt) {
        updateNonBlockingAnimations(dt); //Effects like particle explosions, damage numbers, etc. Things that don't block the flow of turns.
        if(!mBlockingAnimations.empty()) {
            mBlockingAnimations.get(0).update(dt);
        } else {
             //.. handle the next turn. This is where new animations will be enqueued..//
        }
        cleanUpAnimations(); // remove finished animations
    }
}

... जहां एनीमेशन अभिनेता की स्क्रीन स्थिति को अपडेट करता है।

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

क्या यह चीजों को करने का एक समझदार तरीका है? क्या किसी के पास कोई सुझाव है, या यहां तक ​​कि इस तरह के अन्य खेल इस तरह के कैसे करते हैं, इसका भी संदर्भ है।

जवाबों:


2

यदि आपका सिस्टम आपके लिए काम करता है, तो मुझे ऐसा करने का कोई कारण नहीं दिखता है।

ठीक है, एक कारण: यह गड़बड़ हो सकता है जब आप आसानी से "खिलाड़ी.सेटपोजिशन (न्यूपोजिशन)" के परिणामों का न्याय नहीं कर सकते हैं; अब और।

उदाहरण (केवल बातें बनाना): कल्पना करें कि आप खिलाड़ी को अपने जाल के साथ कुछ जाल के ऊपर ले जाते हैं। "Player.setPosition" पर कॉल कुछ अन्य कॉल को ट्रिगर करेगा .. एक जाल श्रोता कोड को कहेंगे जो बदले में अपने आप एक अवरुद्ध एनीमेशन को धक्का देगा जो स्वयं के शीर्ष पर एक "हर्टिंग स्प्लैश" प्रदर्शित करता है।

आप समस्या देखते हैं: स्पलैश एक साथ जाल की ओर खिलाड़ी के कदम के साथ प्रदर्शित होता है । (यहां मान लें कि आप ऐसा नहीं चाहते हैं, लेकिन चाहते हैं कि ट्रैप एनीमेशन सही कदम के बाद खेला जाए;))।

तो जब तक आप अपने कार्यों के सभी परिणामों को ध्यान में रखते हैं जो आप उन "पुशबॉकिंगएनिमेशन" कॉल के बाद करते हैं, सब कुछ ठीक है।

आपको गेम लॉजिक को "कुछ अवरुद्ध करना" शुरू करने की आवश्यकता हो सकती है - कक्षाएं ताकि उन्हें एनीमेशन खत्म होने के बाद निष्पादित करने के लिए कतारबद्ध किया जा सके। या आप एक कॉलबैक "callThisAfterAnimationFinishes" पास करने के लिए pushBlockingAnimation पास करें और कॉलबैक फ़ंक्शन में सेटपॉइंट को स्थानांतरित करें।

एक और दृष्टिकोण भाषाओं की स्क्रिप्टिंग होगा। उदाहरण के लिए लुआ के पास "coroutine.yield" है जो एक विशेष राज्य के साथ फ़ंक्शन देता है ताकि इसे अगले बयान पर जारी रखने के लिए बाद में कहा जा सके। इस तरह से आप आसानी से अपने कोड के "सामान्य" कार्यक्रम प्रवाह को अव्यवस्थित किए बिना गेम लॉजिक को निष्पादित करने के लिए एनीमेशन के अंत की प्रतीक्षा कर सकते हैं। (इसका अर्थ है कि आपका कोड अभी भी "playAnimation (); setPosition ();" के बजाय कॉलबैक में पास होने और कई कार्यों पर गेम लॉजिक को अव्यवस्थित करने के बजाय थोड़ा सा दिखाई देगा।

यूनिटी 3 डी (और कम से कम एक अन्य गेम सिस्टम जो मुझे पता है) सी # "कोड में सीधे इसे अनुकरण करने के लिए सी #" यील्ड रिटर्न "स्टेटमेंट की सुविधा देता है।

// instead of simple call to move(), you have to "iterate" it in a foreach-like loop
IEnumerable<Updatable> move(...) {
    // playAnimation returns an object that contain an update() and finished() method.
    // the caller will not iterate over move() again until the object is "finished"
    yield return getGame().playAnimation(...)
    // the next statement will be executed *after* the animation finished
    player.setPosition(newPosition);
}

बेशक, इस योजना में कॉल टू मूव () को अब सभी गंदे काम मिलते हैं। आप शायद इस तकनीक को केवल विशिष्ट कार्यों के लिए लागू करेंगे, जहां आप जानते हैं कि वास्तव में कौन उन्हें कहां से कॉल करता है। तो इसे केवल एक मूल विचार के रूप में लें कि अन्य इंजन कैसे व्यवस्थित हैं - इसका वर्तमान तरीका आपकी वर्तमान विशिष्ट समस्या के लिए बहुत जटिल है।

मेरा सुझाव है कि जब तक आपको वास्तविक-विश्व की परेशानी न हो, तब तक आप अपने पुशब्लॉकिंग के विचार पर टिके रहें। फिर इसे संशोधित करें। ;)


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