variables undefined after assignment - javascript

I am a beginner level javascript programmer. I can't find a reason why there is undefined values for the winX and WinY variables in the following function:
var game = new Phaser.Game(
800,
600,
Phaser.AUTO,
'game',
{ init: init,
preload: preload,
create: create,
update: update,
randomizeWin: randomizeWin,
myMethod: myMethod
}
);
function init() {
this.sss=56;
this.marginX=150;
this.marinY=100;
}
function preload() {
var wood = game.load.image('wood', 'assets/wood.jpg');
randomizeWin();
console.log(this.winY);
}
function create() {
this.p=[];
for(var i=0;i<3;i++) {
this.p[i]=[];
for(var j=0;j<3;j++){
this.p[i][j]= game.add.sprite(this.marginX+i*170, this.marinY+j*170, 'wood');
this.p[i][j].scale.x=0.2;
this.p[i][j].scale.y=0.2;
this.p[i][j].anchor.setTo(.5,.5);
this.p[i][j].inputEnabled = true;
this.p[i][j].input.useHandCursor = true;
this.p[i][j].events.onInputDown.add(myMethod, this);
}
}
}
function update() {
}
function myMethod(sprite) {
console.log(this.p[this.winX][this.winY]==sprite);// winX is undefined here why??
if(this.p[this.winX][this.winY]==sprite){
game.add.tween(sprite.scale).to ({
x: sprite.scale.x * -1,
// y: sprite.scale.y * -1
}, 1000, Phaser.Easing.Bounce.Out, true);
}
}
function randomizeWin() {
console.log("rand");
this.winX = Math.floor(Math.random() * 3);
this.winY = Math.floor(Math.random() * 3);
}
What is happening here and how to fix it?

The value of this depends on the calling context.
You'd either need to bind the object in question, roughly:
this.p[i][j].events.onInputDown.add(myMethod.bind(this), this);
(But as your code currently stands this would have the same issue) or rely on whatever the framework in question provides in the way of binding.
Welcome to JS.

Using this on JS opens up a whole world of pain. You should avoid it until you are really sure how it works or rename it to something else on your scope:
var self = this;
function create() {
self.p = [];
//etc
}
function randomizeWin(){
self.winX = Math.floor(Math.random() * 3);
self.winY = Math.floor(Math.random() * 3);
}
function myMethod(sprite){
console.log(self.p[self.winX][self.winY]==sprite);
}

Related

Cannot access variable in object from outside

