Best way to communicate between Scripts?

Hi!

I was curious on which is the best practices on Script Communication in PC.

I Come from Unity where normally you get the references to the Script Behaviours whether using find then getComponent<>(). or by declaring them as a public variable and you can assign them in the Editor.

Like if I want to press a button and show another menu in PC, should I have a script for the button that just emits the action and a script on the menu that listens to it and then shows it. Or maybe a MenuManager master script that will FindByName its children and manage it after.

I Know this probably is more of a preference, or maybe im thinking this all wrong. I’d like to know how most of you guys do it. Not only for the menu but to the other parts of the game as well

2 Likes

You can do that in PlayCanvas too.

I tend to use events between scripts via the Entity object or the App object as that allows me to decouple entities and scripts easily.

1 Like

Would you explain this a little more - like to beginning students in school? :^)

My first guess is that using events eliminates the need to do a findByName in order to make the reference. Is that correct? Is there more to it than that?

Thanks a bunch.

1 Like

So there are some ways to “Reference” Entities.

Suppose I want to click a button and then make a menu appear, like a settings menu.
There are some ways to accomplish that.

By Name

You could have a button script that when it’s clicked, you could call:

this.app.root.findByName('Menu');

This would look for an Entity in the Scene Tree named Exactly Menu, and then access the script from there and make it appear. The problem with this approach is that the Name of the Object has to match otherwise it won’t work, in a big project it may become very confusing knowing what needs to be named what without looking at the code.

By Reference

This one I just tried, on the button script you could add a Attribute like this:

ButtonScript.attributes.add('menu', {type: 'entity'});

then you could access the menu script from there, something like this:

this.menu.script.menuScript.method()

Then on the Editor you just drag n drop the menu entity on the Property that would appear on the Script object on the Button Entity.

In this way you won’t have any naming problems as you would with the previous solution but this makes the relationships specific, and you have to manually bind them in the editor, and if you forget to do this, things will also not work.

The Broadcast way

The final way is using events that you may fire from some scripts while other scripts are listening to them.
On the button and menu example, the button would have something like this:

    this.app.fire('menu:open');

and on the Menu script you could have something like this:

    var onOpenMenu = function() {
        // Open the Menu
    };

    // listen for the player:move event
    this.app.on('menu:open', onOpenMenu);

    // remove player:move event listeners when script destroyed
    this.on('destroy', function() {
        this.app.off('menu:open', onOpenMenu);
    });

On this approach you don’t need any explicit reference to anything, it becomes way more easy and flexible, but must be used cautiously because on a larger projects, the number of events being fired may make debugging the game difficult.

This seems to be the preferred way on the PlayCanvas ecosystem, you can read more about it here:
https://developer.playcanvas.com/en/user-manual/scripting/communication/

Sorry I don’t know if it’s clear enough, and @yaustar may correct me if I said anything wrong.

Thanks!

6 Likes

The broadcast way can also be done on any PlayCanvas object (component, script, entity, etc). E.g If two scripts are on an entity, they can communicate/broadcast events via their Entity which keeps the scope of the events small.

This is what I tend to do as it makes scripts very modular.

It be more like as the pc.Script is an instance that belongs to the script component on the Entity.

this.menu.script.menuScript.method();
2 Likes

Thank you very much for the thoughtful reply. Also, thanks to @yaustar as well. I admit that it isn’t fully sticking but I get the general gist.

I’m simply going to have to construct some of my own test projects and play around with the different schemes to really get my head around it as well as the implications. There’s a fuzziness between the language used to describe these things and the way my own brain tends to think about things that needs some work to clarify. I think repetition and working through examples from scratch is the key here for me.

Thanks again.

The playcanvas flappy bird has an example of application events https://playcanvas.com/project/375389/overview/flappy-bird

Events are everywhere in that project but as an example:

  • bird.js die function fires an event: app.fire(‘game:gameover’);
  • game.js is listening to game:gameover and disables the Game Screen and enables the Game Over Screen, among other code.
1 Like