Javascript constructor variable NAN inside function - javascript

I've tried to trace through all the possibilities of what's happening, but I'm learning Javascript so it has to be something I just don't know. The specific issue lies within the pongGame constructor/function; however, I have included my entire code just encase it is necessary. I would assume that, inside my gameLoop function which declared within the pongGame constructor, the variable pongGame.delta would be equal to 10; For, that is what I declared it to be. However, it is equal to NaN. What exactly is the issue that is happening here? Thanks :)
var keys = [false, false, false, false];
var cavnas = document.getElementById("canvas");
var context = cavnas.getContext("2d");
(function() {
startUp();
})();
function startUp() {
resize();
window.addEventListener("resize", resize);
var game = new pongGame();
game.start();
}
function resize() {
document.getElementById("canvas").width = window.innerWidth;
document.getElementById("canvas").height = window.innerHeight;
}
function pongGame() {
this.delta = 10;
this.lastTime = 0;
this.ball = new ball();
this.start = function() {
this.gameLoop();
}
this.update = function() {
this.ball.update();
}
this.render = function() {
context.clearRect(0, 0, window.innerWidth, window.innerHeight);
this.ball.render();
}
var pongGame = this;
this.gameLoop = function(timestamp) {
console.log(pongGame.delta); // 10
pongGame.delta += timestamp - pongGame.lastTime;
while (pongGame.delta > (1000 / 60)) {
pongGame.update();
pongGame.delta -= (1000/60);
}
pongGame.render();
pongGame.lastTime = timestamp;
requestAnimationFrame(pongGame.gameLoop);
}
}
function paddle() {
}
function ball() {
this.x = 1;
this.y = 1;
this.xspeed = 1;
this.yspeed = 1;
this.size = 10;
this.update = function() {
if (this.x == 0 || this.x == window.innerWidth - this.size) {
this.xspeed = -this.xspeed;
}
if (this.y == 0 || this.y == window.innerHeight - this.size) {
this.yspeed = -this.yspeed;
}
this.x += this.xspeed;
this.y += this.yspeed;
}
this.render = function() {
context.beginPath();
context.arc(this.x, this.y, this.size, 0, Math.PI * 2);
context.fill();
}
}

The first time you call gameLoop you do not pass a timestamp so this expression pongGame.delta += timestamp - pongGame.lastTime; sets delta to NAN the first time its ran and then all subsequent runs (which have a timestamp) since its already NAN.
Maybe call it with 0 the first time
this.start = function() {
this.gameLoop(0);
}

Related

How can I reverse the direction of this square after it reaches a certain value?

