16 Replies Latest reply on Jul 2, 2006 7:51 AM by Peter Lorent

    setInterval problem - I give up

    SPGAnne
      OK, I give up. Please be gentle if I've been a total bonehead. I have the following code on a 1 frame main timeline for testing purposes (Document set to play at 20 fps). Two problems: 1) the interval I request for the timer v. what actually happens is different. 2) STRANGELY I get totally different results if I make my .swf document be different fps rates (try 12 v. 20) and you'll see what I mean.

      What the HECK am I doing wrong?

      stop();
      var duration:Number = 18;
      var tps:Number = 18;
      // computed
      var ticks:Number = 0;
      var startTime:Number;
      var interval:Number;
      var intervalID:Number;
      timer = function(intNum:Number):Void {
      interval = intNum;
      intervalID = setInterval(debug,interval);
      startTime = getTimer();
      trace("interval is " + interval + " duration of test is " + duration );

      }

      debug = function():Void {
      ticks = ticks + 1;
      trace("tick: " + ticks + " timer is: " + getTimer());
      if (ticks == duration){
      clearInterval(intervalID);
      currentTime = getTimer();
      trace("start time: " + startTime + " current time: " + currentTime + " elapsed: " + (currentTime - startTime) );
      trace("average interval " + ((currentTime - startTime)/duration) + " v. requested of " + interval);
      trace("computed ticks per second: " + (ticks/((currentTime - startTime)/1000) ) + " v. requested of " + tps );
      }
      }

      testTPS = function (tps:Number):Void {
      intervalNum = Math.round((1/tps * 1000));
      timer(intervalNum);
      }

      testTPS(tps);
        • 1. Re: setInterval problem - I give up
          Level 7
          > What the HECK am I doing wrong?

          Only thing you're doing wrong is making the assumption that setInterval will
          fire at precise intervals.

          It doesn't

          Its only approximate

          If you want any accuracy, always use the getTimer value and work out the
          ACTUAL elapsed time and do whatever you need based on that, not based on the
          interval you supplied
          --
          Jeckyl


          • 2. Re: setInterval problem - I give up
            SPGAnne Level 1
            wow. Wow. So are you saying that on release 8 of Flash there is no precise milisecond timer capability? wow. amazing. OK, I'll try to get a grip.

            So how would I build such a thing that I could use inside a Cass to drive a function/method that needs to fire at various known and dependable ticks per seconds rates?
            • 3. Re: setInterval problem - I give up
              kglad Adobe Community Professional & MVP
              as jeckyl stated, getTimer() will give you more accurate results. but it too is subject to the same problems as everything else in flash computing for cpu cycles.
              • 4. Re: setInterval problem - I give up
                Level 7
                > as jeckyl stated, getTimer() will give you more accurate results. but it
                > too is subject to the same problems as everything else in flash computing
                > for cpu cycles.

                actually .. no its not. getTimer is always accurate to the millsecond.
                --
                Jeckyl


                • 5. Re: setInterval problem - I give up
                  kglad Adobe Community Professional & MVP
                  getTimer() returns the exact time (within an ms) that a swf has been playing WHEN it's executed.

                  the problem is you can't execute or call the getTimer() function exactly. any call to getTimer() must compete (that's a typo in my above message) for cpu cycles and therefore cannot be used for precision timing.
                  • 6. Re: setInterval problem - I give up
                    SPGAnne Level 1
                    Thank you for your help. As a struggling newbie, I TRULY appreciate it. If you don't mind, could you give me a little more guidance on how to use getTimer or some construct using that (i.e. what is the loop I should use that gets the timer periodically without taking over all the CPU cycles) so that I can use THAT inside a class to fire off a method at predictable known intervals? I would be much obliged.
                    • 7. Re: setInterval problem - I give up
                      Level 7
                      You cannot make it fire at a known time .. but the method you DO fire can
                      detect the time since it was last fired and adjust what it does accordingly.

                      Eg if you're using it for moving something at a fixed known speed, you would
                      calculate the amount to move based on the difference in time (rather than
                      assuming that you setInterval or onEnterFrame are calling it at a fixed
                      rate.

                      Jeckyl


                      • 8. Re: setInterval problem - I give up
                        kglad Adobe Community Professional & MVP
                        anne, what is it that you need to do? while jeckyl and i are pointing out that you cannot use flash to precisely time anything, it's acurate enough for most uses.

                        except in extremes where you have a lot of cpu/graphics intensive activity in flash, there's no significant problem with setInterval() or onEnterFrame executing at (close to) predictable intervals.
                        • 9. Re: setInterval problem - I give up
                          SPGAnne Level 1
                          Dear Mr./Ms. kglad,

                          Thank you so much for your willingness to help and your persistence in trying to understand my problem. In answer to your question, I do simulation work. Lots of my stuff is time dependent and fairly precise. In one situation I need to randomly pick a number between about 20 and 200 which is the number of times per minute I need to play a short sound/animation. I have to be sure that precisely that number will play during not only the one minute interval, but should also be precise if measured in 10 second increments and sometimes less. In addition, some times I may need to interrupt the timer and introduce some irregularity which sometimes is random and sometimes is in a known pattern. I have other cases like this but this is probably among the toughest one given my understanding of setInterval's limitations.

                          Again, any and all help you can provide would be greatly appreciated. Maybe Flash just can't hack it. If so please give me the bad news before I get too far with all this so I can come up with plan B.

                          • 10. Re: setInterval problem - I give up
                            kglad Adobe Community Professional & MVP
                            if there isn't a lot more going on in your flash, you can expect flash to be able to play your sound within 5 to 10 thousanths of a second of the correct interval. if that's accurate enough, you should do further testing because if you have a lot going on in your swf that accuracy will drop.

                            unfortunately, obtaining that accuracy means you have to put a drain on the cpu. here's some code you can use to test. depending upon the resources of your machine and the resources (computer-wise) of you users, you may need to adjust the accuracyVar and you should set the frequencyPerSecond to suit your needs.

                            • 11. Re: setInterval problem - I give up
                              SPGAnne Level 1
                              Dear kglad,
                              Thank you for the code snippet. I have done a pile more testing and have some more to do. There are many places where this level of accuracy/inaccuracy will be OK, but I have one case (so far) where it is most definitely not, where I need accuracy for things in the range of 10-24 occurrences per second. I can be off as much as 4 per second on the high end of the target range (i.e. I ask for 24 and I get 20 instead). I did some other testing using a loop in a movie clip with a document rate of 24 fps to call a function, and that may be more tolerable. So now comes another question on another topic...How do I call a method of an object that instantiated the clip?

                              In other words, I have a class that has a constructor that creates an empty movie clip then loads a .swf into that clip. The .swf has 2 frames that loop and then a 3rd frame that just says stop(). The second frame loops to the first frame. On the first frame I want to call a method/function like "timeTick" (like the setInterval does) of the object that had loaded it in the first place. Can I do that? If so how?

                              Again your patient help is very much appreciated.
                              • 12. Re: setInterval problem - I give up
                                kglad Adobe Community Professional & MVP
                                your empty movieclip (that's the target into which your swf is loaded) must have a path and instance name (say, path.instanceName). you would reference that function timeTick in your swf (AFTER loading is complete and your swf has initialized - ie, use onLoadInit() if you're using the moviecliploader class to load your swf) by:

                                path.instanceName.timeTick();
                                • 13. Re: setInterval problem - I give up
                                  SPGAnne Level 1
                                  Dear kglad,
                                  Thank you again for your patient help. Sorry if I didn't make things clear enough the first time around or if I'm doing something so dumb I don't even know how dumb it is. But here's what I want to do. I have a class as follows:
                                  class TimeTester {
                                  private var timer_mc:MovieClip;

                                  public function TimeTester(target_mc:MovieClip) {
                                  trace("constructor creating the empty movie clip for target " + target_mc);
                                  var my_mcl:MovieClipLoader = new MovieClipLoader();
                                  var mclListener:Object = new Object(); // Create listener object
                                  var thisObj:Object = this; // need this so that the onLoadInit function can access instance variables

                                  mclListener.onLoadInit = function(target_mc:MovieClip, status:Number):Void {
                                  trace("constructor onLoadInit done: initialized timer_mc to: " + thisObj.timer_mc);
                                  trace("total frames is " + thisObj.timer_mc._totalframes);
                                  }
                                  my_mcl.addListener(mclListener);
                                  timer_mc = target_mc.createEmptyMovieClip("timer_mc",1);
                                  my_mcl.loadClip("timerloop.swf", timer_mc);
                                  }
                                  public function timeTick():Void {
                                  trace("tick at time " + getTimer() );
                                  }
                                  }

                                  You can see I'm loading a .swf called timerloop.swf. It has 3 frames. Frame 1 I want to have code that invokes timeTick method. Frame 2 has: gotoAndPlay(_currentframe - 1); and frame 3 has: stop();

                                  My test .fla just has the following:
                                  var my_Timer:TimeTester = new TimeTester(this);

                                  So what I can't figure out is how to call the timeTick method since the timerloop.swf that is loaded by the TimeTester class doesn't know anything about the instance name that loaded it in the first place.

                                  Am I thinking about this problem in the wrong way? Also I am still bumming out about the setInterval stuff being so unreliable. Is there anyway in Flash for a programmer to write an extension in C++ and link it into the runtime in some fashion so that I could get a reliable timer capability? Simulation work by it's very nature calls for precision.
                                  • 14. Re: setInterval problem - I give up
                                    Peter Lorent Level 2
                                    Anne,
                                    Why create a new object to serve as a listener when you already have an object (TimeTester)? You can simplify the code and setup methods onLoadStart, onLoadComplete, onLoadInit and onLoadError for the MovieClipLoader events.
                                    Create a new instance of TimeTester and then load the timerloop.swf:
                                    in the test.fla
                                    var my_Timer:TimeTester = new TimeTester(this);
                                    my_Timer.LoadSwf("timerloop.swf");
                                    You can use a public static method to call timeTick from the loaded swf:
                                    in the timerloop.fla
                                    TimeTester.timeTick();

                                    • 15. Re: setInterval problem - I give up
                                      SPGAnne Level 1
                                      LuigiL to me rescue yet again. Thank you too for helping out.

                                      I tried what you suggested, and am very pleased to simplify. Maybe after enough examples and corrections of my stumblings I will start thinking about things in the right way for Flash. All you provided worked just great.

                                      But when I tried to take it to the next level, I ran into another snag with this implementation. I really would like to broadcast/dispatch an event when timeTick happens to various listeners who live in the .fla that instantiated the timer to begin with. But when I tried to do that, I got errors in compile saying I wasn't allowed to access instance variables inside a static function.

                                      So maybe I should back up and state my high level goal since maybe I'm thinking about this totally in the wrong way. At the highest level I need accurate, dependable timer objects I can use in a variety of ways to drive a variety of different features in my stuff. I need to be able to start the timer indicating at what interval I want to be notified either one time , in a loop or for a certain duration of time, and obviously stop the timer as needed. Sometimes I will use a timer inside another object/class to make some internal function work, sometimes I may want it to be used from the timeline of some .swf. I was going down the path of building such a Timer object using setInterval as the mechanism to generate time ticks. All was going very well until I discovered that it isn't very reliable. That's when I thought I might try using the frame looping mechanism of a .swf to generate a perhaps more predictable time interval. Thus the design I'm pursuing with the last bit of code. (I actually did an experiment using this design (external to making it a class) that showed it was more reliable for one of my needs.)

                                      Again, I very much appreciate all the help I'm getting from you gurus.

                                      • 16. Re: setInterval problem - I give up
                                        Peter Lorent Level 2
                                        Anne,
                                        Maybe it's not exactly what you need but it could be a starting point. Attached a class that is used to time your events. When I use the example I already send you by email, I have the following code on the timeline of hotspot.fla:
                                        var head:Head=new Head(this,woman_mc);
                                        var time:TimeTracker=new TimeTracker();
                                        time.addEventListener("heartFailure",this);
                                        time.broadcastMessage("heartFailure",2000,1);

                                        function heartFailure(evt:Object):Void{
                                        trace("Message: Heart Failure!");
                                        }

                                        With the attached class I get the following results in the output panel:
                                        78
                                        Message: Heart Failure!
                                        Elapsed time= 2081

                                        Haven't tested extensively but it seems quite accurate. If this is a feasible setup for you, maybe kglad can help you refine the timeTrack method.