I didn't succeed in accessing the variable playing from outside the object Pong:
Pong = {
// some other objects
initialize: function (runner, cfg) {
Game.loadImages(Pong.Images, function (images) {
this.cfg = cfg;
this.runner = runner;
this.width = runner.width;
this.height = runner.height;
this.images = images;
this.playing = false; // variable is defined here
this.scores = [0, 0];
this.menu = Object.construct(Pong.Menu, this);
this.court = Object.construct(Pong.Court, this);
this.leftPaddle = Object.construct(Pong.Paddle, this);
this.rightPaddle = Object.construct(Pong.Paddle, this, true);
this.ball = Object.construct(Pong.Ball, this);
this.sounds = Object.construct(Pong.Sounds, this);
this.runner.start();
} .bind(this));
},
// some more functions
isPlaying: function () { // I added this function to enable for access
return this.playing; // here playing is undefined
},
start: function (numPlayers) {
if (!this.playing) { // here playing is defined
this.scores = [0, 0];
this.playing = true;
this.leftPaddle.setAuto(numPlayers < 1, this.level(0));
this.rightPaddle.setAuto(numPlayers < 2, this.level(1));
this.ball.reset();
this.runner.hideCursor();
}
},
// more objects and functions
This is a pingpong game. The complete page is this:
http://ulrichbangert.de/div/webdesign/javascript/pong.html I cannot understand why this variable can be accessed in start and not in isPlaying.
Why is this and what code do I have to use to access this variable? To enable for debugging I added calling isPlaying in the onclick event.
This is one of the classic problems with javascript, this changing "unexpectedly".
Inside of that callback, this points to something else, not your object. One of solutions is to trap object reference in a closure.
initialize: function (runner, cfg) {
var that = this; // <= "that" won't change.
Game.loadImages(Pong.Images, function (images) {
that.cfg = cfg;
that.playing = false;

Javascript: Could access object and show it, but not a valid property of that object?

My console message:
Uncaught TypeError: Cannot read property 'x' of undefined.
However, when I log to the console the snake.head object, it gives me a valid "response"! How could it be that an object is defined but when trying to store a property of that object in a variable it doesn't work? I also tried just continuing the game without storing the x and y position in a variable and instead accessing it within the head object and guess what? Doesn't work. I even tried just accessing the game.SNAKE[game.SNAKE.length-1].(property) but it also doesn't work! However, when I try it in my snake.init function, it works fine, but I can't do this, as my init only runs once!
var game = {};
game.contextBackground = document.getElementById("bgCanvas").getContext("2d");
game.contextSnake = document.getElementById("snakeCanvas").getContext("2d");
game.contextFruit = document.getElementById("fruitCanvas").getContext("2d");
game.keys = [];
game.SNAKE = [];
game.width = document.getElementById("snakeCanvas").width;
game.height = document.getElementById("snakeCanvas").height;
game.COLUMNS = 35;
game.ROWS = 35;
game.boxSide = game.width/game.COLUMNS;
game.snake = {
snakeLength: 3,
tailx: null,
taily: null,
head: null,
headx: null,
heady: null,
direction: "right",
createSnake: function (snakeLength) {
game.SNAKE.length = this.snakeLength;
for (i=0;i<snakeLength;i++) {
game.SNAKE[i] = {
x: i ,
y: 0
};
}
},
updateSnake: function (length) {
this.head = game.SNAKE[length-1];
this.headx = this.head.x;
for (i in game.SNAKE) {
}
},
init: function() {
this.createSnake(this.snakeLength);
},
update: function() {
this.updateSnake(game.SNAKE.length);
console.log(this.head);
for (i in game.SNAKE) {
game.SNAKE[i].x ++;
}
},
render: function() {
game.contextSnake.clearRect(0,0,game.width,game.height);
for (i in game.SNAKE) {
drawBox(game.SNAKE[i].x,game.SNAKE[i].y,game.contextSnake,"green");
}
}
};
game.fruit = {
x: null,
y: null,
newFruitNecessary: true,
init: function() {
},
update: function() {
},
render: function() {
}
};
function init() {
loop();
game.snake.init();
game.fruit.init();
}
function update() {
game.snake.update();
game.fruit.update();
}
function render() {
game.fruit.render();
game.snake.render();
}
function loop() {
setTimeout(function(){
loop();
},1000/10);
update();
render();
}
function drawBox (gridx,gridy,context,color) {
if (color == null) {
color = "black";
}
context.fillStyle = color;
context.fillRect((gridx * game.boxSide), (gridy * game.boxSide), game.boxSide,game.boxSide);
}
init();
You have to init your snake (and later fruit) before you can loop; otherwise, game.SNAKE will point at an empty array, so the lines
this.head = game.SNAKE[length-1];
this.headx = this.head.x;
will fail to work properly when the first update() calls inside your loop(). game.SNAKE is empty, so you store undefined to this.head; thus, this.head.x resolves to undefined.x, which fails.
Try shifting around the lines in init:
function init() {
game.snake.init();
game.fruit.init();
loop();
}

How to define a repeating function in a Javascript prototype?

I'm trying to define a Javascript class with a repeating function but I can't get it to work:
var Repeater = function() {
this.init.apply(this, arguments);
};
Repeater.prototype = {
run: 0, // how many runs
interval: 5, // seconds
init: function() {
this.repeat();
},
repeat: function() {
console.log(++this.run);
setTimeout(this.repeat, this.interval * 1000);
}
};
var repeater = new Repeater();
How should this be done?
Try this code:
var Repeater = function() {
this.run = 0; // how many runs
this.interval = 5; // seconds
this.init.apply(this, arguments);
};
Repeater.prototype.init = function() {
this.repeat();
}
Repeater.prototype.repeat = function() {
var _this = this;
console.log(++this.run);
setTimeout(function () { _this.repeat() }, this.interval * 1000);
};
var repeater = new Repeater();
I've moved run and interval into constructor, because if you add this to prototype then this will be spread over all instances.
Your problem lies into seTimeout - in your code this timer set new scope for repeater and this was no longer pointing to Repeater instance but for Timeout instance. You need to cache this (I've called this cache _this) and call it into new function passed to setTimeout.
Try like that:
var Repeater = function() {
this.init.apply(this, arguments);
};
Repeater.prototype = {
run: 0, // how many runs
interval: 5, // seconds
init: function() {
this.repeat();
},
repeat: function() {
console.log(++this.run);
var that = this;
setTimeout(function() {that.repeat()}, this.interval * 1000);
}
};
var repeater = new Repeater();
You can read more on how this behaves in this question : How does the "this" keyword work?
Change your repeat function to use a closure in the setTimeout call like so:
repeat: function() {
var ctx = this;
console.log(++this.run);
setTimeout(function(){ctx.repeat()}, this.interval * 1000);
}
You need to set the context explicitly in these kinds of scenarios- that's what the ctx variable is for

Object shows properties but accessing them returns undefined

So I'm writing a game, and I've got a module that returns the keys currently being pressed via jQuery. No problems there. The problem comes when I attempt to access the keys pressed:
var Keys = require('./lib/keys')
Player.prototype.update = function () {
Keys(function (err, keydown) {
console.log(keydown, keydown['w']);
/* // To move a player up, for example:
if (keydown['w']) {
this.y += this.speed;
}
*/
});
};
And the console shows that what keys are pressed, but attempting to access one gives me an undefined instead of true.
Object undefined
s: true
w: true
x: true
__proto__: Object
Anyone have any thoughts?
Update: key module
var $ = require('./jquery')
var Keys = function (callback) {
var keydown = {};
function keyName(event) {
return String.fromCharCode(event.which).toLowerCase();
}
$(document).bind('keydown', function (event) {
keydown[keyName(event)] = true;
return false;
});
$(document).bind('keyup', function (event) {
return false;
});
callback(null, keydown);
}
module.exports = Keys;
/*************
* UPDATE *
*************/
This is the final fix:
./lib/keys.js
var $ = require('./jquery')
var Keys = function () {
this.keydown = {};
var keyName = function (event) {
return String.fromCharCode(event.which).toLowerCase();
}
var self = this;
$(document).bind('keydown', function (event) {
self.keydown[keyName(event)] = true;
return false;
});
$(document).bind('keyup', function (event) {
self.keydown[keyName(event)] = false;
return false;
});
};
Keys.prototype.getKeys = function (callback) {
callback(null, this.keydown);
}
module.exports = new Keys;
./lib/player.js
var Keys = require('./keys')
var Player = function (game, keys) {
// stuff
}
Player.prototype.update = function() {
var self = this;
Keys.getKeys(function(err, keys) {
if (keys['w']) {
self.y -= self.speed;
}
if (keys['a']) {
self.x -= self.speed;
}
if (keys['s']) {
self.y += self.speed;
}
if (keys['d']) {
self.x += self.speed;
}
});
That happens because of Keys has asynchronous processes in it.
It's just a known chrome issue that shows the object value by reference. So you see the object value a moment after you call console.log
To see it more clear open chrome webdev tools and put debugger; instead of console.log and see what's actually in keydown object. And I bet it will be just an empty object.
And I'll just leave it here: http://felix-kling.de/blog/2011/08/18/inspecting-variables-in-javascript-consoles/
That will teach me to scan code too fast. The comments are right and this code isn't pointing to the current problem.
The variable this gets reset every time you enter a new function.
Player.prototype.update = function () {
var self = this;
Keys(function (err, keydown) {
console.log(keydown, keydown['w']);
/* // To move a player up, for example:
if (keydown['w']) {
self.y += self.speed;
}
*/
});
};
I don't see any jQuery here. You need to supply more code, such as Keys source code. But I guess that you need to use http://api.jquery.com/event.which/ , for example, keydown.which === 'w'

JavaScript scope issue with this.connection

I have the below JavaScript code. In the function update, the this.connection resolves to undefined instead of a number. What am I doing wrong?
function Net()
{
this.connection = -1;
this.counter = 1;
this.timelastsend = -1;
setInterval( this.update, 3000);
}
Net.prototype.update = function()
{
if (this.connection > 0 && this.timelastsend > 0)
{
var now = new Date().valueOf();
if (now - this.timelastsend > 1000 * 60)
{
}
}
}
One of the problems of using this is that this is dependent on the way you call the function.
setInterval will call your update method as if it were a standalone function, and so this will be set to the global object.
If you really need to use the this functionality, rewrite your call to to setInterval as follows:
function Net() {
var self = this;
this.connection = -1;
this.counter = 1;
this.timelastsend = -1;
setInterval( function () { self.update() }, 3000);
}
This way, you’ll create a self variable which will keep referring to your object (if you’ve created it using the new operator — another reason to avoid this).
Addendum:
If you’re not actively descending lots of objects from your Net pseudoclass, I’d refactor the thing as follows:
function createNet() {
var connection = -1,
counter = -1,
timelastsent = -1,
self,
update;
update = function () {
var now;
if (connection > 0 && timelastsent > 0) {
now = new Date().valueOf();
if (now - timelastsent > 1000 * 60) {
// ... update code ...
counter += 1;
timelastsent = now;
}
}
};
setInterval(update, 3000);
return {
update: update,
getTimeLastSent: function () { return timelastsent; },
getCounter: function () { return counter; },
getConnection: function () { return connection; }
};
}
You’ll notice there is no mention of this anywhere, which means no ambiguity. I’ve included three getters for the connection, counter and timelastsent properties, but if you want those to be writable from outside the object, you could just as easily add them to the created object.

Categories

Resources