I'm trying to create an idle animation where the red rectangle moves back and forth slightly in a loop. For some reason once it reaches the specified threshhold instead of proceeding to move in the opposite direction, it just stops.
What did I do wrong?
<canvas id="myCanvas" width="1500" height="500" style="border:1px solid #c3c3c3;">
Your browser does not support the canvas element.
</canvas>
<script>
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
// Spaceship structure
var shipWidth = 250;
var shipHeight = 100;
// Canvas parameters
var cWidth = canvas.width;
var cHeight = canvas.height;
// Positioning variables
var centerWidthPosition = (cWidth / 2) - (shipWidth / 2);
var centerHeightPosition = (cHeight / 2) - (shipHeight / 2);
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
function drawShip(){
ctx.clearRect(0, 0, cWidth, cHeight);
ctx.fillStyle = "#FF0000";
ctx.fillRect(centerWidthPosition,centerHeightPosition,shipWidth,shipHeight);
centerWidthPosition--;
if (centerWidthPosition < 400){
++centerWidthPosition;
}
requestAnimationFrame(drawShip);
}
drawShip();
</script>
#TheAmberlamps explained why it's doing that. Here I offer you a solution to achieve what I believe you are trying to do.
Use a velocity variable that changes magnitude. X position always increases by velocity value. Velocity changes directions at screen edges.
// use a velocity variable
var xspeed = 1;
// always increase by velocity
centerWidthPosition += xspeed;
// screen edges are 0 and 400 in this example
if (centerWidthPosition > 400 || centerWidthPosition < 0){
xspeed *= -1; // change velocity direction
}
I added another condition in your if that causes the object to bounce back and forth. Remove the selection after || if you don't want it doing that.
Your function is caught in a loop; once centerWidthPosition reaches 399 your conditional makes it increment back up to 400, and then it decrements back to 399.
here is another one as a brain teaser - how would go by making this animation bounce in the loop - basically turn text into particles and then reverse back to text and reverse back to particles and back to text and so on and on and on infinitely:
var random = Math.random;
window.onresize = function () {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.onresize();
var ctx = canvas.getContext('2d');
ctx.font = 'bold 50px "somefont"';
ctx.textBaseline = 'center';
ctx.fillStyle = 'rgba(255,255,255,1)';
var _particles = [];
var particlesLength = 0;
var currentText = "SOMETEXT";
var createParticle = function createParticle(x, y) {_particles.push(new Particle(x, y));};
var checkAlpha = function checkAlpha(pixels, i) {return pixels[i * 4 + 3] > 0;};
var createParticles = function createParticles() {
var textSize = ctx.measureText(currentText);
ctx.fillText(currentText,Math.round((canvas.width / 2) - (textSize.width / 2)),Math.round(canvas.height / 2));
var imageData = ctx.getImageData(1, 1, canvas.width, canvas.height);
var pixels = imageData.data;
var dataLength = imageData.width * imageData.height;
for (var i = 0; i < dataLength; i++) {
var currentRow = Math.floor(i / imageData.width);
var currentColumn = i - Math.floor(i / imageData.height);
if (currentRow % 2 || currentColumn % 2) continue;
if (checkAlpha(pixels, i)) {
var cy = ~~(i / imageData.width);
var cx = ~~(i - (cy * imageData.width));
createParticle(cx, cy);
}}
particlesLength = _particles.length;
};
var Point = function Point(x, y) {
this.set(x, y);
};
Point.prototype = {
set: function (x, y) {
x = x || 0;
y = y || x || 0;
this._sX = x;
this._sY = y;
this.reset();
},
add: function (point) {
this.x += point.x;
this.y += point.y;
},
multiply: function (point) {
this.x *= point.x;
this.y *= point.y;
},
reset: function () {
this.x = this._sX;
this.y = this._sY;
return this;
},
};
var FRICT = new Point(0.98);//set to 0 if no flying needed
var Particle = function Particle(x, y) {
this.startPos = new Point(x, y);
this.v = new Point();
this.a = new Point();
this.reset();
};
Particle.prototype = {
reset: function () {
this.x = this.startPos.x;
this.y = this.startPos.y;
this.life = Math.round(random() * 300);
this.isActive = true;
this.v.reset();
this.a.reset();
},
tick: function () {
if (!this.isActive) return;
this.physics();
this.checkLife();
this.draw();
return this.isActive;
},
checkLife: function () {
this.life -= 1;
this.isActive = !(this.life < 1);
},
draw: function () {
ctx.fillRect(this.x, this.y, 1, 1);
},
physics: function () {
if (performance.now()<nextTime) return;
this.a.x = (random() - 0.5) * 0.8;
this.a.y = (random() - 0.5) * 0.8;
this.v.add(this.a);
this.v.multiply(FRICT);
this.x += this.v.x;
this.y += this.v.y;
this.x = Math.round(this.x * 10) / 10;
this.y = Math.round(this.y * 10) / 10;
}
};
var nextTime = performance.now()+3000;
createParticles();
function clearCanvas() {
ctx.fillStyle = 'rgba(0,0,0,1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
(function clearLoop() {
clearCanvas();
requestAnimationFrame(clearLoop);
})();
(function animLoop(time) {
ctx.fillStyle = 'rgba(255,255,255,1)';
var isAlive = true;
for (var i = 0; i < particlesLength; i++) {
if (_particles[i].tick()) isAlive = true;
}
requestAnimationFrame(animLoop);
})();
function resetParticles() {
for (var i = 0; i < particlesLength; i++) {
_particles[i].reset();
}}

What does this certain function refer to?

I was analyzing this piece of code (new to javascript) that is part of a simple flappy bird game but cant figure out what does this function this.x = width refer to. Exactly what does the width mean.
Some context
function Pipe() {
this.spacing = 175;
this.top = random(height / 6, 3 / 4 * height);
this.bottom = height - (this.top + this.spacing);
this.x = width;
this.w = 80;
this.speed = 4 ;
this.highlight = false;
this.hits = function(bird) {
if (bird.y < this.top || bird.y > height - this.bottom) {
if (bird.x > this.x && bird.x < this.x + this.w) {
this.highlight = true;
return true;
}
}
this.highlight = false;
return false;
}
this.show = function() {
fill(255);
if (this.highlight) {
fill(255, 0, 0);
}
rect(this.x, 0, this.w, this.top);
rect(this.x, height-this.bottom, this.w, this.bottom);
}
this.update = function() {
this.x -= this.speed;
}
this.offscreen = function() {
if (this.x < -this.w) {
return true;
} else {
return false;
}
}
}
I would really appreciate if someone could help me with this one.
In this case, width is referencing a variable that must have been defined outside of Pipe() function. Same goes for height.

cannot read property of undefined javascript and OOP

I have an object (a function) called 'Game' which has a prototype method called 'gameLoop.' I need this loop to be called in an interval, so I attempt to do this:
setInterval(game.gameLoop,setIntervalAmount);
but receive a "TypeError: Cannot read property 'clearRect' of undefined(…)"
Here is the prototype method:
Game.prototype.gameLoop = function()
{
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
I am still having difficulty understanding Object Oriented Programming in Javascript. I had a working version where the function was just a regular function and I passed in a game object. Any ideas?
By the way, here is some additional code that may be helpful.
function Sprite(imgg,w,h)
{
this.img = imgg;
this.x = 350;//Math.random()*700;
this.y = 350;//Math.random()*700;
this.vx = 0;//Math.random()*8-4;
this.vy = 0;//Math.random()*8-4;
this.width = w;
this.height = h;
this.rotatespeed = 0.01;
this.rotate = 40;
}
Sprite.prototype.drawSprite = function(ctx)
{
ctx.save();
ctx.translate(this.x,this.y);
ctx.rotate(this.rotate);
ctx.drawImage(this.img,0,0,this.img.width,this.img.height,-this.width/2,-this.height/2,this.width,this.height);
ctx.restore();
}
Sprite.prototype.updateSprite = function()
{
this.x += this.vx;
this.y += this.vy;
this.rotate += this.rotatespeed;
if(this.x > 700)
this.vx = -this.vx;
if(this.x < 0)
this.vx = -this.vy;
if(this.y > 700)
this.vy = -this.vy;
if(this.y < 0)
this.vy = -this.vy;
}
Sprite.prototype.mouseEventListener = function(evt, type)
{
console.log("Hello");
}
//------------------------------------------
//GLOBAL VARIALBES
var setIntervalAmount = 30;
var scrollAmount = 0.5;
var game;
function Game()
{
this.camera = new Object();
this.camera.x = -350;
this.camera.y = -350;
this.camera.scale = 1;
this.camera.rotate = 0;
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.id="mycanvas";
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event){
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var canvasX = mouseX * ctx.canvas.width / ctx.canvas.clientWidth;
var canvasY = mouseY * ctx.canvas.height / ctx.canvas.clientHeight;
//console.log(canvasX+" | "+canvasY);
});
this.objects = new Array();
}
Game.prototype.handleMouse = function(evt,type)
{
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].mouseEventListener(evt,type);
}
};
Game.prototype.gameLoop = function()
{
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
/*Game.prototype.drawGame = function()
{
var gameLoop = setInterval(function(){
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
},setIntervalAmount);
}*/
function mouseWheelListener()
{
var evt = window.event;
console.log(evt.wheelDelta);
if(evt.wheelDelta < 0)
game.camera.scale /= (1+scrollAmount);
else
game.camera.scale *= (1+scrollAmount);
}
function mouseDownListener()
{
var evt = window.event;
var type = "down"
game.handleMouse(evt,type);
}
function mouseUpListener()
{
var evt = window.event;
var type = "up"
game.handleMouse(evt,type);
}
function mouseMoveListener()
{
var evt = window.event;
var type = "move"
game.handleMouse(evt,type);
}
//------------------
window.addEventListener('load',function(event){startgame();});
var dog = new Image();
dog.src = "grid.gif";
function startgame()
{
game = new Game();
for(var i=0;i<1;i++)
game.objects.push(new Sprite(dog,250,250));
setInterval(game.gameLoop,setIntervalAmount);
document.getElementById("mycanvas").addEventListener("wheel", mouseWheelListener);
document.getElementById("mycanvas").addEventListener("mousedown", mouseDownListener);
document.getElementById("mycanvas").addEventListener("mouseup", mouseUpListener);
document.getElementById("mycanvas").addEventListener("mousemove", mouseMoveListener);
}
Only issue, with your code is the context on which you are executing the gameloop method.
usually setInterval, setTimeout functions are executed under the global / window context. Hence, if you specify this inside the method, you are technically referring to global context, even though you are executing it on an object.
So, just to make sure you don't run into issues, always have a method as a first argument to setInterval, that would execute the necessary functions, instead of a method reference, something like
setInterval(function(){/*
game.gameLoop()
*/}, 1000);
This way you are executing the setInterval function in the global context but you are calling a method on game object explicitly.
function Sprite(imgg, w, h) {
this.img = imgg;
this.x = 350; //Math.random()*700;
this.y = 350; //Math.random()*700;
this.vx = 0; //Math.random()*8-4;
this.vy = 0; //Math.random()*8-4;
this.width = w;
this.height = h;
this.rotatespeed = 0.01;
this.rotate = 40;
}
Sprite.prototype.drawSprite = function(ctx) {
ctx.save();
ctx.translate(this.x, this.y);
ctx.rotate(this.rotate);
ctx.drawImage(this.img, 0, 0, this.img.width, this.img.height, -this.width / 2, -this.height / 2, this.width, this.height);
ctx.restore();
}
Sprite.prototype.updateSprite = function() {
this.x += this.vx;
this.y += this.vy;
this.rotate += this.rotatespeed;
if (this.x > 700)
this.vx = -this.vx;
if (this.x < 0)
this.vx = -this.vy;
if (this.y > 700)
this.vy = -this.vy;
if (this.y < 0)
this.vy = -this.vy;
}
Sprite.prototype.mouseEventListener = function(evt, type) {
//console.log("Hello");
}
//------------------------------------------
////GLOBAL VARIALBES
var setIntervalAmount = 200;
var scrollAmount = 0.5;
var game;
function Game() {
this.camera = new Object();
this.camera.x = -350;
this.camera.y = -350;
this.camera.scale = 1;
this.camera.rotate = 0;
this.canvas = document.createElement("canvas");
document.body.appendChild(this.canvas);
this.canvas.id = "mycanvas";
this.canvas.width = 700;
this.canvas.height = 700;
this.context = this.canvas.getContext("2d");
var ctx = this.context;
ctx.canvas.addEventListener('mousemove', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var canvasX = mouseX * ctx.canvas.width / ctx.canvas.clientWidth;
var canvasY = mouseY * ctx.canvas.height / ctx.canvas.clientHeight;
//console.log(canvasX+" | "+canvasY);
});
this.objects = new Array();
}
Game.prototype.handleMouse = function(evt, type) {
for (var i = 0; i < this.objects.length; i++) {
this.objects[i].mouseEventListener(evt, type);
}
};
Game.prototype.gameLoop = function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width / 2, this.canvas.height / 2);
this.context.scale(this.camera.scale, this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x, this.camera.y);
for (var i = 0; i < this.objects.length; i++) {
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
}
/*Game.prototype.drawGame = function()
{
var gameLoop = setInterval(function(){
this.context.clearRect(0,0,this.canvas.width, this.canvas.height);
this.context.save();
this.context.translate(this.canvas.width/2, this.canvas.height/2);
this.context.scale(this.camera.scale,this.camera.scale);
this.context.rotate(this.camera.rotate);
this.context.translate(this.camera.x,this.camera.y);
for(var i=0;i<this.objects.length;i++)
{
this.objects[i].updateSprite();
this.objects[i].drawSprite(this.context);
}
this.context.restore();
},setIntervalAmount);
}*/
function mouseWheelListener() {
var evt = window.event;
console.log(evt.wheelDelta);
if (evt.wheelDelta < 0)
game.camera.scale /= (1 + scrollAmount);
else
game.camera.scale *= (1 + scrollAmount);
}
function mouseDownListener() {
var evt = window.event;
var type = "down"
game.handleMouse(evt, type);
}
function mouseUpListener() {
var evt = window.event;
var type = "up"
game.handleMouse(evt, type);
}
function mouseMoveListener() {
var evt = window.event;
var type = "move"
game.handleMouse(evt, type);
}
//------------------
window.addEventListener('load', function(event) {
startgame();
});
var dog = new Image();
dog.src = "https://i.stack.imgur.com/W0mIA.png";
function startgame() {
game = new Game();
for (var i = 0; i < 1; i++)
game.objects.push(new Sprite(dog, 250, 250));
setInterval(function() {
game.gameLoop();
}, setIntervalAmount);
document.getElementById("mycanvas").addEventListener("wheel", mouseWheelListener);
document.getElementById("mycanvas").addEventListener("mousedown", mouseDownListener);
document.getElementById("mycanvas").addEventListener("mouseup", mouseUpListener);
document.getElementById("mycanvas").addEventListener("mousemove", mouseMoveListener);
}
setInterval will call game.gameloop at the global scope which means the value of this inside the function is not what you expect it to be. This can be fixed by binding the function to the desired object.
E.g. change setInterval(game.gameLoop,setIntervalAmount); to setInterval(game.gameLoop.bind(game),setIntervalAmount);.
This example from MDN may provide some clarity for your code's current behaviour:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var retrieveX = module.getX;
retrieveX();
// returns 9 - The function gets invoked at the global scope
// Create a new function with 'this' bound to module
// New programmers might confuse the
// global var x with module's property x
var boundGetX = retrieveX.bind(module);
boundGetX(); // 81

