2011-10-28 22 views
8

फ़्लैश पर फ़्रेम स्किपिंग को मूल रूप से सक्षम करने का कोई तरीका है?फ्लैश पर फ़्रेम छोड़ना

जब आप कोई गेम विकसित करते हैं, तो आप गेमप्ले की गति से मेल खाने के लिए एनिमेशन विकसित करते हैं, और इसे लक्ष्य फ्रेम दर (आमतौर पर फ़्लैश के लिए 24-40fps) पर करते हैं। लेकिन यदि उपयोगकर्ता का कंप्यूटर बहुत धीमा है, और लक्ष्य फ्रेम दर को बनाए नहीं रख सकता है, तो फ्लैश स्वचालित रूप से एफपीएस को कम कर देगा, जिससे एप्लिकेशन धीरे-धीरे खेल सके।

यदि आप समय-आधारित तर्क का उपयोग करते हैं, तो फ्रेम आधारित प्रतिपादन समय आधारित तर्क से मेल नहीं खाएगा, और चीजें अजीब होंगी और आसपास के काम करने के लिए बहुत से कोने के मामले होंगे।

मुझे पता है कि कुछ गेम पॉपकैप के जुमा ब्लिट्ज जैसे फ्रेम स्किपिंग तर्क का उपयोग करते हैं। क्या वे खुद को फ्रेम छोड़ने को लागू कर रहे हैं?

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

+0

"मेरे गेम में स्क्रीन पर 600+ जटिल मूवीक्लिप्स हैं, जो केवल 100 एएस 3 कक्षा से जुड़े हुए हैं जिन पर इसका प्रत्यक्ष नियंत्रण हो सकता है।" क्या आपकी समस्या है कि आप चरण में जोड़े जाने के बाद ऑब्जेक्ट्स के संदर्भ नहीं पा सकते हैं, या gotoAndStop() कलाकारों द्वारा निर्धारित टाइमलाइन कोड को बाधित कर देगा? यदि आप एक्स फ्रेम को छोड़ने और टाइमलाइन कोड की अखंडता को बनाए रखने की आवश्यकता है (इस एटीएम का परीक्षण नहीं किया है, लेकिन आपके वर्कफ़्लो के बारे में भी पर्याप्त नहीं है, तो आप शायद अधिक समय बीत चुके हैं, और gotoAndplay (currentframe + x) निश्चित रूप से एक तरफ या दूसरे के लिए कहने के लिए) –

उत्तर

3

ठीक है, मुझे लगता है कि आप, निम्नलिखित 'समाधान' है, जो काम नहीं करेगा के लिए नहीं देख रहे हैं के रूप में सभी फ्रेम अभी भी खेला जाएगा:

stage.frameRate = new_frame_rate; 

एकमात्र समाधान सिर्फ फ्रेम को छोड़ करने के लिए है अपने enterFrame कॉलबैक में:

// Defined elsewhere. 
var current_frame:Number = 0; 
var frame_skip_factor:uint; // Skip one frame every 'x' frames. 
var is_frame_skip_active:Boolean; 

function on_enter_frame(event:Event):void 
{ 
    if (is_frame_skip_active && current_frame++ % frame_skip_factor == 0) { return; } 

    // Game logic/rendering code... 
} 

(यह सोचते हैं, सर्वोत्तम प्रथाओं के अनुसार, आप एक ही कॉलबैक में केंद्रीकृत खेल तर्क/एनीमेशन है), लेकिन जब किसी भी अतुल्यकालिक कॉलबैक चलाए जा रहे हैं कि दौड़ की स्थिति/जटिलताओं उपस्थित हो सकता है।

रनटाइम स्तर पर फ़्रेम को वास्तव में छोड़ने का कोई तरीका नहीं है; यह एवीएम के अनुबंध का हिस्सा है - कोई फ्रेम छोड़ा नहीं गया है, सभी कोड भाग गए हैं, इससे कोई फर्क नहीं पड़ता। यदि प्रदर्शन एक मुद्दा है, तो आप असीमित कोड निष्पादन का प्रयास कर सकते हैं। ऐसा करने के कुछ तरीके हैं:

