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.
Related
Sorry if question is bad. Its my first one. Im setting prototype functions on Ball object instances but in the loop the function only work on the instance that is called second(last). I tries to search for answer online.
function Ball(x, y, velX, velY, color, size) {
this.x = x;
this.y = y;
this.velX = velX;
this.velY = velY;
this.color = color;
this.size = size;
}
Ball.prototype.draw = function() {
ctx.beginPath();
ctx.fillStyle = this.color;
ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
ctx.fill();
}
Ball.prototype.boundaries = function() {
if (this.x - this.size > width) {
this.x = 0 - this.size;
} else if (this.x + this.size < 0) {
this.x = width - this.size;
} else if (this.y - this.size > height) {
this.y = 0 - this.size;
} else if (this.y + this.size < 0) {
this.y = height - this.size;
}
}
/** Controls that is only working on second object**/
Ball.prototype.setControls = function() {
let _this = this;
window.onkeydown = function(e) {
if (e.key === 'a' && _this.velX > -4) {
_this.velX -= 1;
} else if (e.key === 'd' && _this.velX < 4) {
_this.velX += 1;
} else if (e.key === 'w' && _this.velY > -4) {
_this.velY -= 1;
} else if (e.key === 's' && _this.velY < 4) {
_this.velY += 1;
}
}
this.x += _this.velX;
this.y += _this.velY;
}
let testBall = new Ball(50, 100, 4, 4, 'blue', 10);
let ball2 = new Ball(200, 200, 4, 4, 'green', 12);
function loop() {
ctx.fillStyle = 'rgba(255, 255, 255, 0.4)';
ctx.fillRect(0, 0, width, height);
/** If I switch testBall with ball2** setControls
will work on testBall**/
testBall.draw();
testBall.setControls();
testBall.boundaries();
ball2.draw();
ball2.boundaries();
ball2.setControls();
I've tried to put an if else statement where I initialize x = 1 before the loop and the for each odd num I run the function on 1 object and then even numbers on the other object but its laggy and it obviously becomes a problem when I need more objects.
requestAnimationFrame(loop);
}
loop();
by using window.onkeydown = you are overriding the existing handler, so it will work only for the last initialized instance, you can use addEventListener instead
I want to move an ellipse but I am stuck because my this.x value isn't changing... print("hit this.y = 30"); is working just fine but this--; is not working. Is anything blocking it? Thank you in advance for your time!
let redBubble = 0;
let x = false;
let y = 0;
let d = 0;
function setup() {
createCanvas(400, 400);
redBubble = new Bubble(300, 100, 10);
}
function draw() {
background(56, 23, 56);
redBubble.show();
redBubble.toRight();
redBubble.toLeft();
redBubble.example();
};
class Bubble {
constructor(x, y, d) {
this.x = x;
this.y = y;
this.d = d;
}
show() {
fill(255);
ellipse(this.x, this.y, this.d * 2);
}
toRight() {
if (this.x < 350) {
this.x = this.x + 1;
} else if (this.x === 350) {
this.y = this.y - 1;
}
}
toLeft() {
if (this.y <= 30) {
x = true;
} else if (this.y === 30) {
x = false;
}
}
example() {
if (x) {
this.x--; // not working
print("hit this.y = 30"); // working
}
}
}
Your code is running, but it sounds like it's not doing what you want it to.
All of your functions show(), toRight(), toLeft(), example(), are running every single draw. So every single time, toRight() is incrementing this.x by 1 (unless this.x is exactly 350). So when example() decrements it by 1, they are in effect canceling each other out and not changing this.x, when x is true and this.x is 349.
If you wanted the net effect to be this.x to decrease, you could replace this.x--; with this.x = this.x - 2;. But this is not a great solution.
Using states
It looks like you want to do different things at different stages of your animation, i.e. go right, then go up, then go left. As you've discovered, it can be pretty tricky to coordinate all of these different changes when all of your functions are running every cycle.
Instead, it's a lot easier to conditionally run only the functions you want, depending on what stage of your animation you're in. For this you can use an internal variable to store what it should be doing (I'll use this.direction for this example). Then in your draw function, you'd use if/then statements, like this:
function draw() {
background(56, 23, 56);
redBubble.show();
if (redBubble.direction === 'right') {
redBubble.goRight();
} else if (redBubble.direction === 'up') {
redBubble.goUp();
} else if (redBubble.direction === 'left') {
redBubble.goLeft();
}
};
And then in your individual functions, you'd change direction based on some condition. For example:
toRight() {
this.x = this.x + 1;
if (this.x === 350) {
this.direction = 'up';
}
}
Here's a working snippet of the above technique:
let redBubble;
function setup() {
createCanvas(400, 400);
redBubble = new Bubble(300, 100, 10);
}
function draw() {
background(56, 23, 56);
redBubble.show();
if (redBubble.direction === 'right') {
redBubble.goRight();
} else if (redBubble.direction === 'up') {
redBubble.goUp();
} else if (redBubble.direction === 'left') {
redBubble.goLeft();
} else if (redBubble.direction === 'down') {
redBubble.goDown();
}
};
class Bubble {
constructor(x, y, d) {
this.x = x;
this.y = y;
this.d = d;
this.direction = 'right';
}
show() {
fill(255);
ellipse(this.x, this.y, this.d * 2);
}
goRight() {
this.x = this.x + 1;
if (this.x === 350) {
this.direction = 'up';
}
}
goLeft() {
this.x = this.x - 1;
if (this.x === 30) {
this.direction = 'down';
}
}
goUp() {
this.y = this.y - 1;
if (this.y === 30) {
this.direction = 'left';
}
}
goDown() {
this.y = this.y + 1;
if (this.y === 300) {
this.direction = 'right';
}
}
}
<script src="https://unpkg.com/p5#0.6.1/lib/p5.min.js"></script>
I created a collision detection between Snake and BasicEnemy. I created a for loop to make five different enemies but the collision detection doesn't get called on any of the enemies that were created from the for loop. The collision only works with the one BasicEnemy object. Why isn't collision function being called for all of the enemies inside the array? Thank you.
Sketch.js
var snake;
var food;
var basicEnemy;
var scl = 20;
var enemies = [];
function setup() {
createCanvas(600, 500);
snake = new Snake();
basicEnemy = new BasicEnemy();
//** CREATE FIVE ENEMIES **
for (var i = 0; i < 5; i++) {
enemies[i] = new BasicEnemy();
}
}
// **FUNCTION WHEN SNAKE HITS ENEMY**
function collision() {
console.log("hit!");
}
function draw() {
background(51);
//Draw snake
snake.update();
snake.show();
//Draw basicEnemy
basicEnemy.update();
basicEnemy.show();
//** LOOP THROUGH ENEMIES AND UPDATE AND SHOW **
for (var i = 0; i < enemies.length; i++) {
enemies[i].show();
enemies[i].update();
if (enemies[i].hits(snake)) {
collision();
}
}
}
function keyPressed() {
if (keyCode === UP_ARROW){
snake.dir(0, -1);
} else if (keyCode === DOWN_ARROW) {
snake.dir(0, 1);
} else if (keyCode === LEFT_ARROW) {
snake.dir(-1 , 0);
} else if (keyCode === RIGHT_ARROW) {
snake.dir(1 , 0);
}
}
BasicEnemy.js
function BasicEnemy() {
this.x = random(700);
this.y = random(700);
this.velX = 15;
this.velY = 15;
}
//** FUNCTION TO CHECK IF ENEMY AND SNAKE ARE IN THE SAME LOCATION **
this.hits = function (pos) {
var = d = dist(this.x, this.y, pos.x, pos.y);
if(d < 1) {
return true;
} else {
return false;
}
}
this.show = function () {
fill(255, 0, 100);
rect(this.x, this.y, scl, scl);
}
Snake.js
function Snake() {
this.x = 0;
this.y = 0;
this.xspeed = 1;
this.yspeed = 0;
this.update = function() {
this.x = this.x + this.xspeed * scl;
this.y = this.y + this.yspeed * scl;
this.x = constrain(this.x, 0, width - scl);
this.y = constrain(this.y, 0, height - scl);
}
this.show = function() {
fill(255);
rect(this.x, this.y, scl, scl);
}
this.dir = function (x , y) {
this.xspeed = x;
this.yspeed = y;
}
}
Because you're essentially checking for the distance between the top left corners of the snake and the enemy, this'll only return true, if they completely overlap.
Use an AABB collision detection instead:
return this.x + scl >= pos.x && this.x <= pos.x + scl && this.y + scl >= pos.y && this.y <= pos.y + scl;
This returns true, if the first rectangle contains the second rectangle.
MDN says:
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
I`m trying to make a jump system in processing.js and its done, but not quite what I wanted. The thing is that like this, the jump height depends on how long the key is pressed. What I wanted is the same height regardless how long the key is pressed.
Here is my code:
var keys = [];
void keyPressed() {
keys[keyCode] = true;
};
void keyReleased() {
keys[keyCode] = false;
};
var Player = function(x, y) {
this.x = x;
this.y = y;
this.g = 0;
this.vel = 2;
this.jumpForce = 7;
this.jump = false;
};
Player.prototype.draw = function() {
fill(255,0,0);
noStroke();
rect(this.x, this.y, 20, 20);
};
Player.prototype.move = function() {
if(this.y < ground.y) {
this.y += this.g;
this.g += 0.5;
this.jump = false;
}
if(keys[RIGHT]) {
this.x += this.vel;
}
if(keys[LEFT]) {
this.x -= this.vel;
}
//preparing to jump
if(keys[UP] && !this.jump) {
this.jump = true;
}
// if jump is true, than the ball jumps... after, the gravity takes place pulling the ball down...
if(this.jump) {
this.y -= this.jumpForce;
}
};
Player.prototype.checkHits = function() {
if(this.y+20 > ground.y) {
this.g = 0;
this.y = ground.y-20;
jump = false;
}
};
Var Ground = function(x, y, label) {
this.x = x;
this.y = y;this.label = label;
};
Ground.prototype.draw = function() {
fill(0);
rect(0, 580, width, 20);
};
var player = new Player(width/2, height/2);
var ground = new Ground(0, 580, "g");
void draw() {
background(255,255,255);
player.draw();
player.move();
player.checkHits();
ground.draw();
}
Any help would be aprreciated.
What are you doing here is like: "If this(the Player) isn't touching the ground then, if (in addition) key UP is pressed, jump!". So it will allow the player jumping even if he is in the air... increasing the jump height
You should do something like: "if player is touching the ground allow to jump (if key UP pressed), otherwise you are already jumping!".
Something like this:
if(this.y < ground.y) {
this.y += this.g;
this.g += 0.5;
this.jump = true;
}
else{
this.jump = false;
}
if(keys[UP] && !this.jump) {
this.jump = true;
this.y -= this.jumpForce;
}
I have a canvas, and I'm using geolocation, google maps and openweathermap to get the weather of where the user is. The weather will be taken and cause the game I'm making to also use that weather...
How can I check if two squares that are spawned onto the canvas overlap? This is the code for the rain, which looks nothing like rain at the moment...
function rectangle(x, y, w, h) {
var randomx = Math.floor(Math.random() * canvas.width - 50);
this.x = randomx || x || 0;
this.y = y || 0;
this.w = w || 0;
this.h = h || 0;
this.expired = false;
this.draw = function() {
cx.fillStyle = "blue";
cx.fillRect(this.x, this.y, this.w, this.h);
};
this.update = function() {
this.y++;
if (y > canvas.height) {
this.expired = true;
}
};
}
var rectangles = new Array();
function newRect() {
rectangles.push(new rectangle(window.randomx, window.y, 10, 10));
}
var timing = 0;
function loop() {
cx.clearRect(0, 0, canvas.width, canvas.height);
if (timing % 10 === 0) {
newRect();
}
for (var i = 0, l = rectangles.length; i < l; i++) {
rectangles[i].update();
rectangles[i].draw();
if (rectangles[i].expired) {
rectangles.splice(i, 1);
i--;
}
}
timing++;
requestAnimFrame(loop);
}
loop();
My assumption, is that I need to perform a 'hit test' to see if two rectangles in the array are in the same perimeter... I guess where my this.draw and this.update function are I should do something like...
this.hitTest = function () {
//Maths to check here
};
Then in the forloop do...
rectangles[i].hitTest();
But I'm not sure on the Maths or where to go from there...
Any help would be appreciated, thanks in advance!
You can extend your rectangle object like this:
function rectangle(x, y, w, h) {
... existing code here ...
}
rectangle.prototype.intersects = function(rect) {
return !( rect.x > (this.x + this.w) ||
(rect.x + rect.w) < this.x ||
rect.y > (this.y + this.h) ||
(rect.y + rect.h) < this.y);
}
Based on this code by Daniel Vassallo, adopted for your object.
Now simply call the function on the rectangle you want to compare with:
if ( rectangles[x].intersects(rectangles[y]) ) {
... they intersect ...
}
To check if a new rectangle intersects with an existing you can do:
function isOverlapping(myNewRect, rectangles) {
for(var i = 0, r; r = rectangles[i]; i++) {
if (myNewRect.intersect(r)) return true;
}
return false;
}