Jump to content

global variables and prefabs


Jayguar
 Share

Recommended Posts

So i'm relatively new to JS and Phaser. 

I'm using yeoman to scaffold phaser and it is all working fine...except for global variables.

I'm too new to coding in general to bend everything to my will.

the issue i'm having is trying to get a prefab to talk to the 'play' state.

 

I have a function inside my prefab:

var destroyBacon = function() {	this.destroy();	this.game.score += 1;}; 

the 'this.destroy();' works perfectly.

but I want for every time I use that function (which is every time I click a sprite from that prefab) to add a point to the 'score'.

I get this every time:

Uncaught TypeError: Cannot read property 'score' of null  

I'm not sure if I should even be using the 'this.game.' or where I should put the actual score variable. 

 

Ideally, I'd like each of my prefabs (of sprites) to add to the score.

 

any advice would definitely help.

 

Link to comment
Share on other sites

We'd need to see more code to work out what context it's running in, but it strikes me that your above example shouldn't work, because 'this' in that context would normally be referring to the destroyBacon function itself. You can do console.log(this) wherever you're not sure to find out which object it's referring to, and determine then what you need to do, as 'this' is a tricky beast to newcomers.

Link to comment
Share on other sites

From my understanding 'this.game' referrers to all variables in the game? 

this is pretty much everything in the bacon prefab

'use strict';var Bacon = function(game, x, y, frame) {	Phaser.Sprite.call(this, game, x, y, 'bacon', frame);	this.anchor.setTo(0.5, 0.5);	this.game.physics.arcade.enableBody(this);	this.body.collideWorldBounds = true;	this.body.bounce.setTo(1, 1);	this.body.velocity.x = this.game.rnd.integerInRange(-500, 500);	this.body.velocity.y = this.game.rnd.integerInRange(-500, 500);	this.inputEnabled = true;	this.events.onInputDown.add(destroyBacon, this);  };var destroyBacon = function() {	this.destroy();	this.game.score += 1;};