JavaScript game not working, freezes after initialization

I have the following problem: I'am trying to make a simple game in JavaScript. The idea of the game is to have a canvas, a ball bouncing inside and small pad going left to right to hit the ball. I've done it like this, and it works fine:
var canvasBg;
var contextBg;
var canvasBall;
var contextBall;
function Drawable() {
this.initialize = function(x,y) {
this.x = x;
this.y = y;
};
this.draw = function() {
};
}
function Ball() {
var dx = 2;
var dy = 2;
var radius = 5;
this.draw = function() {
contextBall.beginPath();
contextBall.clearRect(0,0,canvasBall.width,canvasBall.height);
contextBall.closePath();
contextBall.beginPath();
contextBall.fillStyle = "#0000ff";
contextBall.arc(this.x, this.y, radius, 0, Math.PI*2, true);
contextBall.closePath();
contextBall.fill();
// the code seems to stop here
if(this.x<0 || this.x>300)
dx = -dx;
if(this.y<0 || this.y>150)
dy = -dy;
if((this.x+radius)>pad.x && (this.x-radius)<(pad.x+50) && (this.y+radius)>pad.y && (this.y-radius)<(pad.y+10)) {
dy = -dy;
}
if(this.y>(pad.y-2) && this.y<(pad.y+12) && (this.x+radius)>pad.x && (this.x-radius)<(pad.x+50)) {
dx = -dx;
}
this.x += dx;
this.y += dy;
};
}
Ball.prototype = new Drawable();
KEY_CODES = {
37: 'left',
39: 'right',
};
KEY_STATUS = {};
for (code in KEY_CODES) {
KEY_STATUS[ KEY_CODES[ code ]] = false;
}
document.onkeydown = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = true;
}
};
document.onkeyup = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = false;
}
};
function Pad() {
var hSpeed = 5;
this.padWidth = 50;
this.padHeight = 10;
this.draw = function() {
contextBg.clearRect(0,0,canvasBg.width,canvasBg.height);
contextBg.fillStyle = "#ffffff";
contextBg.fillRect(this.x,this.y,this.padWidth,this.padHeight);
};
this.move = function() {
if(KEY_STATUS.left || KEY_STATUS.right) {
contextBg.clearRect(0,0,canvasBg.width,canvasBg.height);
if(KEY_STATUS.left) {
this.x -= hSpeed;
if (this.x <= 0)
this.x = 0;
} else if (KEY_STATUS.right) {
this.x += hSpeed;
if (this.x >= 300-this.padWidth)
this.x = 300 - this.padWidth;
}
this.draw();
}
};
}
Pad.prototype = new Drawable();
function init() {
canvasBg = document.getElementById('display');
contextBg = this.canvasBg.getContext('2d');
canvasBall = document.getElementById('ball');
contextBall = this.canvasBall.getContext('2d');
ball = new Ball();
ball.initialize(10,10);
pad = new Pad();
pad.initialize(120,80);
setInterval(function(){animate();},30);
}
function animate() {
ball.draw();
pad.draw();
pad.move();
};
However, I decided to try to improve my code a bit, and i made a class GamePlay:
var game = new GamePlay();
function Drawable() {
this.initialize = function(x,y) {
this.x = x;
this.y = y;
};
this.draw = function() {
};
}
function Ball() {
var dx = 2;
var dy = 2;
var radius = 5;
this.draw = function() {
this.context.beginPath();
this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
this.context.closePath();
this.context.beginPath();
this.context.fillStyle = "#0000ff";
this.context.arc(this.x, this.y, radius, 0, Math.PI*2, true);
this.context.closePath();
this.context.fill();
if(this.x<0 || this.x>300)
dx = -dx;
if(this.y<0 || this.y>150)
dy = -dy;
if((this.x+radius)>pad.x && (this.x-radius)<(pad.x+50) && (this.y+radius)>pad.y && (this.y-radius)<(pad.y+10)) {
dy = -dy;
}
if(this.y>(pad.y-2) && this.y<(pad.y+12) && (this.x+radius)>pad.x && (this.x-radius)<(pad.x+50)) {
dx = -dx;
}
this.x += dx;
this.y += dy;
};
}
Ball.prototype = new Drawable();
KEY_CODES = {
37: 'left',
39: 'right',
};
KEY_STATUS = {};
for (code in KEY_CODES) {
KEY_STATUS[ KEY_CODES[ code ]] = false;
}
document.onkeydown = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = true;
}
};
document.onkeyup = function(e) {
var keyCode = (e.keyCode) ? e.keyCode : e.charCode;
if (KEY_CODES[keyCode]) {
e.preventDefault();
KEY_STATUS[KEY_CODES[keyCode]] = false;
}
};
function Pad() {
var hSpeed = 5;
this.padWidth = 50;
this.padHeight = 10;
this.draw = function() {
this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
this.context.fillStyle = "#ffffff";
this.context.fillRect(this.x,this.y,this.padWidth,this.padHeight);
};
this.move = function() {
if(KEY_STATUS.left || KEY_STATUS.right) {
this.context.clearRect(0,0,this.canvas.width,this.canvas.height);
if(KEY_STATUS.left) {
this.x -= hSpeed;
if (this.x <= 0)
this.x = 0;
} else if (KEY_STATUS.right) {
this.x += hSpeed;
if (this.x >= 300-this.padWidth)
this.x = 300 - this.padWidth;
}
this.draw();
}
};
}
Pad.prototype = new Drawable();
function GamePlay() {
var ball;
var pad;
this.setUpGame = function() {
this.canvasBg = document.getElementById('display');
this.contextBg = this.canvasBg.getContext('2d');
this.canvasBall = document.getElementById('ball');
this.contextBall = this.canvasBall.getContext('2d');
Ball.prototype.canvas = this.canvasBall;
Ball.prototype.context = this.contextBall;
Pad.prototype.canvas = this.canvasBg;
Pad.prototype.context = this.contextBg;
ball = new Ball();
ball.initialize(10,10);
pad = new Pad();
pad.initialize(120,80);
};
var animate = function() {
ball.draw();
pad.draw();
pad.move();
};
this.startGame = function() {
setInterval(function(){animate();},30);
};
}
function init() {
game.setUpGame();
game.startGame();
}
BUT, it only draws a ball on its initializing coordinates and then seems to stop there. I tried to do some manual testing by putting alert() on certain points in code and I found out that it seems to stop in the middle of ball's draw method and skips calling pad.draw() and pad.move() in animate(). I don't know what is wrong, my guess that is something with prototypes. I am new to JavaScript and this prototype-based OOP is still a bit confusing to me. Thanks.
I've tried code and found next problems:
function init - hope it is called after html is fully loaded
Ball.draw function refers object pad, which is not defined in its context, use game.pad
var animate = function creates local "private" variable, change it to this.animate = function
in setInterval call proper function setInterval(function(){game.animate();},30);
var game = new GamePlay(); is called before GamePlay is defined, move this string below
after these changes it works without errors in console
I believe this is because of your miss-use of paths in your draw method.
First, you don't need to wrap .clearRect with .beginPath and .closePath.
Second, and what is likely causing your script to error is that you are using .fill after .closePathwhen you draw the circle. .fill should be used before .closePath and actually after using .fill you don't need to use .closePath as it will already close your path for you.