1) पिक्सेल बेंडर को कुछ कंप्यूटिंग ऑफ़लोड करें, ताकि इसे असीमित रूप से और/या समानांतर में संसाधित किया जा सके (http://www.adobe.com/devnet/flex/ लेख/flashbuilder4_pixelbender.html)

2) एकाधिक फ्रेमों पर लंबे संचालन के निष्पादन को फैलाएं (एक राज्य की बचत और राज्य बहाल करने की आवश्यकता है, एक ला स्मृति चिन्ह पैटर्न)। विवरण (और एक महान पढ़ा गया) यहां: http://www.senocular.com/flash/tutorials/asyncoperations/

किसी भी मामले में, मैं (प्रथम और सबसे प्रमुख) फ्लैश बिल्डर प्रोफाइलर या स्टैट्स क्लास (श्री डोब) जैसे टूल के साथ प्रदर्शन बाधा को निश्चित रूप से पहचानने की अनुशंसा करता हूं।

ब्लिटिंग समाधान हो सकता है (एनीमेशन के प्रत्येक फ्रेम के लिए टाइल के साथ एक स्प्राइटशीट बनाएं)। लेकिन किसी भी मामले में, मुझे लगता है कि आपको क्या करना होगा सबक्लास मूवीक्लिप है और प्ले(), स्टॉप(), और gotoAndplay() विधियों को ओवरराइड करें।

public class MyMovieClip extends MovieClip 
{ 
    override public function play():void 
    { 
     addFrameSkipListener(); 

     super.play(); 
    } 

    override public function gotoAndPlay(frame:Object, scene:String = null):void 
    { 
     addFrameSkipListener(); 

     super.gotoAndPlay(frame, scene); 
    } 

    // .... 
} 

कहाँ फ्रेम श्रोता को छोड़ वर्तमान फ्रेम दर फ्रेम या समय के अनुसार फ्रेम को छोड़ देगा, यदि आवश्यक हो: अपने वर्ग कुछ इस तरह दिखना चाहिए। स्वाभाविक रूप से, जब एनीमेशन समाप्त हो गया है तो आपको फ्रेमस्कीपलिस्टर को भी हटाने की आवश्यकता होगी।

जबकि मूवीक्लिप ओवरराइड समाधान पेपर पर जो भी आप चाहते हैं, वह कर सकता है, यदि आपके पास बहुत सारी ऑब्जेक्ट्स हैं, तो यह वास्तव में प्रदर्शन को कम कर सकता है क्योंकि अतिरिक्त ENTER_FRAME श्रोताओं कुछ ओवरहेड जोड़ देंगे।

+0

"रनटाइम स्तर पर वास्तव में फ्रेम को छोड़ने का कोई तरीका नहीं है; यह एवीएम के अनुबंध का हिस्सा है - कोई फ्रेम छोड़ा नहीं गया है, सभी कोड चलाए गए हैं, इससे कोई फर्क नहीं पड़ता।" बहुत रोचक, क्या आप मुझे एक विश्वसनीय लिंक मिल सकते हैं जो कहता है? मुझे यह यहां नहीं मिल रहा है http://www.adobe.com/content/dam/Adobe/en/devnet/actionscript/articles/avm2overview.pdf – felipemaia

+0

