So I have 10 UI Buttons and they all need to do a different thing when clicked on it.
Now I have made 1 script for a button. I want to duplicate this script and rename it. I have renamed the script file but then in the script I see that I need to change a lot of code to. I tried to change all the code and now in the editor I get this error: “Script btnStates is already defined in other asset”.
How can I fix this? And is there an easy way to copy scripts?
Hi @Maarten_deVries,
Well, you can download the script file and reupload it, that will result in two identical .js files in your assets. But that won’t do what you are looking for since each script needs a unique script type name to be used on your entities.
And definitely your approach won’t scale, imagine if you need 50 buttons later. The right way to do that is to use a single script and change the behavior each time the button is clicked.
One way I do this easily is to fire a custom event based on the button name each time the button is clicked:
// When we release the element assign the original texture if
// we are not hovering or the hover texture if we are still hovering
BtnStates.prototype.onRelease = function (event) {
event.element.textureAsset = this.hovered ? this.hoverAsset : this.originalTexture;
this.app.fire('ButtonClicked:'+this.entity.name);
};
Now on any other script I can catch the event for a specific button using its name:
this.app.on('ButtonClicked:Start Game Button', function(){
// add custom logic
}, this);
thank you for your reply. That sounds like a better solution indeed.
I am not really sure what I need to do.
Let me describe what I am trying to do.
I have a Bone object with a camera parented to it. The Bone object has multiple animation files attached to it.
For example:
Animation1
Animation2
Animation3
I have 3 uit Buttons. If I click on Button1 I want to play Animation1, if I click on Button2 I want to play Animation2. etc…
So what do I put in which script where?
Hmm, the code I’ve posted works by replacing the last method in the UI Button example script, found here:
https://developer.playcanvas.com/en/tutorials/ui-elements-buttons/
But I’d say if you find that difficult, try reading first through the User Manual and maybe take a couple of Javascript tutorials to get more comfortable in scripting in PlayCanvas.
I have a c# background in Unity. All the javascript tutorials I find online are about making website functianality. Nothing really related to game design / playcanvas. I can only use the example files you have on the tutorials page. Let me try to describe my problem as clear as possible.
1 Like
I have to objects. 1 is a UI Button called “Start Game Button” 2 is an animated Bone object with a camera attached to it.
I have 2 scripts. “BtnStates.js” which I have atteached to the UI Button “Start Game Button” and “PlayAnimation.js” which I have attached to the “Root” entity.
These are the 2 scripts:
var PlayAnimation = pc.createScript('playAnimation');
// initialize code called once per entity
PlayAnimation.prototype.initialize = function() {
};
// update code called every frame
PlayAnimation.prototype.update = function(dt) {
};
this.app.on('ButtonClicked:Start Game Button', function(){
// add custom logic
this.app.root.findByName("AnimationCamera").animation.play("1:START-ENTRENCE|7:ENTRENCE-LEFT.glb", 0.8);
}, this);
and
var BtnStates = pc.createScript('btnStates');
BtnStates.attributes.add('hoverAsset', {
type:'asset',
assetType:'texture'
});
BtnStates.attributes.add('activeAsset', {
type:'asset',
assetType:'texture'
});
// initialize code called once per entity
BtnStates.prototype.initialize = function() {
// Get the original button texture
this.originalTexture = this.entity.element.textureAsset;
// Whether the element is currently hovered or not
this.hovered = false;
// mouse events
this.entity.element.on('mouseenter', this.onEnter, this);
this.entity.element.on('mousedown', this.onPress, this);
this.entity.element.on('mouseup', this.onRelease, this);
this.entity.element.on('mouseleave', this.onLeave, this);
// touch events
this.entity.element.on('touchstart', this.onPress, this);
this.entity.element.on('touchend', this.onRelease, this);
};
// When the cursor enters the element assign the hovered texture
BtnStates.prototype.onEnter = function (event) {
this.hovered = true;
event.element.textureAsset = this.hoverAsset;
// set our cursor to a pointer
document.body.style.cursor = 'pointer';
};
// When the cursor leaves the element assign the original texture
BtnStates.prototype.onLeave = function (event) {
this.hovered = false;
event.element.textureAsset = this.originalTexture;
// go back to default cursor
document.body.style.cursor = 'default';
};
// When we press the element assign the active texture
BtnStates.prototype.onPress = function (event) {
event.element.textureAsset = this.activeAsset;
};
// When we release the element assign the original texture if
// we are not hovering or the hover texture if we are still hovering
BtnStates.prototype.onRelease = function (event) {
this.app.fire('ButtonClicked:'+this.entity.name);
event.element.textureAsset = this.hovered ? this.hoverAsset : this.originalTexture;
};
Now I get this error when I launch the scene:
“Uncaught TypeError: Cannot read property ‘on’ of undefined” in the “PlayAnimation.js” script.
I hope you can help me out with this.
Right, you need to put that event listener inside your script methods. You can’t generally use this
in JS outside an object scope.
var PlayAnimation = pc.createScript('playAnimation');
// initialize code called once per entity
PlayAnimation.prototype.initialize = function() {
this.app.on('ButtonClicked:Start Game Button', function(){
// add custom logic
this.app.root.findByName("AnimationCamera").animation.play("1:START-ENTRENCE|7:ENTRENCE-LEFT.glb", 0.8);
}, this);
};
Thanks for the quick response.
I have added a console.log to my PlayAnimation.js script to see if the event gets triggered.
However in the console I don’t see the message that I have added in my console.
What am I missing.
var PlayAnimation = pc.createScript('playAnimation');
// initialize code called once per entity
PlayAnimation.prototype.initialize = function() {
this.app.on('ButtonClicked:Start Game Button', function(){
// add custom logic
console.log("button clicked");
this.app.root.findByName("AnimationCamera").animation.play("1:START-ENTRENCE|10:LEFT-LOUNGE.glb", 0.8);
}, this);
};
// update code called every frame
PlayAnimation.prototype.update = function(dt) {
};
Not sure, the code seems correct, can you share a sample project url to take a look?
1 Like
With a quick look your button is named StartGameButton and not Start Game Button.
That means that the event listener should be updated to:
this.app.on('ButtonClicked:StartGameButton', function(){
Try that for a start.
1 Like
yea sorry I renamed it to that I tought that that would maybe fix it. But that did not.
The script component in your button entity is disabled, that means that the btnStates
script isn’t enabled.
Enable it and it will work:


thank you very much that did the trick! I didn’t notice that button. I saw the that “btnStates” was set to “On” and is green.
Won’t make this mistake again. Thanks for helping me out.
1 Like