I'm trying to draw a line using ctx.lineTo in loop.
I have small function in my prototype
this.draw = function(ctx)
{
ctx.beginPath();
trace(trail.join(' '));
for(var i=0;i<trail.length;i++)
{
// ctx.lineTo(trail[i].x,trail[i].y);
}
ctx.stroke();
}
When I run this, I receive some points traced ([389.272, 722.798] [392.583, 25.069]...) but I see nothing (very surprising)
When I remove the comment from ctx.lineTo, it fails and my trace returns [NaN, NaN] [NaN, NaN].... Constants in drawing function works perfectly (and my points doesn't change), but I need value from variables...
What's wrong? Problem occurs only on Firefox
edit:
trace is simple text assignment to html object
trail is an array of points which are simple objects
function point(x,y)
{
this.x = x;this.y = y;
this.toString = function()
{
var xs=this.x.toFixed(3);
var ys=this.y.toFixed(3);
var xs=" ".substring(0,8-xs.length)+xs;
var ys=" ".substring(0,8-ys.length)+ys;
return "["+xs+","+ys+"]";
}
}
There's still not enough information to really answer this, so I'm going to just hazard a guess: change the "point" constructor as follows:
function point(x,y)
{
this.x = x - 0; this.y = y - 0;
this.toString = function()
{
var xs=this.x.toFixed(3);
var ys=this.y.toFixed(3);
var xs=" ".substring(0,8-xs.length)+xs;
var ys=" ".substring(0,8-ys.length)+ys;
return "["+xs+","+ys+"]";
}
}
The idea is to make sure that "x" and "y" are actually numbers and not strings. You could also do this:
this.x = x - 0; this.y = y - 0;
if (isNaN(this.x) || isNaN(this.y)) {
alert("NaN! NaN! x is " + x + " y is " + y);
Related
I'm making a game where the player will move using their cursor and will have to dodge objects. Each object has a hitbox, so I want to be able to update the number of lives whenever the cursor hits one. I'm just not sure what an efficient way is to keep track of all the hitboxes. I'd also like to record the object that the cursor collided with, so that bonus objects can be counted. The objects constantly respawn and move off the canvas, so I think keeping an array of all the hitboxes would pretty quickly get out of hand. Here's some code with some pseudo code for what I want to do.
canvas.addEventListener("mousemove", e => {
mouseX = e.clientX - rect.left;
mouseY = e.clientY - rect.top;
if (somehitboxX<=mouseX<=somehitboxX + 50 and somehitboxY<=mouseY<=somehitboxY + 50){
doSomething
}
});
EDIT: Instead of having my cursor keep track of all the hitboxes, would it be possible to have the hitboxes keep track of the cursor? Maybe by adding an event listener to each object? If that's possible, how would I go about doing it?
EDIT: Here's some code to get a better idea of what I'm working with. The emoji objects are what need to be dodged by the player. Each one has an emoji, a score, coordinates, speed, a hitbox, and a boolean that says whether it's been hit or not (though I'm not sure how to control it yet since that's what I need help with).
function Emoji(emojicon, score, x, y, speed) {
this.emojicon = emojicon;
this.score = score;
this.x = x;
this.y = y;
this.speed = speed;
this.hitbox = { hbx: x, hby: y - 50, hbWidth: 50, hbHeight: 50 };
this.hit = false;
}
The emoji objects are initialized like this:
var xPos = 0;
for (var i = 0; i < 9; i++) {
var emo = new Emoji("😜", 5, xPos, 520, 1);
emojis.push(emo);
xPos += 55;
}
emojis.forEach(emoji => drawEmoji(emoji));
}
And then Emoji.prototype.update updates both the coordinates of the emoji and its hitbox:
Emoji.prototype.update = function() {
if (this.y < 520) {
this.y -= this.speed;
this.hitbox.hby = this.y - 50;
} else {
var flip = Math.floor(Math.random() * 1000);
if (flip == 1) {
this.y -= this.speed;
this.hitbox.y = this.y - 50;
}
}
};
I hope this is enough code to get an idea of what I have so far.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
How does the "this" keyword work, and when should it be used?
(22 answers)
Closed 4 years ago.
I'm fairly new to JavaScript though I do have some programming experience with Python.
My problem is, that I do not seem understand the concept of namespace in JS since it appears to be different than in Python. This is my code:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}
// called every frame to update position of the box
this.update = function () {
$(this.boxid).css({top: this.y, left: this.x});
}
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
When hitting one of the four arrow keys, the move() function is being executed with the correct parameters.
Now the way code is shown up there, JS tells me that the x and y values in the update() function are "undefined". But as soon as I change them from this.x and this.y to snakeObj.x and snakeObj.y, as well as this.boxid to "#box", everything works perfectly.
I would like to understand why the update() function can't "access" the values from the object while the move() function is perfectly fine with it.
Just for clarification, the working code looks like this:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}
// called every frame to update position of the box
this.update = function () {
$("#box).css({top: snakeObj.y, left: snakeObj.x});
}
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
It's because you've got another this value; the one for the inside function.
In JavaScript, every function gets its own this value. Functions are bound at call-time, which means that if you don't call them via the attribute access they're called without the correct this value. A common workaround is to set var that = this; in your object's constructor so you can use the original value via closure from a function defined in the constructor.
Another workaround, if you don't mind dropping support for IE11, is to use an ES6 arrow function like so:
function snake(x, y) {
// x and y coordinate of square (topleft)
this.x = x;
this.y = y;
// reference to div object 'box2'
this.boxid = "#box";
this.box = document.getElementById(this.boxid);
// attempts to move the box by args
this.move = (speedx, speedy) => (function (speedx, speedy) {
var m = 50;
// check if the box is within the container, moves if true
if ((this.x+(speedx*m))<=150 && (this.y+(speedy*m))<=150 &&
(this.y+(speedy*m))>=0 && (this.x+(speedx*m))>=0) {
this.x = this.x + speedx*m;
this.y = this.y + speedy*m;
}
}).call(this, speedx, speedy);
// called every frame to update position of the box
this.update = () => $("#box").css({top: this.y, left: this.x});
}
var snakeObj = new snake(100, 100);
var t = setInterval(s.update, 100);
I have a Javascript question, that might be obvious, but I just can't seem to find the solution for it, and I don't know how to solve it.
(Also, I'm still pretty new to coding)
So I'm writing a patrol function for squares in my game, and for now I started out with just making the square move one way. Later on I will make it patrol back and forth. That's why I put the move function in the draw function.
I want the move function to be reusable for several squares, but I can't seem to make a general move function work. However, I can make a move function specifically for a certain square, work.
Can anyone tell me why this works:
var square = 16;
var posX = 32;
var posY = 32;
function moveSquare() {
for (i = 0; i < 10; i++) {
posX++;
}
}
function draw() {
var redSquare = { x: posX, y: posY, w: square, h: square, color: "red" };
ctx.fillStyle = redSquare.color;
rect(redSquare.x,redSquare.y,redSquare.w,redSquare.h);
moveSquare();
}
And this doesn't:
var square = 16;
var posX = 32;
var posY = 32;
function move(pos) {
for (i = 0; i < 10; i++) {
pos++;
}
}
function draw() {
var redSquare = { x: posX, y: posY, w: square, h: square, color: "red" };
ctx.fillStyle = redSquare.color;
rect(redSquare.x,redSquare.y,redSquare.w,redSquare.h);
move(posX);
}
By the way, I defined the rect function elsewhere, but I figured it wasn't important to include.
Hope you can help
The value passed to the function move is being passed by value, not by reference.
So the pos inside move is private to the move function.
The pos variable will be a copy of posX, so no matter what you do to it in the move function, the global posX will not be affected.
Consider the code:
var x = 5;
function move(x)
{
x++;
console.log("In function x is: " + x);
}
console.log("Outside function, before call x is: " + x);
move(x);
console.log("Outside function, after call x is: " + x);
This outputs:
"Outside function, before call x is: 5"
"In function x is: 6"
"Outside function, after call x is: 5"
The function move has it's own private copy x.
Look into pass by reference, pass by value and variable scope.
http://videobin.org/+70a/8wi.html
You can see what's happening there, and a demo to try it here: http://student.dei.uc.pt/~drgomes/carry/index.html.
So, I'm using Chipmunk JS demos to get an idea of how it works (see https://github.com/josephg/Chipmunk-js). The simple demo starts alright but then things start jumping crazily and I've been trying to figure out this with no luck so far.
var radToDeg = 180 / Math.PI;
function PlayState() {
this.blocks = [];
this.setup = function() {
space.iterations = 100;
space.gravity = new cp.Vect(0, 150);
space.game = this;
this.ground = space.addShape(new cp.SegmentShape(space.staticBody, new cp.v(0, 480), new cp.v(640, 480), 0));
this.ground.setElasticity(0);
this.ground.setFriction(1);
};
this.update = function() {
space.step(this.dt);
for (var i = 0; i < this.blocks.length; i++) {
var block = this.blocks[i];
block.sprite.x = block.body.p.x;
block.sprite.y = block.body.p.y;
block.sprite.angle = block.body.a * radToDeg;
}
if (isMouseDown("left")) {
if (this.canAddBlock) {
this.canAddBlock = false;
this.addBlock(mouseX, mouseY);
}
} else {
this.canAddBlock = true;
}
};
this.draw = function() {
clearCanvas();
for (var i = 0; i < this.blocks.length; i++) {
this.blocks[i].sprite.draw();
}
// this.ground.sprite.draw();
};
this.addBlock = function(x, y) {
width = 64;
height = 64;
var newBlock = new Block(x, y, width, height);
newBlock.body = space.addBody(new cp.Body(1, cp.momentForBox(1, width, height)));
newBlock.body.setPos(new cp.v(x, y));
newBlock.shape = space.addShape(new cp.BoxShape(newBlock.body, width, height));
newBlock.shape.setElasticity(0);
newBlock.shape.setFriction(1);
this.blocks.push(newBlock);
};
}
desiredFPS = 60;
switchState(new PlayState());
The source code is pretty straightforward, I have my doubts about the way I'm creating the ground since I can't really tell in what position it actually is. The cubes seem to find it and collide against it though.
The other source file is a little Block class to help me organize things:
Block = (function() {
function constructor(x, y, width, height) {
this.sprite = new Sprite("res/block.png", x, y);
this.width = width;
this.height = height;
}
constructor.prototype = {
update: function() {
}
};
return constructor;
})();
From watching the behavior, I think it is as simple as the sprites and the chipmunk bodies not rotating around the same point. I believe chipmunk rotations are around the center of mass. It looks like the sprites are rotating around the upper left corner. In fact, they may be drawing from that corner too, which explains why they stack funny, and intersect the bottom plane.
I think you need something like this in the update function. (pseudocode):
offset = Vector(-width/2,-height/2)
offset.rotate_by(block.body.a)
block.sprite.x = block.body.p.x + offset.x
block.sprite.y = block.body.p.y + offset.y
I don't know chipmunk at all but playing around with your demo it seems like the Physics isn't right at all (right from the beginning for me). Just a hunch from looking at your code, but it looks to me like you should be setting the dimensions on the Sprite instance in your Block class, rather than on the Block instance itself.
Block = (function() {
function constructor(x, y, width, height) {
this.sprite = new Sprite("res/block.png", x, y);
// Do you mean to set the width and height of the sprite?
this.sprite.width = width;
this.sprite.height = height;
}
constructor.prototype = {
update: function() {
}
};
return constructor;
})();
I'm writing a simple javascript game. With an avatar and obstacles. At this moment I simulated a class in javascript "rectangle". The code is here:
function rectangle (x,y,width,height,verticalvelocity,dangerous,image)
{
//returns info
this.x=x;
this.y = y;
this.height= height;
this.width=width;
this.verticalvelocity=verticalvelocity
this.jump= jump;
this.image=image
this.dangerous=dangerous
this.drawImg= function() {
context.drawImage(this.image,this.x,this.y,this.width,this.height)}
//getters
this.ycormdd=function () {return (this.y + (this.height /2));} //returns the y coor of the middlepoint
this.xcormdd= function () {return (this.x + (this.width /2));} //returns the x coor of the middlepoint
this.danger= function () {if (this.dangerous == 0) {return true} else {return false}};
//the setters
this.setdangerous= function (dangerous) {this.dangerous = dangerous};
this.setx= function (x) {this.x = x};
this.sety= function (y) {this.y = y};
this.setwidth= function (width) {this.width = width};
this.setheight= function (height) {this.height = height};
this.setimage= function (image) {this.image = image};
this.setverticalvelocity= function (verticalvelocity) {this.verticalvelocity=verticalvelocity};
}
The problem is that I use the rectangle "class" for both my avatar and obstacle so I type
var avatar= new rectangle (....)
var obstacle= new rectangle (...)
And that's just not how it's done. As far as I understand I need te make 3 classes. One class avatar, one class obstacle and one class rectangle. Since both my obstacle and avatar are represented by a rectangle, I think both my avatar and rectangle "class" needs to have access to the rectangle class.But I have absolutely no idea how to do this :s. Can somebody please help? thanks in advance. I think my future rectangle "class" should look like this:
function rectangle (x,y,width,height,image)
{
//returns info
this.x=x;
this.y = y;
this.height= height;
this.width=width
this.image=image
//draws a rectangle
this.drawImg=function () {
context.drawImage(this.image,this.x,this.y,this.width,this.height)}
//getters
this.ycormdd=function () {return (this.y + (this.height /2));} //returns the y coor of the middlepoint
this.xcormdd= function () {return (this.x + (this.width /2));} //returns the x coor of the middlepoint
//the setters
this.setx= function (x) {this.x = x};
this.sety= function (y) {this.y = y};
this.setwidth= function (width) {this.width = width};
this.setheight= function (height) {this.height = height};
this.setImage = function (image) {this.image = image};
}
But than I need to create an avatar and obstacle class.
functions I need in the avatar class are:
setverticalvelocity
getverticalvelocity
(+ functionality from rectangle)
And for my obstacle, I need:
setdangerous
getdangerous.
(+ functionality from rectangle)
I hope somebody understands my question. :p
Inheritance as described in the comments may lead to horrible multiple inheritance - it depends on how complicated the game is going to get.
Take a look at decorator & strategy patterns. http://www.ycit-he.org/files/Resources/PHP%20Objects,%20Patterns,%20and%20Practice.pdf has a section (it's php but that doesn't matter too much).
http://addyosmani.com/blog/decorator-pattern/ has javscript code (I haven't read it through so don't know how relevant it might be.
The php code link has a section that describes decorators in terms of game "tiles" which may be useful.
Ok, while not using decorators in the strict sense here's some code i put together to demonstrate not inheriting everything. It's not meant to be great code - but to show how you use "pseudo decorators" can be used.
// this is your basic game tile - presuming all tiles will have a name, can move or not and will have some attributes
game_tile = function(n, m, atts) {
this.name = n;
this.mobile = m;
this.attributes = atts;
this.say = function() {
message = 'i am ' + this.name + ' and i can ';
if ( ! this.mobile ) {
message += 'not';
}
message += ' move around the game board\n';
for (i = 0; i < this.attributes.length; i++) {
message += this.attributes[i].message();
}
alert(message);
}
}
/* these next objects are 'attribute' objects for a game tile */
// this sets starting postion on game board
position = function(x, y) {
this.x = x;
this.y = y;
this.message = function() {
return '\n i am at x = ' + this.x + ', y = ' +this.y;
}
}
// this will draw the image - once the code to do it is written !
picture = function(src, w, h) {
this.image = src;
this.width = w;
this.height = h;
// code to draw image
this.message = function() {
return '\n my image is ' + this.image + ' at size x = ' + this.width + ' y = ' + this.height;
}
}
// stats for a character
stats = function(hp, dmg) {
this.health = hp;
this.damage = dmg;
this.message = function() {
return '\n i have health = ' + this.health + ' and do damage = ' + this.damage;
}
}
// a special ability
ability = function(n, dmg) {
this.name = n;
this.damage = dmg;
this.message = function() {
return '\n i will ' + this.name + ' you for damage = ' + this.damage;
}
}
// a player has a name, can move and position, picture & stats attributes
player1 = new game_tile('houdini', true, [
new position(12, 12),
new picture('mage.png', 24, 24),
new stats(120, 120)
]);
// this river only has an image and a position
river = new game_tile('the river thames', false, [
new position(25, 36),
new picture('river.png', 240, 12),
]);
// a boss - same as a player but with a special ability
boss = new game_tile('ming the merciless', true, [
new position(52, 52),
new picture('boss.png', 24, 24),
new stats(1200, 1200),
new ability('crush', 80)
]);
// they say something !
player1.say();
boss.say();
river.say();
I solved the problem without prototype, I still have a rectangle "class" But my avatar is now defined as follow:
function avatar(rectangle,verticalvelocity){
//returns info
this.verticalvelocity=verticalvelocity;
//returnns the rectangle
this.getRect=function () {return rectangle;}
.
.
.
}
And when I need for example the x coordinate of the avatar, I type:
avatar.getRect().getX()
Hope this helps somebody ;)