Node Socket.io object trouble

I'm having some trouble with Node Socket.IO
I have put all my code in pastebins
Server file
var io = require("socket.io").listen(1337);
io.set("log level", "0");
var particles = [];
var players = [];
var remove_loop;
var particle;
io.sockets.on("connection", function(socket) {
//connection
socket.emit("hello");
console.log("A new connection has been established");
//new player
socket.on("new_player", function() {
players.push(socket.id);
console.log("New player connected.");
console.log("ID: " + socket.id);
});
//new particle
socket.on("new_particle", function(data) {
particle = data;
socket.broadcast.emit("particles_data", particle);
});
});
Game file
window.onload = function() {
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//display settings
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
setInterval(function() {
if(canvas.width != window.innerWidth || canvas.height != window.innerHeight) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
}, 1000);
//remove cursor
document.getElementById("canvas").style.cursor = "none";
//server connection
var socket = io.connect("http://localhost:1337");
//variables
var update_loop;
var draw_loop;
var local_player;
var mouse_x;
var mouse_y;
var remote_players;
var particles;
var remove_loop;
var explosion;
var background_color;
init();
function init() {
//initialize
local_player = new Player();
background_color = "000000";
explosion = true;
remote_players = [];
particles = [];
draw_loop = setInterval(function() { draw(); }, 10);
update_loop = setInterval(function() { update(); }, 10);
//server
socket.on("hello", function() {
socket.emit("new_player");
});
socket.on("particles_data", function(data) {
particles.push(data);
});
};
function update() {
for(var i = 0; i < particles.length; i++) {
particles[i].move();
}
};
function draw() {
//background_color
ctx.fillStyle = "#" + background_color;
ctx.fillRect(0, 0, canvas.width, canvas.height);
//remove particles
setInterval(function() {
if(!remove_loop) remove_loop = setInterval(function() {
setTimeout(function() {
if(particles.length > 0) {
particles.shift();
}
}, 1);
}, 20);
}, 10);
//particles
for(var i = 0; i < particles.length; i++) {
if(particles[i].x < canvas.width &&
particles[i].y < canvas.width) {
if(particles[i].x < canvas.width &&
particles[i].y < canvas.height) {
particles[i].draw(ctx);
}
}
}
}
function newParticle() {
socket.emit("new_particle", new Particle(local_player.x, local_player.y, local_player.color));
particles.push(new Particle(local_player.x, local_player.y, local_player.color));
};
//move mouse
canvas.onmousemove = function(event) {
if(!event) event = window.event;
local_player.x = event.pageX;
local_player.y = event.pageY;
newParticle();
};
//touch mouse (phones/tables)
canvas.onmousedown = function(event) {
if(!event) event = window.event;
local_player.x = event.pageX;
local_player.y = event.pageY;
newParticle();
}
};
Player file
function Player() {
this.x = 0;
this.y = 0;
this.color = Math.floor(Math.random() * 999999);
while (this.color < 100000) {
this.color = Math.floor(Math.random() * 999999);
}
};
Particle file
function Particle(x, y, color) {
this.start_x = x;
this.start_y = y;
this.speed = Math.floor(Math.random() * 3 + 1);
this.x = x;
this.y = y;
this.size = Math.floor(Math.random() * 3 + 1);
this.color = "#" + color;
this.direction = Math.floor(Math.random() * 8);
this.move = function() {
this.speedDecreaseChance = Math.random(Math.random() * 100);
//Chance that the particle loses it's velocity like you would
//see with real particles
if(this.speedDecreaseChance > 3) { this.speed -= 0.5 };
//It's important that they move -AWAY- from X and Y.
this.subDirection = Math.floor(Math.random() * 2);
if(this.direction == 0) { //upper left
if(this.subDirection == 0) {
this.x -= this.speed;
} else if(this.subDirection == 1) {
this.y -= this.speed;
}
} else if(this.direction == 1) { //bottom right
if(this.subDirection == 0) {
this.x += this.speed;
} else if(this.subDirection == 1) {
this.y += this.speed;
}
} else if(this.direction == 2) { //upper right
if(this.subDirection == 0) {
this.x += this.speed;
} else if(this.subDirection == 1) {
this.y -= this.speed;
}
} else if(this.direction == 3) { //bottom left
if(this.subDirection == 0) {
this.x -= this.speed;
} else if(this.subDirection == 1) {
this.y += this.speed;
}
} else if(this.direction == 4) { //left
this.x -= this.speed/1.5;
if(this.subDirection == 0) {
this.y -= this.speed;
} else if(this.subDirection == 1) {
this.y += this.speed;
}
} else if(this.direction == 5) { //up
this.y -= this.speed/1.5;
if(this.subDirection == 0) {
this.x -= this.speed;
} else if(this.subDirection == 1) {
this.x += this.speed;
}
} else if(this.direction == 6) { //right
this.x += this.speed/1.5;
if(this.subDirection == 0) {
this.y -= this.speed;
} else if(this.subDirection == 1) {
this.y += this.speed;
}
} else if(this.direction == 7) { //down
this.y += this.speed/1.5;
if(this.subDirection == 0) {
this.x -= this.speed;
} else if(this.subDirection == 1) {
this.x += this.speed;
}
}
};
this.draw = function(ctx) {
ctx.beginPath();
ctx.shadowColor = this.color;
ctx.shadowBlur = 8;
ctx.arc(this.x, this.y, this.size ,0 ,2*Math.PI);
ctx.fillStyle = this.color;
ctx.fill();
ctx.shadowBlur = 0;
};
};
Now the problem is that there's an error in my traffic between the server and all sockets.
What I want to do is make it possible that when one has particle objects to send them to the server and the server sends them to everyone except the original sender.
I did this through socket.broadcast.emit();
This went successful.
However when the objects arrive at the other sockets I get this error:
Uncaught TypeError: Object #<Object> has no method 'move'
Uncaught TypeError: Object #<Object> has no method 'draw'
For every particle object that exists at that moment.
If anyone knows why my objects lose their methods and would be so friendly to help a programmer in distress I'd be absolutely delighted :)
Thanks in advance!
From what I know Socket.IO expected JSON data as 2nd parameter for the emit function. JSON data format doesn't support function as values according to http://www.json.org/
You are sending a javascript object and expecting the object to be created from the json on a different client. This is not how Socket.IO communication works.
Instead of doing that you should send the data required to construct the object and use that to construct the object on the client.
You could do some thing like the following
Change this line
socket.emit("new_particle", new Particle(local_player.x, local_player.y, local_player.color));
to
socket.emit("new_particle", {x:local_player.x, y:local_player.y, color:local_player.color});
and then the event listener
socket.on("particles_data", function(data) {
particles.push(data);
});
to handle the creation of object from the data
socket.on("particles_data", function(data) {
particles.push(new Particle(data.x, data.y, data.color));
});
When an object is serialized to JSON, it loses all type information. This is what socket.io is transmitting.
var particle = new Particle(1, 2, 'ccc');
console.log(JSON.stringify(particle)); // {"start_x":1,"start_y":2,"speed":3,"x":1,"y":2,"size":3,"color":"#ccc","direction":5}
You can't tell if it's a particle or a monkey or something else.
When you receive this object, you need to convert it to a Particle first.
socket.on("particles_data", function(data) {
var particle = ...;
particles.push(particle);
});
You could define a constructor and create it again:
var particle = new Particle(data.x, data.y, data.color);
Or you could change its prototype:
var particle = $.extend(new Particle(), data); // here using jQuery helper method

Categories

Resources