Raxxen Posted February 16, 2014 Share Posted February 16, 2014 Hi all, I am currently trying to use buttons in a game. I followed a tutorial on how to make them and they work well. The only problem is I am getting a problem with scope. I have created a board object then set alot of values using this.values. However when I made my buttons they also used this.values. I am having trouble trying to get it sorted out. Here is my code. Hopefully you can understand this better then my explanation: Board.prototype.setup = function() { //Create all the buttons. var buttonTexture = PIXI.Texture.fromImage("./button.png"); // this just makes a button and a button array. var buttons = []; for (var i = 0; i < this._tokenColors.length; i++) { var button = new PIXI.Sprite(buttonTexture); button.anchor.x = 0.0; button.anchor.y = 0.0; button.buttonMode = true; button.interactive = true; button.position.x = (viewWidth/6) * (i % 6); button.position.y = viewHeight - 100; button.color = this._tokenColors[i]; button.tint = button.color; stage.addChild(button); buttons.push(button); //I tried getting it to use a function in the Board class. button.mousedown = button.touchstart = function(data) { Board.prototype.nextColor(this.color); }; }};//Here is the function it calls when pressedBoard.prototype.nextColor = function (color) { document.getElementById("debug").innerHTML = color + " has been pressed"; this._nextColor = color; //This should set the BOARD'S next color this._ready = true; //This should set the BOARD to ready}I believe what is happening is instead of passing the values to the Board class, it is passing it to the button that calls the function instead. I just have no idea how to fix this. Any help would be greatly appreciated! Lenny Quote Link to comment Share on other sites More sharing options...
Zaidar Posted February 16, 2014 Share Posted February 16, 2014 What if you try :button.mousedown = button.touchstart = function(data) { Board.prototype.nextColor(this.color).bind(this);}; Quote Link to comment Share on other sites More sharing options...
Raxxen Posted February 16, 2014 Author Share Posted February 16, 2014 Hmm... I tried that and it didn't help. I don't know if it will help but you can look at the actual game here: http://www.theboomstickstudios.com/games/OCF. Quote Link to comment Share on other sites More sharing options...
Qqwy Posted February 16, 2014 Share Posted February 16, 2014 Calling a function through the prototype is the same as calling any normal(e.g. not bound to an object) function. In other words, your assumption is correct:-In the button.onmousedown handler, the 'this' object refers to the button.-When the Board.prototype.nextColor() is called inside there, the 'this' object still refers to the button. Passing values to handlers is one of the things that JavaScript is not very good at (and one of the things they try to fix in ECMAScript 6). The solution suggested by many developers is to create a second reference to the Board object, e.g:var thisBoard = this;button.mousedown = button.touchstart = function(data) { thisBoard.nextColor(this.color);};I hope this helps. ~Qqwy Quote Link to comment Share on other sites More sharing options...
Zaidar Posted February 16, 2014 Share Posted February 16, 2014 Hi Qqwy you score a point in fact, it seems to work. Your solution is what I tried to emulate with the use of bind. this code works too and allow not to create a new variable to reference the current board :button.mousedown = button.touchstart = function(data) { this.nextColor(this.color);}.bind(this);(I've discovered bind not a long time ago, so now I try to use it when possible when I encounter a closure problem) Quote Link to comment Share on other sites More sharing options...
xerver Posted February 16, 2014 Share Posted February 16, 2014 Bind is better when used once, scoping a `self` variable is better when the closure is repeated created (which you should try to avoid). Bind recreates *another* closure, so it is more expensive. Quote Link to comment Share on other sites More sharing options...
Raxxen Posted February 16, 2014 Author Share Posted February 16, 2014 Thank Qqwy! That worked perfectly. Xerver you said that a closure repeated created should be avoided. Are you referring to the way I call a loop to make my buttons? If so what's an alternative method? Thanks for your help! Quote Link to comment Share on other sites More sharing options...
1-800-STAR-WARS Posted February 16, 2014 Share Posted February 16, 2014 Thank Qqwy! That worked perfectly. Xerver you said that a closure repeated created should be avoided. Are you referring to the way I call a loop to make my buttons? If so what's an alternative method? Thanks for your help! I think what he means is using bind returns a new function each time its called, so if you're making 100 objects all with bound contexts, it's less efficient than using the 'var that = this;' approach because that will always just be a reference to the object. Raxxen 1 Quote Link to comment Share on other sites More sharing options...
xerver Posted February 17, 2014 Share Posted February 17, 2014 both, when you loop and create a closure each time you are creating `n` new closures that all do the same thing. Unless you *need* the iteration variable in your closure scope you can create a function normally and pass each iteration:function onClick(e) {}for(var i = 0; i < 1000; ++i) { something.on('click', onClick);}That will not only be faster at run time, it will take less memory. To maintain your bound context, create the bound function once:function MyThing() { var boundFunc = this.onClick.bind(this); for(var i = 0; i < 1000; ++i) { button.mousedown = button.touchstart = boundFunc; }}MyThing.prototype.onClick(e) {} Raxxen and 1-800-STAR-WARS 2 Quote Link to comment Share on other sites More sharing options...
Zaidar Posted February 17, 2014 Share Posted February 17, 2014 Oh, ok xerver, thx fort the clarification Quote Link to comment Share on other sites More sharing options...
Raxxen Posted February 17, 2014 Author Share Posted February 17, 2014 Hey, Xerver, When I tried your first method i got the error that the button has no method "on". EDIT: When I tried the second method, I am unsure of how to get the button's colour.Board.prototype.onClick = function(e) { this.nextColor(e.color); //Doesn't work, also tried calling this.color but to no avail};Cheers Quote Link to comment Share on other sites More sharing options...
xerver Posted February 17, 2014 Share Posted February 17, 2014 The argument is an instance of InteractionData (https://github.com/GoodBoyDigital/pixi.js/blob/master/src/pixi/InteractionData.js) not the item you clicked on. Use e.target to get the sprite that was clicked. Quote Link to comment Share on other sites More sharing options...
mwatt Posted February 18, 2014 Share Posted February 18, 2014 It is important to understand that "this" in JavaScript is not the same as "this" in for instance, Java. In JavaScript, the "this pointer" is contextual. It can change due to multiple reasons, the most commonly confusing ones are in timer invoked functions and in events. Quote Link to comment Share on other sites More sharing options...
Raxxen Posted February 24, 2014 Author Share Posted February 24, 2014 Hey all, I ended up getting it to work! Thanks so much for your help. Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.