Execute a script asset without needing to spawn a new entity: How wrong is this?

Hello there!

I have found a “solution” for one of my scripting problem, but i don’t know how many “programming laws” i have broken with this since i am a beginner js programmer. I would like some suggestions :sweat_smile:

The problem: I need an easy way to configure many objects in my scene and when i select one of these options something must happen in my game. I think this is what people call “Strategy Pattern” since i don’t what to do an infinite “if else” statement nor a switch to sort this list of events…

Part of this problem i have solved using a JSON attribute (array) to set every option. But i was lacking the most important part: the functionality when that option is selected

In my test I made an script attribute and used the code below to try fire an event and it worked just fine…is it possible i ran into problems if i continue using this way to run scripts on a large project?



I was able to call this function this way without defining it as prototype…but i bet I if do this I may have problems with the “this.” keyword when needed because of his scope referencing the window object


That can work if that method doesn’t require access to the entity/script instance properties. Thing of that method as a global method. You can still access the running application like this:

   const app = pc.Application.getApplication();

Though I’d recommend that you look at events to easily communicate from one script to the other. It will be much easier to work with that in your case:

https://developer.playcanvas.com/en/user-manual/scripting/communication/

I thought about that…i may lose some entity properties in the process…I going to write here what i think that would work using events. I really wanted to be able to encapsulate different actions in different scripts for the sake of maintenance if i need to change it later or improve it

I will post some screenshots soon

Ooook…i think this is a better way to do it…
In my level i have the level script attached to the root because it needs to run when the level opens for debugging purposes.

I have another script called optionScript that will have a json attribute with all info this option should have and a child to be my action handler.

Once my user interacts with this option i will pass down to the handler entity script using a fire/on events

If i swap the script on the child handler it will do something else just like i wanted to do.

What i didn’t get very well its the motive it only works if I put an “setTimeout” in my levelScript. Does the initialize function don’t happen at the same time in every script or they follow an order from the parent script to the children ones?

EDIT: I did a test now:
I created a new script that prints the entity name concatened with “initialize” word with console.log and i noticed the script order + entities order in hierarchy panel influences the intialize function execution order. Interesting…

1 Like

What’s the end goal here? It seems like just having global functions that you can call from anywhere would be enough?

I need an easy way to configure many objects in my scene and when i select one of these options something must happen in my game

What type of configuration are talking about here?

Edit: Looking at the last post, you want to send a data object to scripts that are listening for it? If so, the timeout isn’t needed.

Add the event listener for executeScript on initialize on MyTestScript and in LevelScript, fire the executeScript event with the data on postInitialize

2 Likes

Well…I am trying to make a personalization app that should have plenty customization options to decorate a room. This way i have two types of customization: Add 3D meshes and change their material…since it all will be store in a single entity i would like to have one script that handles the material change on interact and another to handle the mesh spawn

Since my team will have non programmers i want to have a easy setup that can call global functions when the option is selected in order to be able to add any kind of interaction they wish to test in the final product

The first attempt to call functions globally worked, but i won’t be able to use internal script attributes (and calling the prototype object from a .js file seems a bit odd to me for some reason). Using the link Leonidas sent worked better using communication events for what i need.
https://developer.playcanvas.com/en/user-manual/scripting/communication/

The problem with the timeout its: I was calling the event too fast (for debugging purposes) and it was there to wait until every event was bound in the script to be able to call it later.

I learned later the initialize functions follows an order to execute…it depends the script order in the same entity and it starts from the highest entity in the hierarchy to the lowest children. Since i was calling to execute script on the initialize from root it was executing fast than the initialize function from a child entity that was binding an event

I would simply add a global function for this. It looks like you simply have a problem with events order. A common way to do it is to subscribe (this.app.on(...)) to events in initialize method. This way all scripts of all entities from top to down in hierarchy would subscribe to the events they need to listen to. Then, you just fire the main event in postInitialize method. Since it happens after all scripts have initialized, all scripts would be able to listen to it, no matter where they are in the hierarchy.

2 Likes

Thanks! I did another test printing a string on initialize/postInitialize functions from my entities and i noticed that playcanvas run the initialize first from all entities from top do bottom then run the postInit in the same order.

You may find these lifecycle diagrams helpful here :slight_smile:

https://developer.playcanvas.com/en/user-manual/scripting/application-lifecyle/

1 Like