I'm currently creating a little game to learn to code in p5.js.
The bug I'm facing is when I try to shoot missils[array of object] the Keyboard Arrow at comets that fly around [also an array of objects]. In order to understand if the missils would shoot the comet, I created a class method that compare their distance and if their distance is less than for ex 20, both the missil and the comets are getting spliced from their array.
It works randomly, sometimes it works for 20 comets and sometimes it lags at the first encounter. I suspect that this has to do with the nested for loops that I'm using.
First of all I'm creating 2 objects MOVER every 5 seconds in the Setup function and store them into an array.
for(let i=0; i<2; i++) {
{
setInterval(
function(){
movertest = new Mover(random(400, width), random(400, height));
mover.push(movertest);
},
5000)
};
}
I basically created then a method called "destroy" in my object Mover, which indicates whether or not a missil is less then 20 pixels away.
destroy(px, py) {
if( dist(this.position.x, this.position.y, px, py) <= 20) {
return true
} else {
return false;
}
}
and then when I summon those functions in the draw functions of P5.js, it is lagging.
for (i=0; i < missil.length; i++) {
missil[i].show();
missil[i].update();
for (p=0; p < planets.length; p++) {
missil[i].bounce(planets[p].position.x, planets[p].position.y, planets[p].lrect/2)
};
//if missil is in the canvas then check for collision
if (missil[i].contains(width/2,height/2)) {
for (let u = 0; u < mover.length; u++) {
if (mover[u].destroy(missil[i].position.x, missil[i].position.y)) {
mover.splice(u,1);
missil.splice(i,1);
console.log(u);
console.log(i)
};
}
} else {
missil.splice(i,1)
}
} // if missil is out of the canvas it get erased from the array.
If you would like to help me that would be super appreciated! If you want to play the game to understand the error, you can move green rectangle with your mouse, and avoid the comets and shoot them with the Keyboard arrow! thanks a lot ! :)
Here is the entire code:
let mover = [];
let x = 0;
let collision = 0; //counter to know when to end the game
let collu = 0;
let lrect = 10; //size of the ship.
let accslider, velslider;
let shoot = false; //to know if to shoot a missil.
let started = true;
let movertest = [];
//number of missil.
let missil = [];
let outofcanvas;
let a = 0;
let b = 0;
let munitions = 100;
let planets = [];
let cron;
function windowalert() {
if (confirm("Votre score est de rejouer?")) {
location.reload()
} else {
location.close();
}
}
function setup() {
background(0, 1);
cnv = createCanvas(900, 600);
for (let i = 0; i < 2; i++) {
setInterval(function() {
movertest = new Mover(random(400, width), random(400, height));
mover.push(movertest);
}, 5000)
}
for (p = 0; p < 4; p++) {
planets[p] = new Planet(100, 100, 20 + p * 20, 20 + p * 20)
}
ship = new Ship(300, 300);
accslider = createSlider(0, 255, 100);
accslider.position(width + 20, 20);
// noLoop(); // putted here since loop is when pressed the button start => function
}
function draw() {
text(munitions, 80, 20);
if (started) {
background(0, 50);
for (let i = 0; i < mover.length; i++) {
mover[i].show();
mover[i].update(x);
mover[i].edge();
// if rollover/ contains is true => then change collision +1 => collsison arrives at 255=> you are dead.
if (mover[i].contains(mouseX, mouseY)) {
collision += 1;
lrect += 0.04;
}
}
if (collision >= 255) {
clearInterval(cron);
started = false;
windowalert()
}
ship.move(mouseX, mouseY);
//ship.impact(mover[i].position.x,mover[i].position.y)
ship.show();
ship.edge();
noCursor();
x += 0.00005;
for (p = 0; p < planets.length; p++) {
planets[p].show(50 + p * 10, 180 + p * 40, 120 + p * 10);
planets[p].move();
}
for (i = 0; i < missil.length; i++) {
missil[i].show();
missil[i].update();
for (p = 0; p < planets.length; p++) {
missil[i].bounce(planets[p].position.x, planets[p].position.y, planets[p].lrect / 2)
}
//if missil is in the canvas then check for collision
if (missil[i].contains(width / 2, height / 2)) {
for (let u = 0; u < mover.length; u++) {
if (mover[u].destroy(missil[i].position.x, missil[i].position.y)) {
mover.splice(u, 1);
missil.splice(i, 1);
console.log(u);
console.log(i)
};
}
} else {
missil.splice(i, 1)
}
}
}
} // if missil is out of the canvas it get erased from the array.
setInterval(function() {
if (munitions < 100) {
munitions += 1
}
}, 1000);
function keyPressed() {
if (munitions > 0) {
if (keyIsDown(LEFT_ARROW))
{
a = -1;
munitions += -1
} // a is in the class munitions and represent the vector x. I did it like that so when we click both arrow it goes in diagonal.
if (keyIsDown(RIGHT_ARROW))
{
a = 1;
munitions += -1
}
if (keyIsDown(UP_ARROW)) {
b = -1;
munitions += -1
}
if (keyIsDown(DOWN_ARROW))
{
b = 1;
munitions += -1
}
for (let u = 0; u < 1; u++) {
let mi = new Missil(mouseX, mouseY, a, b);
missil.push(mi);
}
}
}
function keyReleased() {
if (keyCode == LEFT_ARROW) {
a = 0
} // this was implemented to reput the missil vector at the default value when released the key.
if (keyCode == RIGHT_ARROW) {
a = 0
}
if (keyCode == UP_ARROW) {
b = 0
}
if (keyCode == DOWN_ARROW) {
b = 0
}
}
class Missil {
constructor(x, y, a, b) //partira de mx,my.
{
this.position = createVector(x, y);
this.vel = createVector(a, b);
this.vel.mult(random(2, 4))
}
update() {
this.position = this.position.add(this.vel);
}
show() {
stroke(255);
noStroke();
fill(255, 0, 0, 100);
ellipse(this.position.x, this.position.y, 5);
}
contains(px, py) {
if (dist(this.position.x, this.position.y, px, py) < width / 2) {
return true
} else {
return false
}
}
bounce(px, py, dista) {
{
if (dist(this.position.x, this.position.y, px, py) < dista) {
let v = createVector(this.position.x - px, this.position.y - py);
this.vel = this.vel.mult(1.5).reflect(v)
}
}
}
}
class Planet {
constructor(x, y, lrect, lrect2) {
this.position = createVector(x, y)
this.vel = p5.Vector.random2D();
this.lrect = lrect;
this.lrect2 = lrect2;
}
show(r, g, b) {
fill(r, g, b);
noStroke();
ellipseMode(CENTER);
ellipse(this.position.x, this.position.y, this.lrect, this.lrect2)
stroke(255);
}
move() {
let center = createVector(width / 2, height / 2)
this.gravityacc = p5.Vector.sub(center, this.position);
this.gravityacc.setMag(0.004);
this.vel = this.vel.add(this.gravityacc);
this.position = this.position.add(this.vel);
this.vel.limit(1.3);
}
}
class Mover { //those are the comets
constructor(x, y) {
this.position = createVector(x, y);
this.vel = p5.Vector.random2D();
this.vel.mult(random(3));
//this.acc=p5.Vector.random2D();// acceleeration is a a random vector here.
// this.acc.setMag(0.01); // magnitude of acceleration is slow. Acceleration is a vector.
// this.vel.limit(3); // shrinks size of vector to 5, but if it smaller then 5 then it doent equal to 5 like in setMag().
}
update(speed)
{
setInterval(function() {
this.speed += 0.01
}, 3000);
let mouse = createVector(mouseX, mouseY);
this.acc = p5.Vector.sub(mouse, this.position);
this.acc.setMag(0.04)
this.acc.limit(0.1)
this.vel.add(this.acc); /// add acceleration to velocitiy.
this.position.add(this.vel);
this.vel.limit(5);
}
show() {
stroke(255, 10);
strokeWeight(0);
fill(map(this.position.x, 0, width, 0, 255), map(this.position.y, 0, height, 0, 255), 255, 255);
ellipse(this.position.x, this.position.y, 5)
}
edge() {
if (this.position.x >= width) {
let n = createVector(-1, 0);
this.vel = this.vel.reflect(n)
}
if (this.position.x <= 0) {
let n = createVector(1, 0);
this.vel = this.vel.reflect(n)
}
if (this.position.y >= height) {
let n = createVector(0, -1);
this.vel = this.vel.reflect(n)
}
if (this.position.y <= 0) {
let n = createVector(0, 1);
this.vel = this.vel.reflect(n)
}
}
contains(px, py) {
if (dist(this.position.x, this.position.y, px, py) < 5 + lrect) {
return true
} else {
return false
}
}
destroy(px, py) {
if (dist(this.position.x, this.position.y, px, py) <= 20) {
return true
} else {
return false;
}
}
}
class Ship {
constructor(x, y) {
this.position = createVector(x, y);
this.vel = createVector();
this.acc = createVector();
}
move(px, py) {
this.position.x = px;
this.position.y = py
} //if key pressed.
edge() {
if (this.position.x >= width) {
this.position.x = width
}
if (this.position.y >= height - 50) {
this.position.y = height - 50
}
}
show() {
stroke(255);
strokeWeight(0);
fill(collision * 1, 255 - collision * 2, 0, 100);
rect(this.position.x, this.position.y, lrect, lrect)
}
}
/* Without the HTML this isn't functional
"use strict";
document.form_main.start.onclick = () => start();
document.form_main.pause.onclick = () => pause();
document.form_main.reset.onclick = () => reset();
function start() {
pause();
cron = setInterval(() => {
timer();
}, 10);
started = true; // to indicate to start draw
loop(); // noLoop in fucntion setup.
}
function pause() {
clearInterval(cron);
started = false;
}
function reset() {
location.reload();
}
function timer() {
if ((millisecond += 10) == 1000) {
millisecond = 0;
second++;
}
if (second == 60) {
second = 0;
minute++;
}
if (minute == 60) {
minute = 0;
hour++;
}
document.getElementById('hour').innerText = returnData(hour);
document.getElementById('minute').innerText = returnData(minute);
document.getElementById('second').innerText = returnData(second);
document.getElementById('millisecond').innerText = returnData(millisecond);
}
function returnData(input) {
return input > 10 ? input : `0${input}`
} */
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
The problem is in the the missil/mover collision detection loop:
You are looping through all of the "missils"
For each missil you loop through all the movers
In the event of a collision you remove both the mover and the missil
But you continue looping with the current value of i, which may now be past the end of the array!
As a result you are getting an error sometimes because on a subsequent pass through the mover loop missil[i] is undefined. Any time you update an array you are currently looping over you need to be careful to update your indices and re-check your length before continuing.
// 1. You are looping through all of the "missils"
for (i = 0; i < missil.length; i++) {
// ...
// 2. For each missil you loop through all the movers
for (let u = 0; u < mover.length; u++) {
if (mover[u].destroy(missil[i].position.x, missil[i].position.y)) {
// 3. In the event of a collision you remove both the mover and the missil
mover.splice(u, 1);
missil.splice(i, 1);
console.log(u);
console.log(i)
}
// 4. But you continue looping with the current value of i, which may now be past the end of the array!
}
Here is a fixed version of your sketch:
let mover = [];
let x = 0;
let collision = 0; //counter to know when to end the game
let collu = 0;
let lrect = 10; //size of the ship.
let accslider, velslider;
let shoot = false; //to know if to shoot a missil.
let started = true;
let movertest = [];
//number of missil.
let missil = [];
let outofcanvas;
let a = 0;
let b = 0;
let munitions = 100;
let planets = [];
let cron;
function windowalert() {
if (confirm("Votre score est de rejouer?")) {
location.reload()
} else {
location.close();
}
}
function setup() {
background(0, 1);
cnv = createCanvas(900, 600);
for (let i = 0; i < 2; i++) {
setInterval(function() {
movertest = new Mover(random(400, width), random(400, height));
mover.push(movertest);
}, 5000)
}
for (p = 0; p < 4; p++) {
planets[p] = new Planet(100, 100, 20 + p * 20, 20 + p * 20)
}
ship = new Ship(300, 300);
accslider = createSlider(0, 255, 100);
accslider.position(width + 20, 20);
// noLoop(); // putted here since loop is when pressed the button start => function
}
function draw() {
text(munitions, 80, 20);
if (started) {
background(0, 50);
for (let i = 0; i < mover.length; i++) {
mover[i].show();
mover[i].update(x);
mover[i].edge();
// if rollover/ contains is true => then change collision +1 => collsison arrives at 255=> you are dead.
if (mover[i].contains(mouseX, mouseY)) {
collision += 1;
lrect += 0.04;
}
}
if (collision >= 255) {
clearInterval(cron);
started = false;
windowalert()
}
ship.move(mouseX, mouseY);
//ship.impact(mover[i].position.x,mover[i].position.y)
ship.show();
ship.edge();
noCursor();
x += 0.00005;
for (p = 0; p < planets.length; p++) {
planets[p].show(50 + p * 10, 180 + p * 40, 120 + p * 10);
planets[p].move();
}
for (i = 0; i < missil.length; i++) {
missil[i].show();
missil[i].update();
for (p = 0; p < planets.length; p++) {
missil[i].bounce(planets[p].position.x, planets[p].position.y, planets[p].lrect / 2)
}
//if missil is in the canvas then check for collision
if (missil[i].contains(width / 2, height / 2)) {
let colission = false;
for (let u = 0; u < mover.length; u++) {
if (mover[u].destroy(missil[i].position.x, missil[i].position.y)) {
mover.splice(u, 1);
missil.splice(i, 1);
// Exit the mover loop immediately
colission = true;
break;
}
}
if (colission) {
// because we've deleted the item at i, the item that was at
// i + 1 is now at i, so in order not to skip that item we
// need to decrement i before continuing
i--;
}
} else {
missil.splice(i, 1);
i--;
}
}
}
} // if missil is out of the canvas it get erased from the array.
setInterval(function() {
if (munitions < 100) {
munitions += 1
}
}, 1000);
function keyPressed() {
if (munitions > 0) {
if (keyIsDown(LEFT_ARROW))
{
a = -1;
munitions += -1
} // a is in the class munitions and represent the vector x. I did it like that so when we click both arrow it goes in diagonal.
if (keyIsDown(RIGHT_ARROW))
{
a = 1;
munitions += -1
}
if (keyIsDown(UP_ARROW)) {
b = -1;
munitions += -1
}
if (keyIsDown(DOWN_ARROW))
{
b = 1;
munitions += -1
}
for (let u = 0; u < 1; u++) {
let mi = new Missil(mouseX, mouseY, a, b);
missil.push(mi);
}
}
}
function keyReleased() {
if (keyCode == LEFT_ARROW) {
a = 0
} // this was implemented to reput the missil vector at the default value when released the key.
if (keyCode == RIGHT_ARROW) {
a = 0
}
if (keyCode == UP_ARROW) {
b = 0
}
if (keyCode == DOWN_ARROW) {
b = 0
}
}
class Missil {
constructor(x, y, a, b) //partira de mx,my.
{
this.position = createVector(x, y);
this.vel = createVector(a, b);
this.vel.mult(random(2, 4))
}
update() {
this.position = this.position.add(this.vel);
}
show() {
stroke(255);
noStroke();
fill(255, 0, 0, 100);
ellipse(this.position.x, this.position.y, 5);
}
contains(px, py) {
if (dist(this.position.x, this.position.y, px, py) < width / 2) {
return true
} else {
return false
}
}
bounce(px, py, dista) {
{
if (dist(this.position.x, this.position.y, px, py) < dista) {
let v = createVector(this.position.x - px, this.position.y - py);
this.vel = this.vel.mult(1.5).reflect(v)
}
}
}
}
class Planet {
constructor(x, y, lrect, lrect2) {
this.position = createVector(x, y)
this.vel = p5.Vector.random2D();
this.lrect = lrect;
this.lrect2 = lrect2;
}
show(r, g, b) {
fill(r, g, b);
noStroke();
ellipseMode(CENTER);
ellipse(this.position.x, this.position.y, this.lrect, this.lrect2)
stroke(255);
}
move() {
let center = createVector(width / 2, height / 2)
this.gravityacc = p5.Vector.sub(center, this.position);
this.gravityacc.setMag(0.004);
this.vel = this.vel.add(this.gravityacc);
this.position = this.position.add(this.vel);
this.vel.limit(1.3);
}
}
class Mover { //those are the comets
constructor(x, y) {
this.position = createVector(x, y);
this.vel = p5.Vector.random2D();
this.vel.mult(random(3));
//this.acc=p5.Vector.random2D();// acceleeration is a a random vector here.
// this.acc.setMag(0.01); // magnitude of acceleration is slow. Acceleration is a vector.
// this.vel.limit(3); // shrinks size of vector to 5, but if it smaller then 5 then it doent equal to 5 like in setMag().
}
update(speed)
{
setInterval(function() {
this.speed += 0.01
}, 3000);
let mouse = createVector(mouseX, mouseY);
this.acc = p5.Vector.sub(mouse, this.position);
this.acc.setMag(0.04)
this.acc.limit(0.1)
this.vel.add(this.acc); /// add acceleration to velocitiy.
this.position.add(this.vel);
this.vel.limit(5);
}
show() {
stroke(255, 10);
strokeWeight(0);
fill(map(this.position.x, 0, width, 0, 255), map(this.position.y, 0, height, 0, 255), 255, 255);
ellipse(this.position.x, this.position.y, 5)
}
edge() {
if (this.position.x >= width) {
let n = createVector(-1, 0);
this.vel = this.vel.reflect(n)
}
if (this.position.x <= 0) {
let n = createVector(1, 0);
this.vel = this.vel.reflect(n)
}
if (this.position.y >= height) {
let n = createVector(0, -1);
this.vel = this.vel.reflect(n)
}
if (this.position.y <= 0) {
let n = createVector(0, 1);
this.vel = this.vel.reflect(n)
}
}
contains(px, py) {
if (dist(this.position.x, this.position.y, px, py) < 5 + lrect) {
return true
} else {
return false
}
}
destroy(px, py) {
if (dist(this.position.x, this.position.y, px, py) <= 20) {
return true
} else {
return false;
}
}
}
class Ship {
constructor(x, y) {
this.position = createVector(x, y);
this.vel = createVector();
this.acc = createVector();
}
move(px, py) {
this.position.x = px;
this.position.y = py
} //if key pressed.
edge() {
if (this.position.x >= width) {
this.position.x = width
}
if (this.position.y >= height - 50) {
this.position.y = height - 50
}
}
show() {
stroke(255);
strokeWeight(0);
fill(collision * 1, 255 - collision * 2, 0, 100);
rect(this.position.x, this.position.y, lrect, lrect)
}
}
/* Without the HTML this isn't functional
"use strict";
document.form_main.start.onclick = () => start();
document.form_main.pause.onclick = () => pause();
document.form_main.reset.onclick = () => reset();
function start() {
pause();
cron = setInterval(() => {
timer();
}, 10);
started = true; // to indicate to start draw
loop(); // noLoop in fucntion setup.
}
function pause() {
clearInterval(cron);
started = false;
}
function reset() {
location.reload();
}
function timer() {
if ((millisecond += 10) == 1000) {
millisecond = 0;
second++;
}
if (second == 60) {
second = 0;
minute++;
}
if (minute == 60) {
minute = 0;
hour++;
}
document.getElementById('hour').innerText = returnData(hour);
document.getElementById('minute').innerText = returnData(minute);
document.getElementById('second').innerText = returnData(second);
document.getElementById('millisecond').innerText = returnData(millisecond);
}
function returnData(input) {
return input > 10 ? input : `0${input}`
} */
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.3.1/p5.js"></script>
I can't for the life of me work out how to reset the function createAliens below so I can begin a new game - I'm basically looking for a way to clear the sprites off the canvas so I can reset the game.
Any help would be seriously appreciated :)
const BORDER = 60;
const SPEED = 3;
let score = 0;
let numAliens = 3;
let alienSpeed = 5;
let aliensArray = [];
let ship;
let laser;
let lasers = [];
function preload() {
}
function setup() {
createCanvas(1000, 700);
aliens = new Group();
ships = new Group();
lasers = new Group();
createAliens(numAliens);
ship = createSprite(width/2, height/1.15, 40, 60);
ship.setCollider('rectangle', 0, 0, 40, 60);
ships.add(ship);
}
function draw() {
background(0);
if(aliens == 0) {
createAliens(numAliens + 2);
}
aliens.bounce(aliens); // p5 game methods - collision etc using callbacks
aliens.overlap(lasers, scoreTotal);
aliens.collide(lasers, die);
ship.bounce(aliens, reset);
keyPressed();
drawSprites();
for (let i = 0; i < allSprites.length; i++) { // game borderless
let all = allSprites[i];
if (all.position.x < - BORDER) {
all.position.x = width + BORDER;
}
if (all.position.x > width + BORDER) {
all.position.x = - BORDER;
}
if (all.position.y < - BORDER) {
all.position.y = height + BORDER;
}
if (all.position.y > height + BORDER) {
all.position.y = - BORDER;
}
}
}
function createAliens(numAliens) { // spawn some aliens
for (let j = 0; j < numAliens; j++) {
alien = createSprite(random(width), 0, 50, 60);
alien.shapeColor = color('red');
alien.setSpeed(random(0.3, alienSpeed), random(45, 150));
aliensArray.push(alien);
aliens.add(alien);
}
}
function die(alien) { // kill the alien
alien.remove();
}
function scoreTotal() {
score += 10;
}
function reset() {
console.log('RESET FIRING');
}
function keyPressed() {
if (keyDown(LEFT_ARROW)) {
ship.setSpeed(SPEED, 180);
ship.friction = 0.01;
}
else if (keyDown(RIGHT_ARROW)) {
ship.setSpeed(SPEED, 0);
ship.friction = 0.01;
}
else if (keyDown(UP_ARROW)) {
ship.setSpeed(SPEED, 270);
ship.friction = 0.01;
}
else if (keyDown(DOWN_ARROW)) {
ship.setSpeed(SPEED, 90);
ship.friction = 0.01;
}
if(keyWentDown(' ')) {
let laser = createSprite(ship.position.x, ship.position.y, 5, 5);
laser.setSpeed(10, 270);
laser.shapeColor = color('red');
laser.life = 30;
lasers.add(laser);
}
}
I have got the aliens spawning with the simple conditional logic:
if(aliens == 0) {
createAliens(numAliens + 2);
}
As of now, all I know to be certain is to set the global variable of 'paused' to be false. Adding an eventlistener and updating my loop function, etc. is where I am uncertain on implementation, otherwise the game is "finished" by all means!
var canvas = document.getElementById('canvas');
canvas.width = 1280;
canvas.height = 700;
var ctx = canvas.getContext('2d');
let obstacles = [];
var cancelMe = '';
let difficulty = 10;
let id;
let dis = 0;
let miles = 0;
let paused = false;
function getScore() {
let highScore = localStorage.getItem('highscore');
console.log('highscore is ', highScore);
document.getElementById('score').innerHTML = 'Highscore: ' + highScore + ' ft.';
}
getScore();
function saveScore(score) {
let highScore;
if (!isNaN(localStorage.getItem('highscore'))) {
highScore = localStorage.getItem('highscore');
} else {
highScore = 0;
}
console.log(highScore);
highScore = Math.max(score, highScore);
localStorage.setItem('highscore', highScore);
}
var img = new Image();
img.src = './images/background.jpg';
img.onload = function() {
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
};
var durianImg = new Image();
durianImg.src = './images/durian.png';
durianImg.onload;
var backgroundImage = {
img: img,
x: 0,
speed: -1.5,
move: function() {
backgroundImage.x += this.speed;
backgroundImage.x %= canvas.width;
sprite.distance += 0.2;
},
draw: function() {
ctx.drawImage(this.img, this.x, 0);
if (this.speed < 0) {
ctx.drawImage(this.img, this.x + canvas.width, 0);
} else {
ctx.drawImage(this.img, this.x - this.img.width, 0);
}
}
};
var timeFalling = 0;
function clamp(num, min, max) {
return num <= min ? min : num >= max ? max : num;
}
var sprite = {
name: 'Mr. Sprite',
x: 2,
y: 528,
distance: 0,
int: null,
moveLeft: function() {
sprite.x -= 30;
sprite.x = clamp(this.x, 0, 1280);
sprite.distance -= 30;
},
moveRight: function() {
sprite.x += 30;
sprite.x = clamp(this.x, 0, 1230);
sprite.distance += 30;
},
moveUp: function() {
if ((sprite.y = 528)) {
sprite.y -= 70;
this.beginFall();
}
},
beginFall: function() {
clearInterval(this.int);
timeFalling = 0;
this.int = setInterval(function() {
timeFalling = timeFalling + 1;
}, 10);
},
draw: function() {
spriteImg = new Image();
spriteImg.src = './images/sprite.png';
ctx.drawImage(spriteImg, sprite.x, sprite.y, 50, 60);
},
fall: function() {
if (this.y < 528) {
this.y += 9.8 * timeFalling / 150;
} else {
clearInterval(this.int);
this.y = 528;
}
}
};
class obstacle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
fall() {
if (this.y < 528) {
this.y++;
}
}
}
document.onkeydown = function(e) {
switch (e.keyCode) {
case 37:
case 65:
sprite.moveLeft();
console.log('left', sprite);
break;
case 38:
case 87:
case 32:
sprite.moveUp();
console.log('right', sprite);
break;
case 39:
case 68:
sprite.moveRight();
console.log('right', sprite);
break;
}
};
function checkCollision(obstacle) {
if (obstacle.y + 60 > sprite.y && obstacle.y < sprite.y + 60) {
if (obstacle.x + 50 < sprite.x + 50 && obstacle.x + 50 > sprite.x) {
console.log('Collision');
gameOver();
} else if (obstacle.x < sprite.x + 41 && obstacle.x > sprite.x) {
console.log('Collision');
gameOver();
}
}
}
function updateCanvas() {
backgroundImage.move();
ctx.clearRect(0, 0, canvas.width, canvas.height);
backgroundImage.draw();
dis++;
if (dis % 20 == 0) {
miles++;
}
ctx.fillStyle = '#606060';
ctx.fillText('Distance Traversed: ' + miles + ' ft.', 540, 40);
sprite.draw();
sprite.fall();
if (dis % 40 == 0) {
obstacles.push(randomObstacle());
}
for (let i = 0; i < obstacles.length; i++) {
obstacles[i].draw();
obstacles[i].fall();
checkCollision(obstacles[i]);
if (obstacles[i].y > 520) obstacles.splice(i, 1);
}
}
function startGame() {
difficulty = Number(document.querySelector('#diffSelect').value);
id = setInterval(updateCanvas, difficulty);
startGameButton.disabled = true;
init();
loop();
}
var startGameButton = document.getElementById('startGameButton');
startGameButton.onclick = startGame;
function restartGame() {
clearInterval(id);
obstacles = [];
var timeFalling = 0;
sprite.x = 2;
sprite.y = 528;
sprite.distance = 0;
sprite.int = null;
dis = 0;
miles = 0;
fallSpeed = 1.0005;
startGameButton.disabled = false;
ctx.fillStyle = 'white';
ctx.font = '18px serif';
ctx.clearRect(0, 0, canvas.width, canvas.height);
backgroundImage.draw();
audio.pause();
location.reload();
}
var retryGameButton = document.getElementById('retryGameButton');
retryGameButton.onlick = restartGame;
ctx.fillStyle = 'white';
ctx.font = '18px serif';
function randomObstacle() {
let x = Math.random() * canvas.width;
let y = 0;
return new Durian(x, y);
}
let fallSpeed = 1.0003;
setInterval(function() {
fallSpeed += 0.0008; // tweak this to change how quickly it increases in difficulty
// console.log(fallSpeed);
}, 8000); // timer at which it gets harder
class Durian {
constructor(x, y) {
this.x = x;
this.y = y;
}
draw() {
ctx.drawImage(durianImg, this.x, this.y, 50, 60);
}
fall() {
if (this.y < 528) this.y = (this.y + 1) ** fallSpeed;
this.x -= 1.5;
}
}
var hotbod = document.querySelector('body');
function doStuff() {
hotbod.className += ' animate';
}
window.onload = function() {
doStuff();
};
function gameOver() {
clearInterval(id);
ctx.fillStyle = '#606060';
ctx.font = '70px Anton';
ctx.fillText('GAME OVER', 430, 300);
console.log('save ', miles);
saveScore(miles);
audio.pause();
new Audio('sounds/game_over.wav').play();
}
function init() {
audio = document.getElementById('audio');
// add listener function to loop on end
audio.addEventListener('ended', loop, false);
// set animation on perpetual loop
setInterval(animate);
}
function loop() {
audio.play();
}
And for my index.html where the buttons are displayed:
<div id="menu">
<div class="custom-select instruct">
<select id="diffSelect">
<option value="6.5">Easy</option>
<option value="5.5">Medium</option>
<option value="4.5">Hard</option>
<option value="3">Extreme</option>
</select>
</div>
<input id="startGameButton" type="button" class="instruct" onclick="startGame()" value="Start" />
<input id="retryGameButton" type="button" class="instruct" onclick="restartGame()" value="Reset" />
<p class="disclaimer">DISCLAIMER: Once you wipe out, hit reset & change to a higher difficulty if you dare, then hit start to play again!</p>
</div>
Try the following
btw any ... represents your code I didn't include to save space
...
let gameRunning = false;
...
document.onkeydown = function(e) {
switch (e.keyCode) {
case 80:
if(gameRunning) {
paused = !paused;
startGameButton.value = paused ? "Un-Pause" : "Pause";
}
break;
...
}
};
...
function startGame() {
if(gameRunning){
paused = !paused;
startGameButton.value = paused ? "Un-Pause" : "Pause";
}
else {
difficulty = Number(document.querySelector('#diffSelect').value);
id = setInterval(updateCanvas, difficulty);
gameRunning = true;
startGameButton.value = "Pause";
init();
loop();
}
}
...
I have a game in which there si a rocket. When rockets health is 0 the game over screen should appear and when any key is pressed the game should restart.
I tried using redraw and loop keywords in p5.js
let x = 240;
let x1 = 258;
let score = 0;
let health = 5;
let opelsins = [];
let ecllipseOpelsin = [];
let monsterimg;
let meteorimg;
let inGameSound;
let opelsinimg;
let gameOverSound;
let backgroundsun;
let gameoverScreen;
function collideRectangleCircle(rx, ry, rw, rh, cx, cy, cr)
{
return rx+rw > cx-cr && cx+cr > rx && ry+rh > cy-cr && cy+cr > ry;
}
function Opelsin() {
this.x = random(40,560);
this.y = random(-200,-190);
this.speed = random(3,10);
this.fall = function() {
this.y = this.y + this.speed;
if (this.y > height) {
this.y = random(-200,-100);
this.x = random(40,560);
this.speed = random(3, 10);
}
};
this.show = function() {
fill(255)
ellipse(this.x + 15,this.y + 34, 10, 10)
image(opelsinimg,this.x,this.y, 40, 40)
};
}
function opelsinmodel() {
this.x = random(0,600);
this.y = random(-300,-310);
this.speed = random(3,10);
this.show = function() { ellipse(this.x,this.y, 20, 20) };
}
function setup() {
createCanvas(600, 400);
frameRate(300)
inGameSound.setVolume(1);
inGameSound.loop();
interval = setInterval(scoreCount, 500);
}
function gameOver() {
textSize(20);
text("GAME OVER", 250, 200);
text("SCORE: " + score, 270, 220);
fill(255);
}
function newGame() {
if (keyIsPressed === true) {
//redraw();
loop();
}
}
function preload() {
soundFormats('m4a')
monsterimg = loadImage('assets/monster.png');
opelsinimg = loadImage('assets/opelsin.png');
inGameSound = loadSound('assets/spaceBotInGameMusic.m4a');
gameOverSound = loadSound('assets/gameOverInGameSound.m4a');
backgroundsun = loadImage('assets/backgroundsun.jpg');
gameoverScreen = loadImage('assets/gameoverScreen.png');
}
function scoreCount() {
score++;
}
function draw() {
// background(11, 72, 170);
image(backgroundsun, 0, 0, 700, 400);
if (score == 0) {
for (let i = 0; i < 5; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
} if (score == 50) {
for (let i = 0; i < 10; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 100) {
for (let i = 0; i < 15; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 150) {
for (let i = 0; i < 20; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (score == 200) {
for (let i = 0; i < 25; i ++) {
opelsins[i] = new Opelsin();
ecllipseOpelsin[i] = new opelsinmodel();
}
}
if (keyIsDown(LEFT_ARROW) && x > -14) {
x -= 5;
}
if (keyIsDown(RIGHT_ARROW) && x < 550) {
x += 5;
}
if (keyIsDown(LEFT_ARROW) && x1 > 9) {
x1 -= 5;
}
if (keyIsDown(RIGHT_ARROW) && x1 < 565) {
x1 += 5;
}
fill(255, 255, 0)
rect(x1, 345, 20, 20)
image(monsterimg,x,310,60,60)
for (let opelsin of opelsins) {
opelsin.fall();
opelsin.show();
}
textSize(20);
text("Health: " + health, 10, 20);
fill(255);
textSize(20);
text("Score: " + score, 10, 40);
fill(255);
for (let opelsin of opelsins) {
hit = collideRectCircle(x1, 335, 20, 30, opelsin.x, opelsin.y, 40);
if(hit == true) {
health -= 1;
opelsin.y = height+1;
if (health == 0) {
inGameSound.stop();
gameOverSound.setVolume(1);
gameOverSound.loop();
image(gameoverScreen, 0, 0, 600, 400);
gameOver();
noLoop();
newGame();
}
}
}
}
What I expect is when the game over screen appears and then when the random key is pressed the game should restart.
The issue is that the game loop is stopped by noLoop() when the game is over. The loop is never restarted.
Set a state (e.g waitRestart) when the game is over (instead of newGame()):
let waitRestart = false;
function draw() {
// [...]
for (let opelsin of opelsins) {
hit = collideRectCircle(x1, 335, 20, 30, opelsin.x, opelsin.y, 40);
if(hit == true) {
health -= 1;
opelsin.y = height+1;
if (health == 0) {
inGameSound.stop();
gameOverSound.setVolume(1);
gameOverSound.loop();
image(gameoverScreen, 0, 0, 600, 400);
gameOver();
noLoop();
// newGame(); <----- delete
waitRestart = true; // <----- wait for restart
}
}
}
}
Add a keyPressed() callback instead of the newGame() function, which restarts the game and set all initial states like health and score:
function keyPressed() {
if (waitRestart) {
waitRestart = false;
score = 0;
health = 5;
loop();
}
}
I stuck in one place for few hours, so I decided to go for help here. I'm beginner and i wish to try write a simple pong game.
At this link in Khan Academy you'll see result.
KHAN ACADEMY my pong game
My issue is:
I can't move two players at once. Only player can move - who hit last the keyboard. Last hit key win.
I know there are few ready pong games, but a lot of it is in Java, or all different logic. Can you help me good people? :)
//THIS IS GAME FOR 2 PEOPLE
//PLAYER 1 CONTROLS: UP ARROW (MOVE UP), DOWN ARROW (MOVE DOWN)
//PLAYER 2 CONTROLS: W KEY (MOVE UP), S KEY (MOVE DOWN)
var player1Y = height/2;
var player2Y = height/2;
var player1Score = 0;
var player2Score = 0;
var ball;
var gameStarted = false;
var t = 0;
//Constants
var PAUSE_TIME = 60;
var PLAYER_MOVE_SPEED = 2;
var BALL_SPEED = 3;
var PADDLE_HEIGHT = 80;
var PADDLE_WIDTH = 8;
angleMode = "degrees";
var Ball = function(position, speed) {
this.position = position;
this.speed = speed || BALL_SPEED;
this.radius = 6;
this.resetVelocity = function() {
this.theta = random(0, 75);
this.velocity = new PVector(
this.speed*cos(this.theta), -this.speed*sin(this.theta));
};
this.resetVelocity();
this.draw = function() {
fill(0, 0, 0);
noStroke();
ellipse(this.position.x, this.position.y,
this.radius*2, this.radius*2);
};
this.collideWithPaddle = function(x, y) {
if (this.position.x - this.radius < x + PADDLE_WIDTH/2 &&
this.position.x + this.radius > x - PADDLE_WIDTH/2) {
if (dist(0, this.position.y, 0, y) <
PADDLE_HEIGHT/2 + this.radius) {
if (this.position.x > x) {
this.position.x = x +
this.radius + PADDLE_WIDTH/2;
}
else if (this.position.x < x) {
this.position.x = x -
this.radius - PADDLE_WIDTH/2;
}
this.velocity.mult(new PVector(-1, 1));
}
}
};
this.update = function() {
//Handle wall collisions
if (this.position.x < 0) {
player2Score++;
this.position = new PVector(width/2, height/2);
gameStarted = false;
this.resetVelocity();
}
else if (this.position.x > width) {
player1Score++;
this.position = new PVector(width/2, height/2);
gameStarted = false;
this.resetVelocity();
}
if (this.position.y < 0) {
this.position.y = 0;
this.velocity.mult(new PVector(1, -1));
}
else if (this.position.y > height) {
this.position.y = height;
this.velocity.mult(new PVector(1, -1));
}
//Handle paddle collisions
this.collideWithPaddle(20, player1Y);
this.collideWithPaddle(width-20, player2Y);
this.position.add(this.velocity);
};
};
ball = new Ball(new PVector(width/2, height/2));
var drawScores = function() {
var s;
fill(0, 0, 0);
textSize(16);
s = "Player 1: " + player1Score;
text(s, width*0.25-textWidth(s)/2, 25);
s = "Player 2: " + player2Score;
text(s, width*0.75-textWidth(s)/2, 25);
};
//Move the player1 up
var movePlayer1Up = function() {
player1Y -= PLAYER_MOVE_SPEED;
};
//Move the player1 down
var movePlayer1Down = function() {
player1Y += PLAYER_MOVE_SPEED;
};
//Move the player2 up
var movePlayer2Up = function() {
player2Y -= PLAYER_MOVE_SPEED;
};
//Move the player2 down
var movePlayer2Down = function() {
player2Y += PLAYER_MOVE_SPEED;
};
var drawPlayers = function() {
//Constrain the player movement
player1Y = constrain(player1Y, 0, 400);
player2Y = constrain(player2Y, 0, 400);
rectMode(CENTER);
fill(0, 0, 0);
rect(20, player1Y, PADDLE_WIDTH, PADDLE_HEIGHT);
rect(width-20, player2Y, PADDLE_WIDTH, PADDLE_HEIGHT);
};
draw = function() {
//Control Player 1
if (keyIsPressed) {
if (keyCode===38){
movePlayer1Up();
}
else if(keyCode===40) {
movePlayer1Down();
}
}
//Control Player 2
if (keyIsPressed) {
if (key.toString()==="w"){
movePlayer2Up();
}
else if(key.toString()==="s"){
movePlayer2Down();
}
}
//Draw the environment
background(255, 255, 255);
drawPlayers();
drawScores();
stroke(100, 100, 100);
line(width/2, 0, width/2, height);
//Draw the ball
ball.draw();
if (!gameStarted) {
t++;
if (t >= PAUSE_TIME) {
t = 0;
gameStarted = true;
}
return;
}
ball.update();
};
You should be watching the onkeyup, onkeydown events for moving players, see this related question here. JavaScript multiple keys pressed at once
Now I understand concept, and I just did something like that:
Scope for multiple keys:
var keys = [];
var keyPressed = function(){
keys[keyCode] = true;
};
var keyReleased = function(){
keys[keyCode] = false;
};
and drawing function:
//Controls
if (keys[87]) {
movePlayer2Up();
}
if (keys[83]) {
movePlayer2Down();
}
if (keys[38]) {
movePlayer1Up();
}
if (keys[40]) {
movePlayer1Down();
}
And now it's working! The same link to the Khan Academy - there's the effect. Thank you one more time.