Help with events and printing the value (Console: NaN)

Hello, im learning Playcanvas/js and i came across a problem that i dont understand. Its not and error but i just cant get it to work. Im trying to have one script(GameManager) with all variables and setup that i need, score will be there also. GameManager is reciever and other objects like coins are Emiters. So when i collect coin/keyboard key im raising an event and my GameManager reacts and prints console logs but he does not increment my score, insted it prints NaN. If i put same piece of code anywhere else it works and “this,score” works just fine. What am i missing here? this is my demo : https://playcanvas.com/editor/scene/877406 . For recreating problem just play the game, open console and hit "A"on the keyboard.

GameManager.js

var GameManager = pc.createScript('gameManager');

GameManager.attributes.add('coin', {
    type: 'entity' 
});

GameManager.attributes.add('score', {
    type: 'number',
    default: 1
});

// initialize code called once per entity
GameManager.prototype.initialize = function() {
    
    
    var onClicked = function() {
        console.log('onClicked has been called!');
        this.score++;
        console.log(this.score);
    }; 
    
    this.app.on('emitEvent:myevent', onClicked);
};

// update code called every frame
GameManager.prototype.update = function(dt) {
    //console.log(this.score);
};

EventEmit.js

var EventEmit = pc.createScript('eventEmit');

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

// update code called every frame
EventEmit.prototype.update = function(dt) {
    if(this.app.keyboard.wasPressed(pc.KEY_A)){
        
        this.app.fire('emitEvent:myevent');
        console.log('A key has been presed!');
    }
};

Thanks!

Your code in the project has changed, so we don’t see the result you are describing. However, from the code snippet in your post, I would assume the problem is in this.score. In this context this points to onClicked function, not the GameManager. And since you do not define it in onClicked, this.score++ becomes undefined++, which should give you N/A.

If I would to fix it, I would move onClicked to GameManager level:

GameManager.prototype.initialize = function() {
    this.score = 0;
    this.app.on('emitEvent:myevent', this.onClicked, this);
}

GameManager.prototype.onClicked = function() {
    this.score++;
}
1 Like

Hi LeXXik and thank you for your response. yes it changed a little bit because i still tried to fix things. Its very confusing and not that intuitive. All im trying to do is collect something and increment a value… and im having such a bad time… How can i access my gameManager score? Now its working as you suggested. But i dont feel like thats how things should be done… or i might be wrong.

If you look at this:

var GameManager = pc.createScript('gameManager');

GameManager.attributes.add('coin', {
    type: 'entity' 
});

GameManager.attributes.add('score', {
    type: 'number',
    default: 0
});

GameManager.prototype.Calling = function() {
        var app = this.app;
    
        this.score++;
    
        console.log('onClicked has been called!');
       
        console.log(this.score);
  
};

// initialize code called once per entity
GameManager.prototype.initialize = function() {
    
    this.score = this.score;
    this.app.on('emitEvent:myevent', this.Calling, this);
};

// update code called every frame
GameManager.prototype.update = function(dt) {
    console.log(this.score);
};

in Initialize first this.score have nothing to do with game manager score, but after “=” that is score from game manager. And in update im printing what value, from initialize or from GameManager…?

1 Like

Hi @Aetrix!

Try using the Code Highlight formatter when pasting code in a forum post, it helps a lot with readability!

image

For your question, my insight:

  1. Having a single instance of a GameManager attached to an entity in your Hierarchy (e.g. Root) is perfectly fine.
  2. Having that script act as a singleton listening to events fired from other scripts to adjust the score is great and using events for communication is a good practice.
  3. Using editor attributes in the GameManager to set the initial score is great as well. Just note you don’t really need the following line, since this.score will be set to the attribute value automatically:
// not required
this.score = this.score;
1 Like

As an alternative way to write the callback based on your initial version

// initialize code called once per entity
GameManager.prototype.initialize = function() {
    var self = this;
    
    var onClicked = function() {
        console.log('onClicked has been called!');
        self.score++;
        console.log(this.score);
    }; 
    
    this.app.on('emitEvent:myevent', onClicked);
};
1 Like

I think @Leonidas and @yaustar answered your concerns. Some additional points from me:

The following line is simply a convenience assignment:

var app = this.app;

So, for example, instead of:

GameManager.prototype.Calling = function() {
    this.app.fire('one');
    this.app.fire('two');
};

You can write:

GameManager.prototype.Calling = function() {
    var app = this.app;
    app.fire('one');
    app.fire('two');
};

If you don’t use this.app within .Calling method, then you don’t need it, as it will do nothing.

When the Playcanvas initiates all your scripts, the .initialize() function of each is called once. So, when the engine starts GameManager script, it will execute GameManager.prototype.initialize automatically on start.

Edit:
Since you have score as attribute, then GameManager will know about this.score on initialize. You can follow @Leonidas advice here.

2 Likes

score is a script attribute for GameManager.

2 Likes

@yaustar Oh, you are right! My bad! Let me edit my response.

Thank you all for support and your time. I have manage to create scenario that i wanted, have game manager in scene that responds to events, have objects to send evenets and to show that informations like score on screen. Now I have a little more information and i understand batter some things now, especially THIS and CONTEXT in js is beast for it SELF(no pun intended :slight_smile: ). If i have any new questions i will open a new thread, this is done for me and resolved discussion. will also use code formatter. :slight_smile:

3 Likes