2011-12-15 7 views
14

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

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

मैं यहाँ के आसपास पढ़ने किया गया है और अन्य साइटों पर कि:

यह नहीं करने के लिए यकीन है कि प्रसंस्करण के लिए कोई समस्या नहीं एक और धागा इसके लिए सिर्फ इसलिए एंड्रॉयड इच्छा बनाने के लिए, बेहतर है।

कोड अर्थ कुछ इस तरह होगा:

public void onDrawFrame(GL10 gl) { 
    doLogicCalculations(); 
    clearScreen(); 
    drawSprites(); 
} 

लेकिन मुझे यकीन है कि अगर सबसे अच्छा तरीका हो सकता है नहीं कर रहा हूँ। चूंकि मुझे नहीं लगता कि मुझे यह पसंद आएगा कि अगर मैं GLRenderer::onDrawFrame विधि के अंदर अपना तर्क डालूं तो ऐसा कैसा लगेगा। जहां तक ​​मुझे पता है, यह विधि सिर्फ ड्रॉ करने के लिए है, और यदि मैं वहां तर्क डालता हूं तो मैं फ्रेम को धीमा कर सकता हूं। उल्लेख नहीं है कि यह मेरी समझ में पीओओ की अवधारणाओं को नुकसान पहुंचाता है।

मुझे लगता है कि धागे का उपयोग कर रास्ता हो सकता है, यह मैं कैसे योजना बना रहा था है:

मुख्य गतिविधि:

public void onCreate(Bundle savedInstanceState) { 
    //set fullscreen, etc 

    GLSurfaceView view = new GLSurfaceView(this); 
    //Configure view 

    GameManager game = new GameManager(); 
    game.start(context, view); 

    setContentView(view); 
} 

GameManager:

OpenGLRenderer renderer; 
Boolean running; 
public void start(Context context, GLSurfaceView view) { 
    this.renderer = new OpenGLRenderer(context); 
    view.setRenderer(this.renderer); 

    //create Texturelib, create sound system... 

    running = true; 
    //create a thread to run GameManager::update() 
} 

public void update(){ 
    while(running){ 
     //update game logic here 
     //put, edit and remove sprites from renderer list 
     //set running to false to quit game 
    } 
} 

और अंत में, OpenGLRenderer:

ListOrMap toDraw; 
public void onDrawFrame(GL10 gl) { 
    for(sprite i : toDraw) 
    { 
     i.draw(); 
    } 
} 

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

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

तो यहाँ मेरे सवालों हैं:

सबसे अच्छा तरीका है प्रतिपादन से मेरी खेल तर्क अलग जब OpenGLES का उपयोग कर रहा है कौन सा? मेरे एप्लिकेशन को थ्रेड करना? तर्क को एक अलग विधि में रखें और इसे ड्रॉ विधि से कॉल करें?

उत्तर

10

तो मुझे लगता है कि आप यहां दो तरीकों से जा सकते हैं।

  1. onDrawFrame() से सभी अद्यतन करें: यह भरमार का उपयोग कर के समान है, और एंड्रॉयड इस समारोह जितनी बार संभव कॉल करेंगे। (setRenderMode(RENDERMODE_WHEN_DIRTY) के साथ इसे बंद करें।) इस फ़ंक्शन को अपने धागे (यूआई थ्रेड नहीं) पर बुलाया जाता है और इसका मतलब है कि आप यहां अपना तर्क अपडेट कहते हैं। आपका प्रारंभिक मुद्दा यह था कि यह थोड़ा गन्दा लगता है, और मैं सहमत हूं, लेकिन केवल इसलिए कि फ़ंक्शन का नाम onDrawFrame() है। अगर इसे onUpdateScene() कहा जाता है, तो तर्क अपडेट करना इस मॉडल को अच्छी तरह से फिट करेगा। लेकिन यह दुनिया में बदतर चीज नहीं है, इसे इस तरह से डिजाइन किया गया था, और लोग इसे करते हैं।

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

मैं # 1 की सिफारिश करता हूं। आपको वास्तव में # 2 की आवश्यकता नहीं है। यदि आप करते हैं, तो आप इसे बाद में जोड़ सकते हैं, लेकिन अधिकांश लोग केवल पहले विकल्प का उपयोग कर रहे हैं क्योंकि हार्डवेयर पर्याप्त तेज़ है इसलिए आपको इसके आसपास डिज़ाइन करने की आवश्यकता नहीं है।

