Only one ENTER_FRAME

Hi,

Would it be possible to only have one ENTER_FRAME event in a class managing it for the entire app? You could send which functions of which classes you want to be affected by this ENTER_FRAME.

Thank you!

Yes it’s possible. I believe most developers proceed like that.

Usually developers use an Array of IUpdatable. So every classes in the array have an update method and the manager executes it.

Thanks for the reply.

I’m not too sure about how to proceed… In my EnterFrameManager class (which is a singleton), I have my Array that is going to have all classes that have an update method. To “push” those classes in this Array, I have created a “addClass” function. In the end, in a ENTER_FRAME in my EnterFrameManager class, I do this:

private function update(e:Event):Void {
for (i in 0…classes.length) {
classes[i].update();
}
}

What type should be my Array? Dynamic?

And when I want to add a new class to the Array from another class, should I do:
EnterFrameManager.addClass(this);

Thank you!

All you classes could implement the same Interface or inherits the same Class. So Array<IUpdatable> (implements an interface) or Array<System> ( base class inheritance) for example!

Yes, that sounds right. As long as “this” represents the updatable class, that would be the way to do it.

Alright, I think that I’m able to add and remove classes, but when I’m trying to access the “public function update()” of each class, it crashes… Here’s what I’m trying to do in my EnterFrameManager class:

private function update(e:Event):Void {
for (i in 0…classes.length) {
classes[i].update();
}
}

edit: I just did a trace that gave me null… Maybe it’ll help you to help me :smiley: -> trace(classes[0].update);

Going strictly off of the trace, I’m not sure what the problem is.

Could you post two things:

  1. The entire EnterFrameManager class
  2. If you are using a custom interface/class for your classes array typing, post that too.

Thanks for the help! I’m new to coding. Here’s my class:


package;
import openfl.errors.Error;
import openfl.events.Event;
import openfl.events.EventDispatcher;
import openfl.Lib;

class EnterFrameManager extends EventDispatcher{
	private static var instance:EnterFrameManager;
	private static var allowInstantiation:Bool = false;
	
	private var classes:Array<Dynamic>;
	
	public function new() {
		if (allowInstantiation) {
			super();
			classes = new Array<Dynamic>();
			Lib.current.stage.addEventListener(Event.ENTER_FRAME, update);
		}
		else {
			throw new Error("Can't use EnterFrameManager with NEW. Please use EnterFrameManager.\"addClass\"");
		}
	}
	
	private static function getInstance():EnterFrameManager {
		if (instance == null) {
			allowInstantiation = true;
			instance = new EnterFrameManager();
			allowInstantiation = false;
		}
		
		return instance;
	}
	
	private function update(e:Event):Void {
		for (i in 0...classes.length) {
			classes[i].update();
		}
	}
	
	public static function addClass(myClass:Dynamic):Void {
		getInstance()._addClass(myClass);
	}
	
	private function _addClass(myClass:Dynamic):Void {
		classes.push(myClass);
	}
	
	public static function removeClass(myClass:Dynamic):Void {
		getInstance()._removeClass(myClass);
	}
	
	private function _removeClass(myClass:Dynamic):Void {
		classes.splice(classes.indexOf(myClass), 1);
	}
}

Generally speaking, I try to avoid the use of “Dynamic” as a type. I would not get into the habit of using it unless you really think its necessary. You can read a bit more about potential problems on the following page if you haven’t seen it before:

At any rate, there is a much safer way to do this that allows us to catch problems earlier. I would recommend using an interface like this for your array type:

interface Updatable
{
    public function update():Void;
}

Interfaces are like class blueprints. Instead of using them directly, you have actual classes implement them like so:

class DoerOfThing implements Updatable
{
    public function new()
    {
    
    }

    public function update():Void
    {
        // Do something
    }
}

Basically, implementing the interface means that the class is checked for conformance (in this instance, implementing the “update” function) with the interface and will throw a build error if it doesn’t. Once set up, you can use this class anywhere “Updatable” is used as a type.

It is worth mentioning that the implementing class is free to have whatever other fields and functions it wants beyond the “Updatable” blueprint, but the classes array will only recognize public access to the fields and functions defined by its identifying type “Updatable.”

Hope that all makes sense. :slight_smile:

Thank you for the detailed explanation!

If I understand it well, my array in the EnterFrameManager class would have the type < Updatable >.

The only thing that remains a mystery for me is where do I write what… Is the Updatable written besides my EnterFrameManager like this?

interface Updatable
{
    public function update():Void;
}

class EnterFrameManager extends EventDispatcher{
...

And then, where should I write “DoerOfThing”? For example, if I have Hero.hx that needs to be updated each frame.

I think that I understand the general concept, but where to write what is still a bit blurry in my head.

Again, thank you for all the help! I feel that I’m so close!

Oh wait!! I understand! I created Updatable.hx and put only this in it:

package;

interface Updatable {
	public function update():Void;
}

And then, any class that needs to be updated each frame needs to implements Updatable and have:

public function update():Void {
	trace("It works!");
}

Also, a class can extends something AND implements the Updatable like this:

class Hero extends Sprite implements Updatable{
...

Is that the right way to do? Because it seems to work! :smiley:

Yes, that looks like the right way to me.

Yes, you can do both at the same time. Unlike extending classes, you can actually implement as many interfaces as you want, but again you should have good reason for doing so. As mentioned above, you only have public access to the functions and fields associated with the variable’s current identification.

Take a look at the “Hero” class you have, for example. When you access it from the Array variable in EnterFrameManager, it will only recognize access to “Updatable” fields and will not recognize access to “Sprite” fields. Now, once you’re inside the update function internals, you can play with whatever data you want because Hero obviously knows its own classification. The data associated with Sprite still belongs to Hero, but externally the classes array in EnterFrameManager has no reasonable way of knowing that since it isn’t supposed to work with the Sprite class.

In short: Hero is still 100% a Hero class, but for the array’s purposes, Hero is treated strictly as an “Updatable.”

Hope that makes sense.

Yes, it does make sense!

I might rename my class “PhotonGD” instead of “Hero” :laughing:

Thanks for all the explanation!