and this is the code in the play state

  'use strict';  var Bacon = require('../prefabs/bacon');  this.score = 0;    function Play() {}  Play.prototype = {    create: function() {      this.game.physics.startSystem(Phaser.Physics.ARCADE);      var baconGroup = this.game.add.group();      var bacon = new Bacon(this.game, this.game.world.randomX, this.game.world.randomY);      baconGroup.add(bacon);            this.labelScore = this.game.add.text(this.game.world.centerX, 200, 'the score ' + this.score, { font: '16px Arial', fill: '#ffffff', align: 'center'});    }, 

It doesn't even work where it is, but should I be putting the score variable somewhere else since I would like to reference it in other states (like the state for level 2)?

Link to comment
Share on other sites

Interesting coding style there - not seen this before, but I assume it's require.js or some kind of module system? Can you try this instead for your prefab:

var Bacon = function(game, x, y, frame) {	Phaser.Sprite.call(this, game, x, y, 'bacon', frame);	this.anchor.setTo(0.5, 0.5);	this.game.physics.arcade.enableBody(this);	this.body.collideWorldBounds = true;	this.body.bounce.setTo(1, 1);	this.body.velocity.x = this.game.rnd.integerInRange(-500, 500);	this.body.velocity.y = this.game.rnd.integerInRange(-500, 500);	this.inputEnabled = true;	this.events.onInputDown.add(this.destroyBacon, this);  };Bacon.prototype = Object.create(Phaser.Sprite.prototype);Bacon.prototype.constructor = Bacon;Bacon.prototype.destroyBacon = function() {	this.destroy();	this.game.score += 1;};

This ties destroyBacon to the Bacon object's prototype and ensures instances have access to the same properties the constructor does. This style is more in line with how Phaser itself is written and makes things a little easier to work out, as you've no need then to try and pass the context to an otherwise unrelated function.

 

As for storing simple properties on game or on the states, that's fine for small projects, but I'd recommend creating dedicated object managers for this to keep things modular for larger projects. Maybe create a new Score object in a similar way which has methods for adding a point, resetting, updating a text object as well as properties containing the score value and so on.

Link to comment
Share on other sites

Just to add to that, with the above example, score would be a property of game, so the correct text update code would be:

      this.labelScore = this.game.add.text(this.game.world.centerX, 200, 'the score ' + this.game.score, { font: '16px Arial', fill: '#ffffff', align: 'center'});
Link to comment
Share on other sites

Yhank you for your help, it is much appreciated. 

I'm still stuck though. I've been doing some research on prototype, constructors and closures so I can better understand everything that is going on. It makes a lot more sense now, but I'm still trying to learn.

 

In my project, I'm still getting:

Uncaught TypeError: Cannot read property 'score' of null

I'm sorry to ask you to spoon feed me haha but where is the best place to place my score variable? Also, will it need to have anything besides 'var score = 0;' ?

 

I'd like to get to the point where I can try to solve actual problems and not figuring my way around the language. So again, Thank you for assisting me.

Link to comment
Share on other sites

It's hard to get a feel for scope with your examples as they don't show the full picture, but I'd assume if any previous references to this.game are working then adding a score property to it would work too, and that property would be retrievable anywhere else the game object is available. It's important to understand the distinction between a variable and a property though, and where you can access each. The states for instance are usually set up like this:

// this is the 'namespace', just an object that neatly contains all the game objects - the {} bit is just an empty objectvar MyGame = {};// this is the state itself, which is just a function which is passed your game instance - internally Phaser calls this like 'new MyGame.State(game)', creating a new instance of itMyGame.State = function(game) {  // we make 'test' a property of the state  this.test = "Test";};// here are all of your state's functions - and this is where it gets a bit tricky!MyGame.State.prototype = {  // this is a function defined as a property on the state (don't worry about the prototype bit for now)  preload: function() {    // inside any of these functions, 'this' is the current state, so this works fine    this.doSomething();    // using var on the other hand limits the variable ONLY to this function    var message = "This is a message";  },  doSomething: function() {    // 'message' defined above cannot be seen by this function, so the second part of this console.log will come out as 'undefined'    console.log("I did something!", message);  }};// you can also specify state functions like thisMyGame.State.prototype.create = function() {  // again, 'this' inside here can access any of the properties of the state, so we can check and alter the property we set up at the start  if (this.test === "Test") {    this.test = "Hello";  }};

And to demonstrate prototypes here's a practical (if pointless) example:

var Test1 = function() {  // the colour property here will be available on instances only, and default to 'red'  this.colour = "red";};// set is a property of Test1 only, not its instances - in other languages this may be considered a 'static' member if you consider Test1 to be a 'class'Test1.shape = "square";// create a new instancevar test1instance = new Test1;console.log(test1instance.colour, test1instance.shape); // red undefinedconsole.log(Test1.colour, Test1.shape); // undefined squarevar Test2 = function() {  this.colour = "blue";};var test2instance1 = new Test2;// this is a property of Test2's prototype, and can be found on all of its instances only, even ones already created - unless they have a property already called 'shape', in which case they will continue using what's setTest2.prototype.shape = "triangle";var test2instance2 = new Test2;test2instance2.shape = "circle";console.log(test2instance1.colour, test2instance1.shape); // blue triangleconsole.log(test2instance2.colour, test2instance2.shape); // blue circle
Link to comment
Share on other sites

Thank you for your help! It definitely helped me move my thought process forward. This line definitely helped me wrap my head around the questions I was asking:

 

 

 It's important to understand the distinction between a variable and a property though,

it also has made me think about object managers.

 

I have realized I should probably simplify my game until I have more experience with all of this. I'm probably going to just focus on making the game within the play state and learn how to make modular parts when I'm more experienced.

 

Prototype makes way more sense now though, and even though I understand it, I think I'll need to play around with it to perfect it.

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...