Can I send get button events from buttons without having a script on each button?

I am VERY new to Playcanvas and I’m just trying to set up something where if I click a button it prints an alert message in the browser (nothing more :))

However, I want all the code for the button to be handled in a script (main) that is not attached to the button.

I think I can probably do it if I attach a new script to the button to talk with my main script but is this even necessary? Is there some way I can detect the mousedown event on the button only from the main script?

Basically I don’t want to have millions of scripts for each UI element in my app. Hope you understand.

Cheers

Hi @Grimmy,

That’s a valid request! One way to do so is to leverage Playcanvas events. That is a powerful system to communicate between your different scripts:

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

So for example, you can reuse the btn-state.js script from this example and attach it to your various buttons:

https://developer.playcanvas.com/en/tutorials/ui-elements-buttons/

And on each mouse click the following code will fire a different app-wide event based on the entity name:

BtnStates.prototype.onRelease = function (event) {

   this.app.fire('button:clicked:'+this.entity.name);
}l

On your other scripts you can listen for that event using the following handler:

this.app.on('button:clicked:start', function(){

   // start button clicked

}, this);

this.app.on('button:clicked:settings', function(){

   // settings button clicked

}, this);

As long as your entity names used in your UI are unique, this system will work.

Okay great thanks! Just to clarify though, there is no way I can do this without attaching a new script component to each button? ie, I cant access the mousedown through each button’s element component or something?

If you don’t want to attach any script at all, you can then get references to those entities from your master script.

For example:

var startButton = this.app.root.findByName('Start Button');
startButton.element.on('mouseup', function(){
   // start button clicked
}, this);

Thanks. I just tried this but I get the following error:

Uncaught TypeError: Cannot read property ‘root’ of undefined

Clearly its something obvious so please excuse my noob-ness.
Thanks

That error usually means you are running it somewhere where this.app is undefined.

Can you share some code to take a look?

I have a button object in the scene called Button_Test and I just have a script attached to another entity that looks like this…


var UiBehaviour = pc.createScript('uiBehaviour');

// initialize code called once per entity
UiBehaviour.prototype.initialize = function() {
    
};

// update code called every frame
UiBehaviour.prototype.update = function(dt) {
    
};


//events

var button_test = this.app.root.findByName('Button_Test');

button_test.element.on('mouseup', function()
{
    
   console.log("Hello this is a test debug log. We have begun!");
}, this);

Right, so your code is executing way before the Playcanvas app has been initialized and your entities are available, because it’s running outside of any script method.

Also this.app will always be undefined there.

Try using the following:

var UiBehaviour = pc.createScript('uiBehaviour');

// initialize code called once per entity
UiBehaviour.prototype.initialize = function() {
  
   //events
   var button_test = this.app.root.findByName('Button_Test');

   button_test.element.on('mouseup', function()
   {
      console.log("Hello this is a test debug log. We have begun!");
   }, this);  
};

// update code called every frame
UiBehaviour.prototype.update = function(dt) {
    
};

That works! Okay, I think I’m starting to understand some things now. Much appreciated!

Goes back to reading the documents…

1 Like

What’s the reason for this?