A working setInterval()?

Where is the setInterval() in openfl? I got this one from web but this one stucks up when fired and cleared many times by different Objects.

import haxe.Timer;

class GlobalTimer 
{
    public static var timers:Array<Timer> = new Array();
    
    public static function setInterval(func:Dynamic, milliseconds:Int, rest:Array<Dynamic>):Int

    {
        var timer:Timer = new Timer(milliseconds);
        timers.push(timer);
        var id = timers.length - 1;
        timer.run = function() 
        {
            Reflect.callMethod(null, func, rest);

        }
        
        return id;
    }
    
    public static function clearInterval(id:Int) 
    {
        timers[id].stop();
        timers[id] = null;
    }
    
    public static function setTimeout(func:Dynamic, milliseconds:Int, rest:Array<Dynamic>):Int

    {
        var timer:Timer = new Timer(milliseconds);
        timers.push(timer);
        var id = timers.length-1;
        timer.run = function() 
        {
            Reflect.callMethod(null, func, rest);

            clearTimeout(id);
        }
        
        return id;
    }

    public static function clearTimeout(id:Int) 
    {
        timers[id].stop();
        timers[id] = null;
    }

    
}

Ref: http://haxe.1354130.n2.nabble.com/setTimeout-amp-setInterval-td2154729.html

What do you want to use it for?

If it’s for your main game loop then you probably want to listen for an ENTER_FRAME event. Otherwise you’ll want to set up an OpenFL Timer and listen for a timer event from it. Events are the way Flash and OpenFL do most things so it’s worth reading up on them.

I want a timer that i could set identifier, Time() class or ENTER_FRAME does not do it.

You could create a timer using the Timer class and keep a reference to that timer as the identifier?

i did that and surprisingly it does not work. It is as if no indentifier was set. In setInterval() when we properly set the identifier, it does not mess up. The setInterval owns the function that is bound to the identifier.

I’m not sure what you’re trying to do, but could Haxe’s “bind” feature help? Or how about a closure?

import haxe.Timer;

class Main {
    private var timer0:Timer;
    private var timer1:Timer;
    
    private function myFunction(s:String):Void {
        trace(s);
    }
    
    public static function main():Void {
        //Use bind() to specify myFunction's arguments ahead of time.
        timer0 = new Timer(1000);
        timer0.run = myFunction.bind("Another second has passed.");
        
        //Use a closure to keep a running count, passing a different
        //argument to myFunction every time.
        var timer1Count:Int = 0;
        timer1 = new Timer(1000);
        timer1.run = function():Void {
            timer1Count++;
            if(timer1Count == 1) {
                myFunction("1 second has passed.");
            } else {
                myFunction(timer1Count + " seconds have passed.");
            }
        }
        
        //If you want behavior like setTimeout(), just use Timer.delay().
        Timer.delay(function():Void {
            timer0.stop();
        }, 7000);
        
        //You could also pass the stop() function itself, since it
        //takes zero arguments.
        Timer.delay(timer1.stop, 9000);
    }
}

What did you try, and what happens when you try it?

What do you mean you set the identifier? Doesn’t the setInterval() function choose an identifier for you?

And what do you mean by “mess up”?

Please give us some sample code that demonstrates the problem.

1 Like

@player_03: Tried your suggestions, but it does not resolve it. I have got to set an ID to that timers and specifically stop that Timer. In my set up, there are multiple objects running at once, each using the same function but passes different arguments. When this all fires up many many times, the flash players set ups multiple Timer for one Object only, messing animations up. What should happen is, the Time should get deleted when a new Timer tries to animate the same object. I did it in AS3 using the code below:

I prevent messing up setInterval() by doing this in AS3:

intervaliDs:Array = new Array();

   function new(){
          myObj1.addEventListener(MouseEvent.MOUSE_OVER, starter);
          otherObj.addEventListener(MouseEvent.MOUSE_OVER, starter);
          myObj2.addEventListener(MouseEvent.MOUSE_OVER, starter);
          somethingElseClip.addEventListener(MouseEvent.MOUSE_OVER, starter);
   }

   function starter (e:MouseEvent){
          initializer(e.currentTarget, [other vars]);
   }
    
    function initializer (mc:Object,[other vars]){
        clearInterval(intervaliDs[mc.name])
    
        function animateThis(){
               // some code here
                //clearInterval() when some condition is meet
        }
    
    
         intervaliDs[mc.name] = setInterval(animateThis,20);
    }

