2012-05-18 11 views
18


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

पहले मैं GLSurfaceView.RENDERMODE_CONTINUOUSLYसाथ काम करने की कोशिश की और मैं onDrawFrame करने के लिए सभी कोड डाल:

public void onDrawFrame(GL10 gl) 
    { 
     updateGame(gl, 0.017f); 
     drawGame(gl); 
    } 

यह सबसे सरल और पूर्ण चिकनी है !! - लेकिन यह हार्डवेयर गति (= बेकार) पर निर्भर है


public void onDrawFrame(GL10 gl) 
    { 
     frameTime = SystemClock.elapsedRealtime();   
     elapsedTime = (frameTime - lastTime)/1000; 
     updateGame(gl, elapsedTime); 
     drawGame(gl); 
     lastTime = frameTime; 
    } 

यह सब का सबसे अच्छा है, लेकिन यह पिछले है, कभी कभी झटका


दूसरा मैंने कोशिश की GLSurfaceView.RENDERMODE_WHEN_DIRTY के रूप में के रूप में चिकनी नहीं है , onDrawFrame में मैं केवल वस्तुओं और अलग थ्रेड में इस कोड को ड्राइंग है

while (true) 
    { 
    updateGame(renderer, 0.017f); 
    mGLSurfaceView.requestRender(); 
    next_game_tick += SKIP_TICKS; 
    sleep_time = next_game_tick - System.currentTimeMillis(); 
    if (sleep_time >= 0) 
    { 
     try 
     { 
      Thread.sleep(sleep_time); 
     } 
     catch (Exception e) {} 
     } 
     else 
     { 
     Log.d("running behind: ", String.valueOf(sleep_time)); 
     } 
    } 

इस चिकनी नहीं है और इसे समस्याओं नहीं कर रहा है "पीछे चल रहा है"


मेरा उद्देश्य ऊपर दिए गए पहले कोड उदाहरण की तरह चिकनी छवि आंदोलन है।

संभावित त्रुटि कहीं और है तो मैं देख रहा हूं। कृपया, क्या कोई मेरी मदद कर सकता है?
बेहतर RENDERMODE_WHEN_DIRTY या RENDERMODE_CONTINUOUS का उपयोग बेहतर है?

धन्यवाद।

+1

'त्वरक द्वारा चलती' एक्सीलरोमीटर तुम वापस उछल डेटा दे। क्या यह आपकी समस्या हो सकती है? "कुछ लॉक + = (न्यूलॉक - कुछ लॉक) * .1 एफ;" जैसे कुछ करके आंदोलन को सुगम बनाने का प्रयास करें। – zezba9000

+0

हैलो, अगर मैं एक्सेलेरोमीटर को अक्षम करने की कोशिश करता हूं और निरंतर मूल्य से केवल सरल चाल छवियों को स्पोरैडिक फ्लिक भी करता हूं (इसे RENDERMODE_WHEN_DIRTY के साथ आजमा रहा है) – Commanche

उत्तर

32

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

असल में, इन कारक हैं:

  • eglSwapInterval एंड्रॉयड में लागू नहीं किया गया है, इसलिए इस समय पता करना मुश्किल है जब हार्डवेयर स्क्रीन (हार्डवेयर स्क्रीन सिंक) में अंतिम ड्रा
  • थ्रेड का पर्दाफाश। नींद सटीक नहीं है। थ्रेड अनुरोध से अधिक या कम सो सकता है।
  • SystemClock.uptimeMillis() System.nanoTime(), System.currentTimeMillis() और अन्य समय संबंधित माप सटीक नहीं है (इसकी सटीक)।

यह मुद्दा ड्राइंग प्रौद्योगिकी (ड्राइंग, ओपनजीएल 1.0/1.1 और 2.0) और गेम लूप विधि (निश्चित समय चरण, इंटरपोलेशन, परिवर्तनीय समय चरण) से स्वतंत्र है। आप की तरह, मैं थ्रेड स्लीप, पागल इंटरपोलेशंस, टाइमर इत्यादि की कोशिश कर रहा था। इससे कोई फर्क नहीं पड़ता कि आप क्या करेंगे, हमारे पास इस कारकों पर नियंत्रण नहीं है।