+0

ग्रेट उत्तर स्टीव, धन्यवाद!मुझे लगता है कि मैं भी डिजाइन को गड़बड़ करना पसंद नहीं करता, मैं # 1 का पालन करूंगा। मेरा खेल सक्रिय है, लेकिन भौतिकी या टक्कर की जांच की तरह, इस पर कोई भारी गणना नहीं है। बस मेरे विचारों के बारे में सुनिश्चित करने के लिए, यदि मैं इसे चुनता हूं तो प्रश्न में थ्रेडिंग का मेरा दृष्टिकोण सही होगा (सिंक्रनाइज़ किए गए मानचित्र में तर्क धागा लेखन और इसे पढ़ने के धागे को प्रस्तुत करना)? –

+0

ओह, एक और बात। लोगों ने मुझे अपने तर्क अपडेट को 30fps तक सीमित करने के लिए कहा, यह भी प्रस्तुत करने का मामला है? क्या मुझे पूरे अपडेट को प्रत्येक अपडेट के लिए 33 एमएमएस की प्रतीक्षा करने के लिए सीमित करना चाहिए, या अंतिम अद्यतन के बाद 33 एमएमएस पारित होने पर तर्क को अपडेट करना चाहिए? –

+0

मुझे नहीं लगता कि आपको इसे सीमित करना है, लेकिन हो सकता है कि कुछ फोनों से बेहतर न हों। ऐसा इसलिए है क्योंकि पहले एचडीपीआई फोनों में से कुछ (मुझे लगता है कि डरोइड 1 के समय के बारे में लगता है) सीमित हो गया था, जिसका मतलब है कि वे प्रति सेकंड लगभग 30 गुना से अधिक पिक्सेल से भरा स्क्रीन नहीं खींच सके। हो सकता है कि जीपीयू उस से तेज फ्रेम को क्रैंक कर सके, लेकिन सीपीयू उन्हें स्क्रीन पर पर्याप्त तेज़ी से नहीं ले जा सकता है। मुझे लगता है कि नए फोन पर यह मामला नहीं है। –

6

मानक (और शायद सबसे अच्छा) दृष्टिकोण पीछा कर रहा है हो सके, आसान :) अपने डिजाइन रखें:

public void update(){ 
    while(running){ 
     updateAll(); 
     renderAll(); 
    } 
} 

मैं कुछ क्षणों पर ध्यान देना होगा:

    आप
  • update और render विधियों को क्रमशः कॉल करने की आवश्यकता है, update को दो बार
  • पर कॉल करने से बचें, यदि आप एम पसंद करते हैं ultithreading (मैं नहीं), अपने तरीके डिजाइन इतना update डेटा लिखता है और render पढ़ता केवल
  • ओपन यह अपने "सूत्र" है है कि ध्यान में रखना, इसलिए जब आप जीएल फ़ंक्शन को कॉल यह केवल ओपन करने के लिए कुछ आदेश (glFlush() छोड़कर भेजता है - यह सभी आदेशों को पूरा करता है)
+0

हम्म, आपके अंतिम विषय के रूप में, ओपनजीएलरेन्डर से ऑन ड्राफ्रेम को किसी अन्य धागे पर बुलाया जाता है? या सिर्फ gl.GLxxx() जिन्हें जीएल के अनुरूप अन्य थ्रेड के अनुरोध के रूप में भेजा जाता है? –

+0

@Gtoknu जब आप 'onDrawFrame()' कॉल प्राप्त करते हैं, तो आप एक और धागे पर हैं। यहां देखें: http://developer.android.com/reference/android/opengl/GLSurfaceView.Renderer.html –

+0

@ स्टेवब्लैकवेल ओह, धन्यवाद, मुझे यह एहसास नहीं हुआ है। लेकिन अगर मैं ड्रॉफ्रेम() पर कॉल नहीं कर सकता तो ब्रिगेडिर का जवाब सच कैसे हो सकता है क्योंकि इसे स्वचालित रूप से किसी अन्य थ्रेड द्वारा बुलाया जाता है? वे उलझन में हैं। –

संबंधित मुद्दे