so when this code is fired, the clearInterval() will specifically clear the setInterval() that was binded to mc.name. So in a way, no setInterval is left running in the background that would do its own animation.

Now I am converting all my code to Haxe, so no setInterval was implemented there, I got to animate using ENTER_FRAME or Timer.

I have tried to set an iD to Timer Events by placing them on an Array. There were some left over animation (Messed up), I could not clear them specifically since Timer.stop() stops only the recent Timer.start().

So here is the summary of my code using Timer (no iDs)

   function new(){
          myObj1.addEventListener(MouseEvent.MOUSE_OVER, starter);
          otherObj.addEventListener(MouseEvent.MOUSE_OVER, starter);
          myObj2.addEventListener(MouseEvent.MOUSE_OVER, starter);
          somethingElseClip.addEventListener(MouseEvent.MOUSE_OVER, starter);
   }

   function starter (e:MouseEvent){
          initializer(e.currentTarget, [other vars]);
   }
    
    function initializer (mc:Dynamic,[other vars]){
        stop()  //this is a problem! you cannot fire this up. it trows error.
        var myTimer = new Timer(20,100);
    
        function animateThis(e:TimerEvent){
               // some code here
                //stop() timer when some condition is meet
        }
       
         myTimer.addEventListener(TimerEvent.TIMER,animateThis);
         myTimer.start();
    }

So when we move the mouse over those object very fast and many times, you got myTimer.start() and myTimer.stop() firing at any moment. Animation stucks up and resumes, and so on. If only I could properly set an identifier to each myTimer.start() and then clear it specifically with myTimer.stop(), things will get resolve. BTW using Arrays to store them did not work in this case.

You could use a Map to store multiple timers, based a key (such as the object) or you could consider a different animation system, such as Actuate, which will let you tween or stop based on object

1 Like

As Joshua said, to replicate this functionality, you want a Map.

private var animations:Map<MovieClip, Timer>;
public function new() {
    animations = new Map<MovieClip, Timer>();
    myObj1.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
    myObj2.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
}

private function onMouseOver(e:MouseEvent):Void {
    if(Std.is(e.currentTarget, MovieClip)) {
        animate(cast e.currentTarget);
    }
}

private function animate(mc:MovieClip):Void {
    var animation:Timer = animations.get(mc);
    if(animation != null) {
        animation.stop();
        animations.remove(mc);
    }
    
    animation = new Timer(20);
    animation.run = runAnimation;
    animations.set(mc, animation);
}

private function runAnimation():Void {
    //Update the animation.
}
1 Like

It works! I thought I would settle for less, not anymore!

Actually, now that I think about it, you can use array access for maps:

var animation:Timer = animations[mc];
animations[mc] = animation;
1 Like

I would do animations based on ENTER_FRAME personally, it’s more likely that the animations will then be in sync with the framerate, instead of looking as if they get stuck if you drop frames.

I would love that too, but we cannot add an ID to ENTER_FRAME.

You don’t need to; the listener is already bound to the movie clip in question.

public function new() {
    myObj1.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
    myObj2.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
}

private function onMouseOver(e:MouseEvent):Void {
    if(Std.is(e.currentTarget, MovieClip)) {
        startAnimation(cast e.currentTarget);
    }
}

private function startAnimation(mc:MovieClip):Void {
    //If the listener is already added, this won't change anything.
    mc.addEventListener(Event.ENTER_FRAME, updateAnimation);
}

private function updateAnimation(e:Event):Void {
    if(!Std.is(mc, MovieClip)) {
        return;
    }
    var mc:MovieClip = cast e.currentTarget;
    
    //...
    
    if(/* ... */) {
        stopAnimation(mc);
    }
}

private function stopAnimation(mc:MovieClip):Void {
    mc.removeEventListener(Event.ENTER_FRAME, updateAnimation);
}

There is no setInterval. Also I find Timer needs to use a lot of lines to handle. So I simply use a blank Actuate class.

Actuate.tween (null, 1, { }).onComplete (trace, "That is 1 second of interval");

You can also use Actuate.timer (1).onComplete(trace, [ "hello" ]);

1 Like