कई क्यू & एक इस साइट पर, बुनियादी नियमों चिकनी निरंतर एनिमेशन का निर्माण करने के साथ अनुसार कर रहे हैं:

  • सभी गतिशील स्मृति अनुरोध को हटाने के द्वारा जीसी कम से कम कम करें।
  • फ्रेम को रेंडर करें जितना तेज़ हार्डवेयर उन्हें संसाधित कर सकता है (अधिकांश एंड्रॉइड उपकरणों में 40 से 60 एफपीएस ठीक है)।
  • इंटरपोलेशन या परिवर्तनीय समय चरणों के साथ निश्चित समय चरणों का उपयोग करें।
  • अद्यतन भौतिकी को अनुकूलित करें और उच्च चोटी भिन्नता के बिना सापेक्ष निरंतर समय में निष्पादित करने के लिए दिनचर्या ड्रा करें।

यकीन के लिए, आप पिछले काम का एक बहुत कुछ के बाद से पहले इस सवाल के लिए अपने मुख्य में एक चिकनी एनीमेशन प्राप्त करने के लिए (सराहनीय जीसी और सापेक्ष निरंतर निष्पादन समय के बिना) अपने updateGame() और drawGame() के अनुकूलन द्वारा किए गए लूप जैसा कि आप उल्लेख करते हैं: "सरल और पूर्ण चिकनी"।

परिवर्तनीय चरण समय के साथ आपका विशेष मामला और वास्तविक समय घटनाओं (संगीत की तरह) के साथ सही सिंक में होने के लिए कोई विशेष आवश्यकता नहीं है, समाधान सरल है: "चरण समय परिवर्तनीय चिकनी"।
समाधान अन्य खेल पाश योजनाओं (चर प्रतिपादन के साथ तय समय कदम) के साथ काम करता है और बंदरगाह के लिए आसान है अवधारणा (updateGame और कई फ्रेम में वास्तविक समय घड़ी द्वारा उत्पादित विस्थापन की राशि चिकनी।)

// avoid GC in your threads. declare nonprimitive variables out of onDraw 
    float smoothedDeltaRealTime_ms=17.5f; // initial value, Optionally you can save the new computed value (will change with each hardware) in Preferences to optimize the first drawing frames 
    float movAverageDeltaTime_ms=smoothedDeltaRealTime_ms; // mov Average start with default value 
    long lastRealTimeMeasurement_ms; // temporal storage for last time measurement 

    // smooth constant elements to play with 
    static final float movAveragePeriod=40; // #frames involved in average calc (suggested values 5-100) 
    static final float smoothFactor=0.1f; // adjusting ratio (suggested values 0.01-0.5) 

    // sample with opengl. Works with canvas drawing: public void OnDraw(Canvas c) 
    public void onDrawFrame(GL10 gl){  
     updateGame(gl, smoothedDeltaRealTime_ms); // divide 1000 if your UpdateGame routine is waiting seconds instead mili-seconds. 
     drawGame(gl); 

     // Moving average calc 
     long currTimePick_ms=SystemClock.uptimeMillis(); 
     float realTimeElapsed_ms; 
     if (lastRealTimeMeasurement_ms>0){ 
     realTimeElapsed_ms=(currTimePick_ms - lastRealTimeMeasurement_ms); 
     } else { 
       realTimeElapsed_ms=smoothedDeltaRealTime_ms; // just the first time 
     } 
     movAverageDeltaTime_ms=(realTimeElapsed_ms + movAverageDeltaTime_ms*(movAveragePeriod-1))/movAveragePeriod; 

     // Calc a better aproximation for smooth stepTime 
     smoothedDeltaRealTime_ms=smoothedDeltaRealTime_ms +(movAverageDeltaTime_ms - smoothedDeltaRealTime_ms)* smoothFactor; 

     lastRealTimeMeasurement_ms=currTimePick_ms; 
    } 

    // Optional: check if the smoothedDeltaRealTIme_ms is too different from original and save it in Permanent preferences for further use. 

