ऐसी गेम क्रियाएं जो कई फ़्रेमों को पूरा करने के लिए लेती हैं


20

मैंने पहले कभी भी बहुत गेम प्रोग्रामिंग नहीं की है, बहुत सीधा सवाल है।

कल्पना कीजिए कि मैं एक टेट्रिस गेम बना रहा हूं, जिसमें मुख्य लूप कुछ इस तरह दिख रहा है।

for every frame
    handle input
    if it's time to make the current block move down a row
        if we can move the block
            move the block
        else
            remove all complete rows
            move rows down so there are no gaps
            if we can spawn a new block
                spawn a new current block
            else
                game over

खेल में अब तक सब कुछ तुरंत होता है - चीजें तुरंत पैदा होती हैं, पंक्तियों को तुरंत हटा दिया जाता है, लेकिन क्या होगा अगर मैं चीजों को तुरंत नहीं करना चाहता (यानी चेतन चीजें)?

for every frame
    handle input
    if it's time to make the current block move down a row
        if we can move the block
            move the block
        else
            ?? animate complete rows disappearing (somehow, wait over multiple frames until the animation is done)
            ?? animate rows moving downwards (and again, wait over multiple frames)
            if we can spawn a new block
                spawn a new current block
            else
                game over

मेरे पोंग क्लोन में यह एक मुद्दा नहीं था, क्योंकि हर फ्रेम मैं सिर्फ गेंद को घुमा रहा था और टक्करों के लिए जाँच कर रहा था।

मैं इस मुद्दे पर अपना सिर कैसे लपेट सकता हूं? निश्चित रूप से अधिकांश खेलों में कुछ कार्रवाई शामिल होती है जो एक फ्रेम से अधिक होती है, और अन्य चीजें तब तक रुक जाती हैं जब तक कि कार्रवाई नहीं की जाती है।

जवाबों:


11

इसका पारंपरिक समाधान एक परिमित राज्य मशीन है, जिसे कई टिप्पणियों में सुझाया जा रहा है।

मुझे परिमित राज्य मशीनों से नफरत है।

यकीन है, वे सरल हैं, वे हर भाषा में समर्थित हैं, लेकिन वे इस तरह के अद्भुत दर्द के साथ काम करते हैं। हर हेरफेर में एक टन का बुगप्रोन कॉपी-एंड-पेस्ट कोड लगता है, और छोटे तरीकों से प्रभाव को ट्विक करने से कोड में बहुत बड़ा बदलाव हो सकता है।

यदि आप एक ऐसी भाषा का उपयोग कर सकते हैं जो उनका समर्थन करती है, तो मैं कोरटाइन की सलाह देता हूं। वे आपको ऐसा कोड लिखते हैं जो दिखता है:

function TetrisPieceExplosion()
  for brightness = 0, 1, 0.2 do
    SetExplosionBrightness(brightness)
    coroutine.yield()
  end

  AllowNewBlockToFall()

  SpawnABunchOfParticles()

  RemoveBlockPhysics()

  for transparency = 0, 1, 0.5 do
    SetBlockTransparency(transparency)
    coroutine.yield()
  end

  RemoveBlockGraphics()
end

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

मेरी जानकारी के अनुसार, यह कार्यक्षमता C, C ++, C #, ऑब्जेक्टिव C या जावा में आसानी से उपलब्ध नहीं है। यह एक मुख्य कारण है कि मैं अपने सभी खेल तर्क के लिए लुआ का उपयोग करता हूं :)


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

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

यह सच है, लेकिन टेट्रिस उदाहरण के लिए यह पर्याप्त होना चाहिए :)
बुमज़ैक

सह-रूटीन रॉक- लेकिन लुआ एक भाषा के रूप में कई अन्य तरीकों से चूसता है, मैं सिर्फ इसकी सिफारिश नहीं कर सकता।
डेडएमजी

जब तक आपको केवल शीर्ष स्तर पर (और नेस्टेड फ़ंक्शन कॉल से नहीं) उपज की आवश्यकता होती है, आप सी # में एक ही चीज को पूरा कर सकते हैं, लेकिन हां, लुआ कोरटाइन्स रॉक।
उदार

8

मैं माइक मैकशाफ्ट्री द्वारा गेम कोडिंग कम्प्लीट से इसे ले रहा हूं।

वह एक 'प्रोसेस मैनेजर' के बारे में बात करता है, जो उन कार्यों की एक सूची को उबालता है जिन्हें करने की आवश्यकता है। उदाहरण के लिए, एक प्रक्रिया एक तलवार (एनीमप्रोसेस) ड्राइंग, या एक दरवाजा खोलने, या आपके मामले में, पंक्ति को गायब करने के लिए एनीमेशन को नियंत्रित करेगी।

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

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

  • पंक्ति गायब होने के लिए एक एनिमेशनप्रोसेस
  • टुकड़ों को हटाने के लिए एक आंदोलन
  • स्कोर में अंक जोड़ने के लिए एक स्कोरप्रोसेसर

(चूँकि प्रक्रियाएँ एक-उपयोग की चीजें हो सकती हैं, सशर्त रूप से या वहाँ X राशि के लिए)

यदि आप कोई और विवरण चाहते हैं, तो पूछें।


3

आप क्रियाओं की प्राथमिकता कतार का उपयोग कर सकते हैं। आप एक क्रिया और एक समय में धक्का देते हैं। प्रत्येक फ़्रेम, आपको समय मिलता है, और आप उन सभी कार्यों को बंद कर देते हैं, जिनके पास उस समय से पहले का समय है और उन्हें निष्पादित करते हैं। बोनस: दृष्टिकोण समानांतर रूप से, और आप वास्तव में इस तरह से लगभग सभी खेल तर्क को लागू कर सकते हैं।


1

आपको हमेशा पिछले और वर्तमान फ्रेम के बीच के समय के अंतर को जानना होगा, फिर आपको दो काम करने होंगे।

-जब अपने मॉडल को अपडेट करने के लिए देखें: जैसे। टेट्रिस में जब एक पंक्ति हटाने की शुरुआत होती है, तो आप नहीं चाहते कि सामान पंक्ति के साथ टकराए, इसलिए आप पंक्ति को अपने एप्लिकेशन के 'मॉडल' से हटा दें।

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

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


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

0

आपको खेल को "परिमित राज्य मशीन" के रूप में सोचने की आवश्यकता है। खेल कई राज्यों में से एक में हो सकता है: आपके मामले में, "इनपुट की उम्मीद", "टुकड़ा नीचे जा रहा है", "पंक्ति विस्फोट"।

आप राज्य के आधार पर अलग-अलग चीजें करते हैं। उदाहरण के लिए, "टुकड़ा नीचे जाने" के दौरान आप खिलाड़ी इनपुट को अनदेखा करते हैं, और इसके बजाय अपनी वर्तमान पंक्ति से अगली पंक्ति के टुकड़े को चेतन करते हैं। कुछ इस तरह:

if state == ACCEPTING_INPUT:
    if player presses any key:
        handle input
    row_timer = row_timer - time_since_last_frame
    if row_timer < 0:
        state = MOVING_PIECE_DOWN
elif state == MOVING_PIECE_DOWN:
    piece.y = piece.y + piece.speed*time_since_last_frame
    if piece.y >= target_piece_y:
        piece.y = target_piece_y
        state = ACCEPTING_INPUT
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.