निश्चित रूप से - (अर्द्ध-) प्रसिद्ध लेख (http://ted.onflash.org/2005/07/flash-player-mental-model-elastic।php, और यहां एक AVM2- विशिष्ट अद्यतन के साथ: http://ted.onflash.org/2008/04/flash-player-mental-model-elastic.php) फ़्लैश को एक लोचदार रैसेट्रैक की तुलना में कहते हैं: "में समझें कि खिलाड़ी कभी भी लापरवाह नहीं होता है, यह हमेशा आपके द्वारा किए जाने वाले सभी काम करेगा और कभी भी बाद के फ्रेम चक्र को स्थगित नहीं करेगा। " इसकी विश्वसनीयता/विश्वसनीयता के रूप में, ध्यान दें कि इस आलेख को सीधे एडोब के "एडोब फ्लैश प्लेटफ़ॉर्म के लिए अनुकूलन प्रदर्शन" दस्तावेज़ में संदर्भित किया गया था, यह भी एक महान पढ़ा गया था। उन लिंक के लिए –

+0

TYVM! – felipemaia

9

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

पैकेज

{ 
    import flash.display.Shape; 
    import flash.display.Sprite; 
    import flash.events.Event; 
    import flash.utils.getTimer; 

    /** 
    * ... 
    * @author Zachary Foley 
    */ 
    public class Main extends Sprite 
    { 
     private var lastFrame:int = 0; 
     private var thisFrame:int; 
     private var pixelsPerSecond:Number = 200; 
     private var circle:Shape 
     private var percentToMove:Number; 
     public function Main():void 
     { 
      if (stage) init(); 
      else addEventListener(Event.ADDED_TO_STAGE, init); 
      circle = new Shape(); 
      circle.graphics.beginFill(0xFF0000); 
      circle.graphics.drawCircle(0, 0, 25); 
      circle.x = 50; 
      addChild(circle); 
      addEventListener(Event.ENTER_FRAME, onEnterFrame); 
     } 

     private function onEnterFrame(e:Event):void 
     { 
      // Get the miliseconds since the last frame 
      thisFrame = getTimer(); 
      percentToMove = (thisFrame - lastFrame)/1000; 
      // Save the value for next frame. 
      lastFrame = thisFrame; 
      // Update your system based on time, not frames. 
      circle.x += pixelsPerSecond * percentToMove; 

     } 

     private function init(e:Event = null):void 
     { 
      removeEventListener(Event.ADDED_TO_STAGE, init); 
      // entry point 
     } 

    } 

} 

आप पाते हैं कि कम फ़्रेमदर टक्कर गणना की सटीकता प्रभावित कर रहे हैं:

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

और बस इतना ही पता है, आप फ़्लैश में फ्रेम छोड़ने के लिए नहीं कर सकते हैं। यह खिलाड़ी द्वारा संभाला जाता है। परिवर्तनीय फ्रेम दर को समायोजित करने के लिए अपनी फ्रेम प्रतिपादन तकनीक को समायोजित करना सबसे अच्छा तरीका है।

+0

हैलो, मुझे पता है कि अंतिम फ्रेम के बाद से समाप्त होने वाले समय का उपयोग करके खेल के तर्क को कैसे नियंत्रित किया जाए (यही वह है जो मैं अपने प्रश्न पर समय आधारित तर्क कहता हूं)। मेरा सवाल एनीमेशन को नियंत्रित करने के साथ करना है (एक कलाकार द्वारा बनाई गई मूवीक्लिप पर एक एनीमेशन)। – felipemaia

+0

इसलिए gotoAndStop() का उपयोग करें और gotoAndStop (Math.floor (प्रतिशतToMove * framesPerSecondOfTheMovieClip) का उपयोग कर सही फ्रेम की गणना करें; इस तरह आपकी क्लिप उचित फ्रेम पर जायेगी कि कितना समय बीत चुका है। ब्लिटिंग के साथ एक ही दृष्टिकोण करने से आपको कुछ मामलों में प्रदर्शन बढ़ावा मिल सकता है। –

+0

लेकिन फिर मैं फ्लैश टाइमलाइन पर एनीमेशन को नियंत्रित करने की क्षमता खो देता हूं, जिससे कलाकारों को अपनी संपत्तियां विकसित करना बहुत मुश्किल हो जाता है, प्रत्येक एकल संपत्ति को अपनी नियंत्रण कक्षा की आवश्यकता होती है। मेरे गेम में स्क्रीन पर 600+ जटिल मूवीक्लिप्स हैं, जो केवल 100 एएस 3 कक्षा से जुड़े हुए हैं जिन पर इसका प्रत्यक्ष नियंत्रण हो सकता है। – felipemaia

2

आपकी सबसे बड़ी समस्या यह है कि आप blitting नहीं कर रहे हैं। कलाकार अभी भी समयरेखा और निर्यात स्प्राइट शीट पर एनिमेट कर सकते हैं। मैं फ्लैश प्लेयर टाइमलाइन आधारित एनिमेशन के आसपास प्रदर्शन सीमाओं को गंभीरता से समझने में कुछ समय व्यतीत करूंगा। यहाँ लिंक की एक जोड़ी पाने के लिए आप शुरू कर रहे हैं:

आप देख सकते हैं gotoAndStop() का उपयोग कर समय से एनीमेशन को नियंत्रित; आप जिस स्प्रिंग्स के साथ काम कर रहे हैं उसकी मात्रा के संबंध में एनीमेशन के लिए बदतर संभव तरीका है।

तुम भी नए राई 2 डी ग्राफिक्स एपीआई के साथ काम करने पर गौर कर सकता है, स्टार्लिंग फ्रेमवर्क

सीधे आपके प्रश्न को हल करने के लिए, मैं दूसरे समाधान पहले से ही चर्चा है, एक कार्यावधि में स्प्राइट शीट को प्रस्तुत करना बफ़र प्रदर्शन। समय पर किसी भी समय आवश्यक sprites की संख्या के आधार पर, आप स्मृति सीमाओं के लिए कम एनीमेशन प्रदर्शन स्वैप कर सकते हैं।

शुभकामनाएं।

1

मैंने हाल ही में कुछ इसी तरह से भाग लिया; शायद निम्नलिखित किसी तरह से मदद करता है:

  • gotoAndStop (फ्रेम) तुरंत फ्रेम
  • पर actionscript निष्पादित करेंगे आप एक से अधिक gotoAndStop एक भी ENTER_FRAME घटना (या किसी अन्य घटना) के भीतर कॉल कर सकते हैं।

परीक्षण के रूप में मैंने फ्लैश प्रो CS5.5 के भीतर एक नई AS3.0 प्रोजेक्ट बनाया है। मैंने एक नया मूवीक्लिप बनाया और टाइमलाइन को 23 फ्रेम में विस्तारित किया।

पहले फ्रेम में मैं निम्नलिखित कोड कहा:

import flash.events.Event; 

// do something every frame 
this.addEventListener(Event.ENTER_FRAME, handleEnterFrame); 
// let event handler change the playHead 
this.stop(); 

// advance playhead 2 frames every frame 
function handleEnterFrame(anEvent: Event): void 
{ 
    trace('* ENTER_FRAME'); 
    this.gotoNextFrame(); 
    this.gotoNextFrame(); 
} 

// advance to next frame, show playheads position 
function gotoNextFrame(): void 
{ 
    // at last frame? 
    if (this.currentFrame < this.totalFrames) 
    { 
    // no, advance to next frame 
    var before: int = this.currentFrame; 
    this.gotoAndStop(this.currentFrame + 1); 
    trace('before: ' + before + ', current: ' + this.currentFrame); 
    } 
    else 
    { 
    // last frame, stop updating the playhead 
    this.removeEventListener(Event.ENTER_FRAME, handleEnterFrame); 
    } 
} 

फ्रेम 5 में मैं एक महत्वपूर्ण फ्रेम बनाया गया और कोड कहा:

this.gotoAndPlay(10); 

फ्रेम 14 की उम्र में मैं एक महत्वपूर्ण फ्रेम बनाया है और मैं निम्नलिखित ट्रेस उत्पादन मिला

this.gotoAndPlay(16); 

चलाने के बाद: कोड जोड़ा

* ENTER_FRAME 
before: 1, current: 2 
before: 2, current: 3 
* ENTER_FRAME 
before: 3, current: 4 
before: 4, current: 10 
* ENTER_FRAME 
before: 11, current: 12 
before: 12, current: 13 
* ENTER_FRAME 
before: 13, current: 16 
before: 16, current: 17 
* ENTER_FRAME 
before: 17, current: 18 
before: 18, current: 19 
* ENTER_FRAME 
before: 19, current: 20 
before: 20, current: 21 
* ENTER_FRAME 
before: 21, current: 22 
before: 22, current: 23 
* ENTER_FRAME 

मुझे नहीं पता कि उपर्युक्त उपरोक्त कितना कुशल या समय ले रहा है। मुझे इसे केवल एक मूवीक्लिप के साथ उपयोग करना पड़ा था (विकास के आखिरी चरण में यह पता चला कि यह मुख्य काम भी चला सकता है, लेकिन एनिमेशंस चलाने के लिए कोई बजट नहीं था; चरित्र में सही समय के लिए पैडस्टेप जनरेटिंग स्क्रिप्ट शामिल थी समय)।

अपने मामले में आप जांच सकते हैं कि अंतिम ENTER_FRAME के ​​बाद से कितना समय बीत चुका है और फिर फ्रेम की सही संख्या अग्रिम करें।

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

1

जहां तक ​​मुझे पता है, किसी भी अंतराल पर मूवीक्लिप फ्रेम को छोड़ने के लिए एएस 3 में कुछ भी नहीं बनाया गया है, या टाइमलाइन एनीमेशन के माध्यम से सामान्य से अधिक तेज़ी से आगे बढ़ने के लिए कुछ भी नहीं है। ज़ूमा जैसे गेम संभवतया इसे मैन्युअल रूप से कर रहे हैं, या शुरुआत के साथ टाइमलाइन का उपयोग किये बिना अपने एनिमेशन चला रहे हैं।

मैन्युअल रूप से ऐसा करने के लिए, आप दो मुख्य विकल्प हैं:

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

उदाहरण के लिए:

var preferredFrameRate = 24; //use whatever your timeline animations are set to 
function skipFramesIfNeeded() { 
    var currentFrameRate = stage.frameRate; 
    var speedDifference = 1 - (currentFrameRate/preferredFrameRate);//value between 0-1 
    if(.5 <= speedDifference < .66) { 
     gotoAndPlay(this.currentFrame+1); 
    } else if(.66 <= speedDifference) { 
     gotoAndPlay(this.currentFrame+2); 
    } 
} 

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

कोड केवल: यदि आप समय पा सकते हैं, तो यह बेहतर होगा कि हर किसी के सुझावों को बेहतर लगे। अपने एनिमेशन को टाइमलाइन से बाहर ले जाएं, और उन्हें कोड के साथ ड्राइव करें। एनीमेशन और संक्रमण गति के लिए सेटिंग्स या गुणक रखें, या प्रति फ्रेम कितनी पिक्सल ऑब्जेक्ट्स ले जाएं।

फिर आप अपना पसंदीदा फ्रेमरेट स्टोर कर सकते हैं, इसकी तुलना चरण.frameRate से करें, और उसके अनुसार गुणक को समायोजित करें। यह गति में चिकनी वृद्धि के लिए अनुमति देगा।

उदाहरण के लिए:

var preferredFrameRate = 24; //or whatever you want this to run at 
var defaultSpeedMultiplier = 1; 
var speedMultiplier = 1; //this is the multiplier we'll update 

function updateAnimationSpeed() { 
    var currentFrameRate = stage.frameRate; // 18, hypothetically 
    var speedDifference = 1 - (currentFrameRate/preferredFrameRate); //.25, or a difference of 25% 
    speedMultiplier = defaultSpeedMultiplier + extraSpeed; 
    //speed multiplier increases from 1 to 1.25 to make up for less frequent frames 
} 

कलाकार द्वारा बनाए गए दृश्य राज्यों के लिए, आप संभवतः बिटमैप्स के एक गिने सेट लोड, और आदेश है कि आप एक फ्रेम से दूसरे करने के लिए कदम होगा में उनके बीच स्विच कर सकते हैं।

संपादित करें: सिद्धांत में, आप शायद परिवर्तन का पता लगा सकते हैं, और फ्रेमरेट को वापस बदल सकते हैं, लेकिन यदि उपयोगकर्ता की मशीन नहीं रह सकती है, तो फ्लैश शायद इसे अनदेखा कर देगा।

1

आप अपने मंच की जड़ पर कहीं भी एक सौ या तो फ्रेम लंबी खाली फिल्म क्लिप बना सकते हैं, इसमें दस सेकंड या इतनी लंबी पूरी तरह से चुप ध्वनि क्लिप डालें, और ध्वनि को स्ट्रीम और लूप पर सेट करें।

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

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