[SOLVED] Order of update() calls in engine-only version?

Can I (in the engine-only version) control the update order of the scrips attached to the entities like I can do in the Editor?

And will the update event for the application object be fired before or after all the entity updates?

The order of the update of the scripts should be the order that you add them to the script component.

Event order can be found here: Application Lifecycle | Learn PlayCanvas

And the order of the entities is also the order at which you add them? In the Editor you can specify the order in the settings.

I’m not aware that you can in the Editor.

It’s only render layer order and the order that the scripts are concatenated in as part of the build step that you can change in the Editor Settings

So this settings:
afbeelding
Is not ment for the order of the update() function?
Then I misunderstood that.

But in the engine-only case, will the order of the update event be the order at which the entities are added? And within one entity the order at which the script are added to the script component?

Nope. It’s a build step to set the order of scripts being concatenated together. Similar to JS bundlers like rollup and webpack

AFAIK, there’s no entity order as the components are updated by system as shown in the diagram linked to earlier.

If you are asking which order the script components are updated in, I’ve always considered it to be undefined because it’s much easier to structure my code with that assumption. I rely on update and postUpdate calls as much as I can.

If I need an explicit order, I set up a manager or similar in my project that allows me that finer control that I want X entities updated before Y entities.

At the script component level, the scripts are updated in the order they were added to the script component.

There is more info here

Just to add to this. If I did a larger engine only project in PlayCanvas (or Unity), I would avoid using scripts as much as possible. I’d create a single script (lets call it Game) on one object in the scene, and implement its update and postUpdate functions the way that they would call updates and postUpdates on every game system I have.

For example, imagine you have characters and cameras. I’d have class CharacterManager and CameraManager for example, and those would store arrays of their respective objects.

In the Game.update I would do:

update() {
  this.characters.forEach(character => character.update());
  this.cameras.forEach(cam => cam.update());
}

and this defines the execution order.

Internally, each of those objects (Character, Camera …) would keep a reference to the Entity, and the component(s) that are needed.

2 Likes

And why would you it this way? To have more control, or because it is more efficient? Or both?

Both. Having lots of entities with components adds the overhead of calling update functions on those. And manually calling update functions give me access to ordering, that is completely independent of the order of entities in the hierarchy, or order of creation of scripts, which I think is pretty hard to control, and even inspect / change if its not working the way you need to.

And you do not add a script to an entity using the script component at all?
Just having you own object manager class with I assume a reference to the entity itself?

Correct. Those would not be scripts at all, just normal js files. Most likely using ES6 class syntax or typescript and all that. The mentioned Game script would be a typical script though, and it would hold instances of all other classes.

Engine examples are a good (but very simple) example of this. They rarely internally create scripts (other then use existing post-effects and similar). For example here:
https://playcanvas.github.io/#/graphics/mesh-morph

We create meshInstances, and keep references to them, and loop over them to update them. We could have instead create some updater script and attach it to each of them, but it would make it more complicated.

And why wouldn’t that Game stript be an ES6 class too, with an update() function that is called by the callback of the applications update event? Why should you add the game script to an object? (Just to be sure I understand your solution).

Technically, game scripts do not fully support ES6 due to the way they are loaded by the engine and patched. (This was originally designed before ES6 was the norm).

They can be ES6 classes but you will lose some functionality such as hotswapping.

Additionally, game scripts are external files (assets) and are loaded directly by the engine at runtime. So they have to be in a format that the browser can support. ES6 is supported by 98% ish of browsers.

Well you need one script with an update function on some global Entity in the scene. This is to get a single call to update function by the engine. This needs to be a normal script, so not ES6. But all this would do would be to instantiate your main non-script class (in initialize) and call its update (in update), nothing else, very minimal script.
And that root non-script class would be ES6 and add all other mangers / pointers to it.

But isn’t that (more or less) the same as using the update event of the application to call all updates.
This can then be ES6 I assume.

It’s similar, but you have control over the order of updates independent of the hierarchy / creation order. It makes a large difference for large projects.

Ik think my last remark was not clear enough. What I ment is this:

Why not add a listener to the update event of the application object. And in the callback running the for loop to call the update() of each object that you have created before. (and in the order your like).

It is not clear to me why one would need to have at least one script attached to an object just to catch the update call.

sure, events are just fine as well.