एक निश्चित समय के कदम योजना के लिए, एक intermetiate updateGame परिणामों में सुधार करने के लिए लागू किया जा सकता है:

float totalVirtualRealTime_ms=0; 
float speedAdjustments_ms=0; // to introduce a virtual Time for the animation (reduce or increase animation speed) 
float totalAnimationTime_ms=0; 
float fixedStepAnimation_ms=20; // 20ms for a 50FPS descriptive animation 
int currVirtualAnimationFrame=0; // useful if the updateGameFixedStep routine ask for a frame number 

private void updateGame(){ 
    totalVirtualRealTime_ms+=smoothedDeltaRealTime_ms + speedAdjustments_ms; 

    while (totalVirtualRealTime_ms> totalAnimationTime_ms){ 
     totalAnimationTime_ms+=fixedStepAnimation_ms; 
     currVirtualAnimationFrame++; 
     // original updateGame with fixed step     
     updateGameFixedStep(currVirtualAnimationFrame); 
    } 


    float interpolationRatio=(totalAnimationTime_ms-totalVirtualRealTime_ms)/fixedStepAnimation_ms; 
    Interpolation(interpolationRatio); 
} 

कैनवास और openGlES10 निम्नलिखित उपकरणों के साथ बैठक के साथ परीक्षण किया गया: एसजी SII (57 एफपीएस), एसजी नोट (57 एफपीएस), एसजी टैब (60 एफपीएस), अनबन्धित एंड्रॉइड 2.3 (43 एफपीएस) धीमी एमुलेटर रननी विंडोज एक्सपी (8 एफपीएस) पर एनजी। टेस्ट प्लेटफॉर्म लगभग 45 ऑब्जेक्ट्स + 1 विशाल पृष्ठभूमि (70 एमपी स्रोत छवि से बनावट) वास्तविक भौतिकी पैरामीटर (किमी/एच और जी) में निर्दिष्ट पथ के साथ चल रहा है, बिना स्पाइक्स या कई उपकरणों के बीच झटका (अच्छी तरह से, एम्यूलेटर पर 8 एफपीएस) अच्छा नहीं दिखता है, लेकिन इसकी प्रवाह स्थिर गति के रूप में अपेक्षित है)

एंड्रॉइड रिपोर्ट समय के लिए आलेखों की जांच करें। कुछ बार एंड्रॉइड एक बड़े डेल्टा समय की रिपोर्ट करता है और केवल अगले लूप औसत से छोटा होता है, जिसका अर्थ है रीयलटाइम वैल्यू के पढ़ने पर ऑफसेट।

enter image description here

और अधिक विस्तार के साथ

: enter image description here

How to limit framerate when using Android's GLSurfaceView.RENDERMODE_CONTINUOUSLY?

System.currentTimeMillis vs System.nanoTime

Does the method System.currentTimeMillis() really return the current time?

+0

आपको बहुत धन्यवाद javgui, मैं इस ASAP का परीक्षण करूंगा और रिपोर्ट करने के बाद ... – Commanche

+0

हाय फिर से, इसलिए, इस उदाहरण में एक त्रुटि होनी चाहिए - चिकनी टाइमस्टेप का मान बार-बार बढ़ता है, लेकिन अगर मैं "smoothTimeStep = gameTimeElapsed * smoothFactor + (temp-gameTimeElapsed)" - यह अच्छा लग रहा है :-) अब यह है बहुत बेहतर है, लेकिन कभी-कभी फ्लिक भी (अक्सर नहीं) - मैंने चिकनी टाइमस्टेप लॉग किया है और यहां यह मान है: 0.021 0.021 0.021 ........ 0.06 0.095 0.03 0.008 0.007 0.005 0.021 0.021 शायद यह केवल सैमसंग एचडब्ल्यू पर समस्या है (एसजीएस 2 पर परीक्षण किया गया), मैं एक और डिवाइस पर कोशिश करूंगा। – Commanche

+0

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