javascript P5 function creates endless loop - javascript

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);
}

Related

Delay between each recursive call to function

I am trying to build a maze generator for a personal project. I have a recursive depth-first search function that recursively goes through each cell in the grid, checks if it has unvisited neighbors, then calls the recursive function again with the next neighbor. It is able to generate the maze just fine but I want to add a delay between each call to the recursive function so I can animate the creation of the maze as it visits each cell. Using the chrome debugger, it seems to do the 1s delay for the first iteration and then it stops waiting and jumps from the await delay back to the beginning of the function over and over without ever moving on. What am I doing wrong?
Here is the recursive function and delay function:
async function recursiveDFS(currentCell) {
await delay(1000);
highlightCell(currentCell);
currentCell.visited = true;
var [next, direction] = getNextNeighbor(currentCell);
while(typeof(next) != 'undefined') {
removeWall(currentCell, next, direction);
highlightCell(next);
recursiveDFS(next);
[next, direction] = getNextNeighbor(currentCell);
}
}
function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms)
});
}
and here is the full javascript code:
"use strict"
// declare globals
const numCols = 10;
const numRows = 10;
const cellSize = 50;
var grid = [];
// create canvas
var canvas = document.createElement('canvas');
canvas.id = 'canvas';
canvas.width = numCols * cellSize;
canvas.height = numRows * cellSize;
var body = document.getElementsByTagName("body")[0];
body.appendChild(canvas);
var context = canvas.getContext('2d');
function setup() {
createGrid();
const start = grid[0][0]; // start at top left cell
const end = grid[1][1];
recursiveDFS(start);
}
class Cell {
constructor(col, row) {
this.col = col;
this.row = row;
this.neighbors = {};
this.walls = {
top: true,
right: true,
bottom: true,
left: true
};
this.visited = false;
}
setNeighbors() {
//top
if(this.row - 1 >= 0) {
this.neighbors.top = grid[this.col][this.row - 1];
}
//right
if (this.col + 1 < numCols) {
this.neighbors.right = grid[this.col + 1][this.row];
}
//bottom
if (this.row + 1 < numRows) {
this.neighbors.bottom = grid[this.col][this.row + 1];
}
//left
if (this.col - 1 >= 0) {
this.neighbors.left = grid[this.col - 1][this.row];
}
}
}
// create 2d array of Cell objects
// indexing as grid[col][row]
// grid = [[(0,0), (1,0)],
// [(0,1), (1,1)]]
function createGrid() {
for (var col = 0; col < numCols; col++) {
var colArr = []
for (var row = 0; row < numRows; row++) {
var cell = new Cell(col, row);
colArr.push(cell);
drawGridLines(cell);
}
grid.push(colArr);
}
for (var row = 0; row < numRows; row++) {
for (var col = 0; col < numCols; col++) {
grid[col][row].setNeighbors();
}
}
}
// return single neighbor randomized from all possible neighbors
function getNextNeighbor(cell) {
if (cell.neighbors) {
var neighbors = [];
for (var neighbor in cell.neighbors) {
if (cell.neighbors[neighbor].visited === false){
neighbors.push([cell.neighbors[neighbor], neighbor]);
}
}
}
if(neighbors.length > 0) {
return neighbors[Math.floor(Math.random() * neighbors.length)];
} else {
return [undefined, undefined];
}
}
function delay(ms) {
return new Promise(resolve => {
console.log("waiting...");
setTimeout(resolve, ms)
});
}
async function recursiveDFS(currentCell) {
await delay(1000);
highlightCell(currentCell);
currentCell.visited = true;
var [next, direction] = getNextNeighbor(currentCell);
while(typeof(next) != 'undefined') {
removeWall(currentCell, next, direction);
highlightCell(next);
recursiveDFS(next);
[next, direction] = getNextNeighbor(currentCell);
}
}
function highlightCell(cell) {
context.globalCompositeOperation='destination-over'; // fill rect under existing grid
const topLeft = [(cell.col) * cellSize, (cell.row) * cellSize];
context.fillStyle = '#FF0000';
context.fillRect(topLeft[0], topLeft[1], cellSize, cellSize);
}
function removeWall(cell1, cell2, direction) {
switch (direction) {
case 'top':
cell1.walls.top = false;
cell2.walls.bottom = false;
break;
case 'right':
cell1.walls.right = false;
cell2.walls.left = false;
break;
case 'bottom':
cell1.walls.bottom = false;
cell2.walls.top = false;
break;
case 'left':
cell1.walls.left = false;
cell2.walls.right = false;
break;
}
redrawGrid();
}
function redrawGrid() {
context.clearRect(0, 0, numCols * cellSize, numRows * cellSize); // clear canvas
for (var col = 0; col < numCols; col++) {
for (var row = 0; row < numRows; row++) {
drawGridLines(grid[col][row]);
}
}
}
function drawGridLines(cell) {
const topLeft = [ cell.col * cellSize, cell.row * cellSize];
const topRight = [(cell.col + 1) * cellSize, cell.row * cellSize];
const bottomLeft = [ cell.col * cellSize, (cell.row + 1) * cellSize];
const bottomRight = [(cell.col + 1) * cellSize, (cell.row + 1) * cellSize];
context.lineWidth = 2;
//draw top line
if(cell.walls.top){
context.beginPath();
context.moveTo(topLeft[0], topLeft[1]);
context.lineTo(topRight[0], topRight[1]);
context.stroke();
}
//draw right line
if(cell.walls.right) {
context.beginPath();
context.moveTo(topRight[0], topRight[1]);
context.lineTo(bottomRight[0], bottomRight[1]);
context.stroke();
}
//draw bottom line
if(cell.walls.bottom) {
context.beginPath();
context.moveTo(bottomRight[0], bottomRight[1]);
context.lineTo(bottomLeft[0], bottomLeft[1]);
context.stroke();
}
//draw left line
if(cell.walls.left) {
context.beginPath();
context.moveTo(bottomLeft[0], bottomLeft[1]);
context.lineTo(topLeft[0], topLeft[1]);
context.stroke();
}
}
setup();
async function recursiveDFS(currentCell) {
await delay(1000);
highlightCell(currentCell);
currentCell.visited = true;
var [next, direction] = getNextNeighbor(currentCell);
while(typeof(next) != 'undefined') {
removeWall(currentCell, next, direction);
highlightCell(next);
await recursiveDFS(next);
[next, direction] = getNextNeighbor(currentCell);
}
}
Add await when u call recursiveDFS(next); so that it will wait for the function to be done before going to the next step as you have set the function as async.

function .push keep replacing all elements same as last one in array

I'm trying to make trails of moving objects by using vector history array in p5js.
but after push updated vector, all elements in this.history replaced as last one.
I've searched some question here but still can't understand.
let ppp = [];
function setup() {
createCanvas(400, 400);
for (let i = 0; i < 3; i++) {
let p = new Particle();
ppp.push(p);
}
}
function draw() {
background(220);
for (let i = 0; i < ppp.length; i++) {
ppp[i].display();
ppp[i].update();
}
}
function Particle() {
this.pv = createVector(random(width), random(height));
this.history = [];
let rndV = p5.Vector.random2D();
this.spdV = rndV.mult(random(1, 3));
this.update = function() {
this.pv.add(this.spdV);
this.history.push(this.pv); // replace all vector element
console.log(this.history);
}
this.display = function() {
fill(30);
ellipse(this.pv.x, this.pv.y, 30);
for (let i = 0; i < this.history.length; i++) {
let trail = this.history[i];
ellipse(trail.x, trail.y, 10);
}
}
}
or if you think my approach isn't the best, I'll be happy to hear any suggestion^^
Thanks,
This can be a bit misleading in javascript:
this.history.push(this.pv);
You're pushing a reference to the same this.pv pre-allocated vector
What you are trying to do is something like:
this.history.push(this.pv.copy());
Where you are allocating memory for a completely new p5.Vector object with the x,y coordinates copied from this.pv (using the copy() method)
Demo:
let ppp = [];
function setup() {
createCanvas(400, 400);
for (let i = 0; i < 3; i++) {
let p = new Particle();
ppp.push(p);
}
}
function draw() {
background(220);
for (let i = 0; i < ppp.length; i++) {
ppp[i].display();
ppp[i].update();
}
}
function Particle() {
this.pv = createVector(random(width), random(height));
this.history = [];
let rndV = p5.Vector.random2D();
this.spdV = rndV.mult(random(1, 3));
this.update = function() {
this.pv.add(this.spdV);
this.history.push(this.pv.copy()); // replace all vector element
//console.log(this.history);
}
this.display = function() {
fill(30);
ellipse(this.pv.x, this.pv.y, 30);
for (let i = 0; i < this.history.length; i++) {
let trail = this.history[i];
ellipse(trail.x, trail.y, 10);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
Bare in mind as the sketch runs this will use more and more memory.
If simply need to render the trails and don't need the vector data for anything else you can simply render into a separate graphics layer (using createGraphics()) immediately which will save memory on the long run:
let ppp = [];
let trailsLayer;
function setup() {
createCanvas(400, 400);
// make a new graphics layer for trails
trailsLayer = createGraphics(400, 400);
trailsLayer.noStroke();
trailsLayer.fill(0);
for (let i = 0; i < 3; i++) {
let p = new Particle();
ppp.push(p);
}
}
function draw() {
background(220);
// render the trails layer
image(trailsLayer, 0, 0);
for (let i = 0; i < ppp.length; i++) {
ppp[i].display();
ppp[i].update();
}
}
function Particle() {
this.pv = createVector(random(width), random(height));
let rndV = p5.Vector.random2D();
this.spdV = rndV.mult(random(1, 3));
this.update = function() {
this.pv.add(this.spdV);
// render trails
trailsLayer.ellipse(this.pv.x, this.pv.y, 10);
}
this.display = function() {
fill(30);
ellipse(this.pv.x, this.pv.y, 30);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
Update to fade trails you could try something like Moving On Curves example. Notice noStroke(); is called in setup() and
fill(0, 2);
rect(0, 0, width, height);
render a faded out (alpha=2) rectangle ?
You could do something similar:
let ppp = [];
let trailsLayer;
function setup() {
createCanvas(400, 400);
background(255);
// make a new graphics layer for trails
trailsLayer = createGraphics(400, 400);
trailsLayer.noStroke();
// set translucent fill for fade effect
trailsLayer.fill(255, 25);
for (let i = 0; i < 3; i++) {
let p = new Particle();
ppp.push(p);
}
}
function draw() {
background(220);
// fade out trail layer by rendering a faded rectangle each frame
trailsLayer.rect(0, 0, width, height);
// render the trails layer
image(trailsLayer, 0, 0);
for (let i = 0; i < ppp.length; i++) {
ppp[i].display();
ppp[i].update();
}
}
function Particle() {
this.pv = createVector(random(width), random(height));
let rndV = p5.Vector.random2D();
this.spdV = rndV.mult(random(1, 3));
this.update = function() {
this.pv.add(this.spdV);
// reset at bounds
if(this.pv.x > width){
this.pv.x = 0;
}
if(this.pv.y > height){
this.pv.y = 0;
}
if(this.pv.x < 0){
this.pv.x = width;
}
if(this.pv.y < 0){
this.pv.y = height;
}
// render trails
trailsLayer.push();
trailsLayer.fill(0);
trailsLayer.noStroke();
trailsLayer.ellipse(this.pv.x, this.pv.y, 10);
trailsLayer.pop();
}
this.display = function() {
fill(30);
ellipse(this.pv.x, this.pv.y, 30);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
For the sake of completeness here's a version using the history vector array, but limiting that to a set size and reusing vectors allocated once (instead making new ones continuously):
let ppp = [];
function setup() {
createCanvas(400, 400);
noStroke();
for (let i = 0; i < 3; i++) {
let p = new Particle();
ppp.push(p);
}
}
function draw() {
background(220);
for (let i = 0; i < ppp.length; i++) {
ppp[i].display();
ppp[i].update();
}
}
function Particle() {
this.pv = createVector(random(width), random(height));
// limit number of history vectors
this.historySize = 24;
this.history = new Array(this.historySize);
// pre-allocate all vectors
for(let i = 0 ; i < this.historySize; i++){
this.history[i] = this.pv.copy();
}
let rndV = p5.Vector.random2D();
this.spdV = rndV.mult(random(1, 6));
this.update = function() {
this.pv.add(this.spdV);
this.resetBounds();
this.updateHistory();
};
this.updateHistory = function(){
// shift values back to front by 1 (loop from last to 2nd index)
for(let i = this.historySize -1; i > 0; i--){
// copy previous to current values (re-using existing vectors)
this.history[i].set(this.history[i-1].x, this.history[i-1].y);
}
// finally, update the first element
this.history[0].set(this.pv.x, this.pv.y);
};
this.resetBounds = function(){
// reset at bounds
if(this.pv.x > width){
this.pv.x = 0;
}
if(this.pv.y > height){
this.pv.y = 0;
}
if(this.pv.x < 0){
this.pv.x = width;
}
if(this.pv.y < 0){
this.pv.y = height;
}
};
this.display = function() {
fill(30);
ellipse(this.pv.x, this.pv.y, 30);
for (let i = 0; i < this.historySize; i++) {
let trail = this.history[i];
// fade trails
let alpha = map(i, 0, this.historySize -1, 192, 0);
fill(30, alpha);
ellipse(trail.x, trail.y, 10);
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>

I Want To add a image instead of triangle in my code in p5.js

i tried doing 'loadImage()' using preload() but it stuck in loading only
it did not help me because
i just copied code from a source
now it is working but if i add image using loadImage() it doesn't work
i am new to it please help me
html code
<!DOCTYPE html>
<html>
<head >
<meta charset="UTF-8">
<title> Kill Corona Virus </title>
<script src="libraries/p5.js" type="text/javascript"></script>
<script src="libraries/p5.dom.js" type="text/javascript"></script>
<script src="libraries/p5.sound.js" type="text/javascript"></script>
<script src="game.js" type="text/javascript"></script>
<script src="scoreboard.js" type="text/javascript"></script>
<script src="ship.js" type="text/javascript"></script>
<script src="bubble.js" type="text/javascript"></script>
<script src="sketch.js" type="text/javascript"></script>
<style>
body {
padding: 0;
margin: 0;
}
canvas {
vertical-align: top;
}
</style>
</head>
<body style="background-color:grey;">
</body>
</html>
bubble.js
function Bubble(x, y, size, speed, col, crazyness) {
// position
this.x = x;
this.y = y;
this.size = size;
this.speed = speed;
this.col = col;
// should we delete?
this.alive = true;
// crazy fx
this.crazyness = crazyness;
// schedule ball for destroyal
this.destroy = function() {
this.alive = false;
}
this.setSpeed = function(newSpeed) {
this.speed = newSpeed;
}
this.display = function() {
strokeWeight(1);
stroke(0);
fill(this.col);
ellipse(this.x, this.y, this.size, this.size);
};
// move the ball down (towards the ground)
this.move = function() {
this.y += this.speed;
this.size += random(-this.crazyness, this.crazyness);
};
// detects intersection with another Bubble()
this.intersects = function(other) {
d = dist(this.x, this.y, other.x, other.y);
r1 = this.size / 2;
r2 = other.size / 2;
if (d < r1 + r2)
return true
else
return false
}
}
game.js
function Game(ship, scoreboard) {
this.debug = false;
this.ship = ship;
this.scoreBoard = scoreboard;
var canvas = document.querySelector("canvas")
this.reset = function() {
this.gameActive = false;
this.scoreBoard.reset();
this.meteors = [];
this.projectiles = [];
this.meteorsDensity = 0.985;
this.meteorsDensityInc = 0.0001;
this.meteorsMinSpeed = 0.25;
this.meteorsMinSpeedInc = 0.0001;
this.meteorsMaxSpeed = 2;
this.meteorsMaxSpeedInc = 0.0001;
this.meteorsMinSize = 25;
this.meteorsMaxSize = 125;
}
this.isActive = function() {
return this.gameActive;
}
this.start = function() {
this.gameActive = true;
}
this.showWelcomeScreen = function() {
background(255);
textFont("Courier New");
fill(0);
noStroke();
textAlign(CENTER);
welcome_msg = "Kill Corona-virus";
textSize(random(65, 68));
text(welcome_msg, width / 2, height / 2);
action_msg = "Click to start, click to play.";
textSize(25);
text(action_msg, width / 2, height / 4);
score_msg = "Your previous score was " + scoreBoard.score + ".";
textSize(25);
text(score_msg, width / 2, height / 4 * 3);
credits_msg = "(c) 2020 - Haseef Azhaan";
textSize(15);
text(credits_msg, width / 2, height / 4 * 3.75);
}
this.createNewMeteor = function() {
if (random() > this.meteorsDensity) {
// pick random color, speed, size and horizontal position
col = color(random(255), random(255), random(255), 50);
speed = random(this.meteorsMinSpeed, this.meteorsMaxSpeed);
size = random(this.meteorsMinSize, this.meteorsMaxSize);
x = random(0 + size / 2, width - size / 2);
// vertical position is fixed
y = -size / 2;
// crzyness is just a visual FX
crazyness = random(0.5, 1.5);
//create a new "meteor" (a Bubble)
this.meteors.push(new Bubble(x, y, size, speed, col, crazyness));
}
};
this.updateAndDisplayMeteors = function() {
for (var i = this.meteors.length - 1; i >= 0; i--) {
this.meteors[i].move();
this.meteors[i].display();
}
};
this.updateAndDisplayProjectiles = function() {
for (var i = this.projectiles.length - 1; i >= 0; i--) {
this.projectiles[i].move();
this.projectiles[i].display();
}
};
this.updateAndDisplayShip = function() {
this.ship.updatePosition();
this.ship.display();
};
this.displayScoreboard = function() {
this.scoreBoard.display();
};
canvas.addEventListener("keyup",(e)=>{
if(e.key==='Enter'){alert("p")}
})
this.shoot = function() {
this.projectiles.push(this.ship.shoot());
}
this.stopIfMeteorHitGround = function() {
// iterate through all the meteors
for (var i = this.meteors.length - 1; i >= 0; i--) {
// when a meteor hits the ground, it's game over
if (this.meteors[i].y > height) {
this.gameActive = false;
}
}
};
this.removeLostProjectiles = function() {
// iterate through all the projectiles
for (var i = this.projectiles.length - 1; i >= 0; i--) {
// if a projectile passes the screen top, it's lost (can delete it)
if (this.projectiles[i].y < 0)
this.projectiles.splice(i, 1);
}
};
this.detectSuccessfullShots = function() {
// iterate through all the meteors
for (var i = this.meteors.length - 1; i >= 0; i--) {
// for each meteor, now consider all projectiles
for (var j = this.projectiles.length - 1; j >= 0; j--) {
// is there a hit?
if (this.meteors[i].intersects(this.projectiles[j])) {
// destroy both projectile and meteor
this.meteors[i].destroy();
this.projectiles[j].destroy();
// increment score!
this.scoreBoard.incrementScore();
// increment game difficulty! :)
this.meteorsMinSpeed += this.meteorsMinSpeedInc;
this.meteorsMaxSpeed += this.meteorsMaxSpeedInc;
this.meteorsDensity -= this.meteorsDensityInc;
}
}
}
};
this.removeKilledMeteors = function() {
// remove meteors scheduled for removal
for (var i = this.meteors.length - 1; i >= 0; i--) {
if (!this.meteors[i].alive)
this.meteors.splice(i, 1);
}
};
this.removeUsedProjectiles = function() {
for (var i = this.projectiles.length - 1; i >= 0; i--) {
if (!this.projectiles[i].alive)
this.projectiles.splice(i, 1);
}
};
this.setDebug = function(v) {
this.debug = v;
}
this.showDebugInfo = function() {
if (this.debug == true) {
print("# meteors: " + this.meteors.length);
print("# projectiles: " + this.projectiles.length);
}
}
}
scoreboard.js
function ScoreBoard(x,y) {
// position
this.x = x;
this.y = y;
// initial score
this.score = 0;
this.display = function() {
noStroke();
fill(0);
textAlign(RIGHT);
textFont("Courier new");
textSize(22);
text("score: " + this.score,this.x,this.y);
};
this.incrementScore = function() {
this.score++;
};
this.reset = function() {
this.score = 0;
}
}
ship.js
,
in the place of this triangle i want a image
function Ship(x,y) {
// ship position
this.x = x;
this.y = y;
// width and height
this.width = 25;
this.height = 50;
this.display = function() {
fill(color(255,0,0,50));
stroke(0);
strokeWeight(1);
triangle(this.x - this.width, this.y,this.x, this.y - this.height,this.x + this.width, this.y);
};
// update position based on mouseX
this.updatePosition = function() {
this.x = mouseX;
this.y = height - 10;
};
// shoot a projectile
this.shoot = function(){
projectile = new Bubble(this.x, this.y - 50, 10,-10,0,0);
return projectile;
}
}
sketch.js
var game;
var ship_im;
function setup() {
var a = createCanvas(windowWidth, windowHeight);
ship = new Ship(width / 2, height / 2);
var b = createCanvas(windowWidth, windowHeight);
ship_im = loadImage("ship.png")
scoreBoard = new ScoreBoard(width - 10, 20);
game = new Game(ship, scoreBoard);
game.reset();
game.setDebug(true);
}
function draw() {
if (game.isActive()) {
background(255);
// create new meteors
game.createNewMeteor();
// update position of and display stuff (meteors, projectiles, ship)
game.updateAndDisplayMeteors();
game.updateAndDisplayProjectiles();
game.updateAndDisplayShip();
// display the scoreboard
game.displayScoreboard();
// remove projectiles that passed the top of screen
game.removeLostProjectiles();
// detect successfull shots (projectile hits meteor)
// after a successfull shoot, projectile and meteor will be marked as "dead"
game.detectSuccessfullShots();
// remove "dead" meteors and projectiles
game.removeKilledMeteors();
game.removeUsedProjectiles();
// if a meteor hits the ground, it's game over.
game.stopIfMeteorHitGround();
// show debug info when enables
//game.showDebugInfo();
} else {
game.showWelcomeScreen();
}
}
function mouseClicked() {
// when the game is active, clicking the mouse shots
if (game.gameActive)
game.shoot();
// when the game is inactive, clicking the mouse restarts the game
else {
game.reset();
game.start();
}
}
function keyPressed(){
if(keyCode===ENTER){
if (game.gameActive)
game.shoot();
// when the game is inactive, clicking the mouse restarts the game
else {
game.reset();
game.start();
}
}
}
please ignore bad indentation

Why is my unfinished javascript game crashing after the 3rd death?

// Commented because does not work in Sandbox
// window.localStorage; //Ignore this line
// Where all my variables have been assigned
var c = document.getElementById("GameScreen");
var ctx = c.getContext("2d");
var charY = 220;
const gravity = 10;
var score = 0;
var time = 0;
var speed = 5;
var cloneID = 0;
var clonePos = [600];
var clonePoints = [0];
var animationBounce = 0;
var jump = 10;
var charDead = 0;
var dataCharY = [];
var dataDisObst = [];
var disObst = 1000;
var lowestLoopDis;
var jumpFactor = 0;
var disDeath;
var AIgames = 1;
var bestScoreAI = 0;
ctx.translate(c.width / 2, c.height / 2);
// Was going to use this for background trees but haven't done it yet
new obj(50, 50, 30, 30);
// Runs most functions
function runAll() {
if (charDead == 0) {
clearAll(); //This function runs most of the code
updateChar();
createGround();
updateObj();
groundDetect();
updateScore();
hitDetect();
addData();
testBetterAI();
getDisObst();
jumpAI();
removeUnusedObst();
}
}
// Was going to use this for trees but haven't yet
function obj(x, y, width, height) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
ctx.beginPath();
ctx = c.getContext("2d");
ctx.fillStyle = "brown";
ctx.fillRect(this.x, this.y, this.width, this.height);
ctx.fillStyle = "green";
ctx.arc(-293, 150, 50, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
this.cloneID = cloneID;
}
new obj(-293, 212, 0, 2 * Math.PI);
// Creates the floor (IKR)
function createGround() {
ctx.fillStyle = "green";
ctx.fillRect(-635, 250, c.width, 50);
}
// Creates the character every milisecond (or 10, I can't remember)
function updateChar() {
ctx.fillStyle = "blue";
ctx.fillRect(-300, charY - animationBounce, 15, 30);
ctx.fillStyle = "pink";
ctx.beginPath();
ctx.arc(-293, charY - animationBounce - 15, 15, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
// Removes everything in order to be redrawn in new position
function clearAll() {
ctx.clearRect(-700, -700, 2000, 2000);
}
// Redraws every square / object
function updateObj() {
for (var i = 0; i != clonePos.length; i++) {
ctx.fillStyle = "green";
ctx.fillRect(clonePos[i], 220, 30, 30);
}
}
// Creates new square (I also decided to rename them half way through with obstacle instead of object)
function createObst() {
clonePos.push(600);
cloneID++;
}
// Changes the squares / obstacles position relative to the movement
function moveObst() {
for (var ii = 0; ii != clonePos.length; ii++) {
clonePos[ii] -= speed;
}
}
// Tests to see if the character is on the ground
function groundDetect() {
if (charY > 220) {
charY = 220;
}
}
// Makes gravity actually work
function charGravity() {
if (charY < 220) {
charY += gravity;
}
}
// Updates the score counter text
function updateScore() {
document.getElementById("scoreText").innerHTML = score;
}
// Gives the character a little bounce when moving
function charBounce() {
setTimeout(function() {
animationBounce++;
}, 100);
setTimeout(function() {
animationBounce++;
}, 200);
setTimeout(function() {
animationBounce++;
}, 300);
setTimeout(function() {
animationBounce--;
}, 400);
setTimeout(function() {
animationBounce--;
}, 500);
setTimeout(function() {
animationBounce--;
}, 600);
}
// Makes the character jump
function charJump() {
if (charY == 220) {
jump = 4;
setTimeout(function() {
charY -= jump;
}, 20);
jump = 8;
setTimeout(function() {
charY -= jump;
}, 40);
jump = 12;
setTimeout(function() {
charY -= jump;
}, 60);
jump = 16;
setTimeout(function() {
charY -= jump;
}, 80);
setTimeout(function() {
charY -= jump;
}, 100);
setTimeout(function() {
charY -= jump;
}, 120);
}
}
// Detects when the character has a hit a square
function hitDetect() {
for (var iB = 0; iB != clonePos.length; iB++) {
if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
charDied();
}
}
}
// Runs when character dies
function charDied() {
disDeath = disObst;
charDead = 1;
charRevive();
testBetterAI();
decideAdjustments();
}
// Adds score very interval
function addingScore() {
if (charDead == 0) {
score += 100;
}
}
// Adds to an array that I will use later
function addData() {
dataCharY.push(charY);
dataDisObst.push(disObst);
}
// Test to see if one of my AI's (which hasn't been made yet) scores is better than the previous best
function testBetterAI() {
// Commented because does not work in Sandbox
// if (score > localStorage.getItem("bestScore")) {
// }
}
// Calculates the distance to the nearest square / obstacle
function getDisObst() {
lowestLoopDis = 1000;
for (var iiA = 0; iiA != clonePos.length; iiA++) {
if (clonePos[iiA] > -320) {
if (clonePos[iiA] > 0) {
if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
lowestLoopDis = Math.abs(clonePos[iiA]);
}
} else {
if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
lowestLoopDis = Math.abs(clonePos[iiA]);
}
}
}
}
if (lowestLoopDis < disObst) {
disObst = lowestLoopDis;
}
}
// Increments the speed of the obstacles / squares and the character
function addSpeed() {
if (speed < 25) {
speed++;
}
}
// Restarts the game
function charRevive() {
clonePos = [600];
charDead = 0;
score = 0;
time = 0;
speed = 5;
AIgames++;
}
// I accidently did this twice, whoops
function testBetterAI() {
if (score > bestScoreAI) {
bestScoreAI = score;
}
}
// Makes the unfinished AI jump when it wants to
function jumpAI() {
if (disObst <= disDeath + jumpFactor) {
charJump();
}
}
// What changes need to be made in order to improve the AI
function decideAdjustments() {
jumpFactor += Math.floor(Math.random() * 10) - 5;
if (jumpFactor < 0) {
jumpFactor = 0;
}
}
// Removing blocks that are off the screen
function removeUnusedObst() {
if (clonePos[0] < -650) {
clonePos.shift();
}
}
// Intervals here
setInterval(function() {
time++;
}, 1000);
setInterval(function() {
runAll();
}, 10);
setInterval(function() {
moveObst();
}, 50);
setInterval(function() {
charGravity();
}, 25);
setInterval(function() {
createObst();
}, 3000);
setInterval(function() {
charBounce();
}, 650);
setInterval(function() {
addingScore();
}, 3500);
setInterval(function() {
addSpeed();
}, 25000);
#GameScreen {
background-color: CornflowerBlue;
}
#scoreText {
text-align: center;
font-size: 35px;
}
<div id="scoreText"></div>
<canvas id="GameScreen" width="1270px" height="550px"></canvas>
What happens
In your hitDetect function:
function hitDetect() {
for (var iB = 0; iB != clonePos.length; iB++) {
if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
charDied();
}
}
}
You loop over the clonePos array, until iB is equal to the length of that array. If a condition is met (collision), you execute charDied, which, in turn, executes charRevive:
function charRevive() {
clonePos = [600];
// ...
}
Meanwhile, the hitDetect loop continues. And at one point (seemingly when you start to increase the speed), it happens that iB is now above 1, which is the new length of clonePos. Now, what happens? Well, you are trapped in an infinite loop:
Lesson to be learned
If you're looping on an Array which can mutate during the loop (and change its length), never use this type of condition:
i != myArr.length
Always prefer a stricter condition if you want your loop to end at some point:
i < myArr.length
And, even better, if looping makes no sense after a condition is met, end this loop by returning. eg:
function hitDetect() {
for (var iB = 0; iB < clonePos.length; iB++) {
if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
return charDied();
// Alternatively, if there is other stuff to do after the loop, you can use:
// break;
}
}
}
Fixed code
// Commented because does not work in Sandbox
// window.localStorage; //Ignore this line
// Where all my variables have been assigned
var c = document.getElementById("GameScreen");
var ctx = c.getContext("2d");
var charY = 220;
const gravity = 10;
var score = 0;
var time = 0;
var speed = 5;
var cloneID = 0;
var clonePos = [600];
var clonePoints = [0];
var animationBounce = 0;
var jump = 10;
var charDead = 0;
var dataCharY = [];
var dataDisObst = [];
var disObst = 1000;
var lowestLoopDis;
var jumpFactor = 0;
var disDeath;
var AIgames = 1;
var bestScoreAI = 0;
ctx.translate(c.width / 2, c.height / 2);
// Was going to use this for background trees but haven't done it yet
new obj(50, 50, 30, 30);
// Runs most functions
function runAll() {
if (charDead == 0) {
clearAll(); //This function runs most of the code
updateChar();
createGround();
updateObj();
groundDetect();
updateScore();
hitDetect();
addData();
testBetterAI();
getDisObst();
jumpAI();
removeUnusedObst();
}
}
// Was going to use this for trees but haven't yet
function obj(x, y, width, height) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
ctx.beginPath();
ctx = c.getContext("2d");
ctx.fillStyle = "brown";
ctx.fillRect(this.x, this.y, this.width, this.height);
ctx.fillStyle = "green";
ctx.arc(-293, 150, 50, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
this.cloneID = cloneID;
}
new obj(-293, 212, 0, 2 * Math.PI);
// Creates the floor (IKR)
function createGround() {
ctx.fillStyle = "green";
ctx.fillRect(-635, 250, c.width, 50);
}
// Creates the character every milisecond (or 10, I can't remember)
function updateChar() {
ctx.fillStyle = "blue";
ctx.fillRect(-300, charY - animationBounce, 15, 30);
ctx.fillStyle = "pink";
ctx.beginPath();
ctx.arc(-293, charY - animationBounce - 15, 15, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
}
// Removes everything in order to be redrawn in new position
function clearAll() {
ctx.clearRect(-700, -700, 2000, 2000);
}
// Redraws every square / object
function updateObj() {
for (var i = 0; i < clonePos.length; i++) {
ctx.fillStyle = "green";
ctx.fillRect(clonePos[i], 220, 30, 30);
}
}
// Creates new square (I also decided to rename them half way through with obstacle instead of object)
function createObst() {
clonePos.push(600);
cloneID++;
}
// Changes the squares / obstacles position relative to the movement
function moveObst() {
for (var ii = 0; ii < clonePos.length; ii++) {
clonePos[ii] -= speed;
}
}
// Tests to see if the character is on the ground
function groundDetect() {
if (charY > 220) {
charY = 220;
}
}
// Makes gravity actually work
function charGravity() {
if (charY < 220) {
charY += gravity;
}
}
// Updates the score counter text
function updateScore() {
document.getElementById("scoreText").innerHTML = score;
}
// Gives the character a little bounce when moving
function charBounce() {
setTimeout(function() {
animationBounce++;
}, 100);
setTimeout(function() {
animationBounce++;
}, 200);
setTimeout(function() {
animationBounce++;
}, 300);
setTimeout(function() {
animationBounce--;
}, 400);
setTimeout(function() {
animationBounce--;
}, 500);
setTimeout(function() {
animationBounce--;
}, 600);
}
// Makes the character jump
function charJump() {
if (charY == 220) {
jump = 4;
setTimeout(function() {
charY -= jump;
}, 20);
jump = 8;
setTimeout(function() {
charY -= jump;
}, 40);
jump = 12;
setTimeout(function() {
charY -= jump;
}, 60);
jump = 16;
setTimeout(function() {
charY -= jump;
}, 80);
setTimeout(function() {
charY -= jump;
}, 100);
setTimeout(function() {
charY -= jump;
}, 120);
}
}
// Detects when the character has a hit a square
function hitDetect() {
for (var iB = 0; iB < clonePos.length; iB++) {
if (clonePos[iB] > -320 && clonePos[iB] < -280 && charY > 200) {
return charDied();
}
}
}
// Runs when character dies
function charDied() {
disDeath = disObst;
charDead = 1;
charRevive();
testBetterAI();
decideAdjustments();
}
// Adds score very interval
function addingScore() {
if (charDead == 0) {
score += 100;
}
}
// Adds to an array that I will use later
function addData() {
dataCharY.push(charY);
dataDisObst.push(disObst);
}
// Test to see if one of my AI's (which hasn't been made yet) scores is better than the previous best
function testBetterAI() {
// Commented because does not work in Sandbox
// if (score > localStorage.getItem("bestScore")) {
// }
}
// Calculates the distance to the nearest square / obstacle
function getDisObst() {
lowestLoopDis = 1000;
for (var iiA = 0; iiA < clonePos.length; iiA++) {
if (clonePos[iiA] > -320) {
if (clonePos[iiA] > 0) {
if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
lowestLoopDis = Math.abs(clonePos[iiA]);
}
} else {
if (Math.abs(clonePos[iiA]) < lowestLoopDis) {
lowestLoopDis = Math.abs(clonePos[iiA]);
}
}
}
}
if (lowestLoopDis < disObst) {
disObst = lowestLoopDis;
}
}
// Increments the speed of the obstacles / squares and the character
function addSpeed() {
if (speed < 25) {
speed++;
}
}
// Restarts the game
function charRevive() {
clonePos = [600];
charDead = 0;
score = 0;
time = 0;
speed = 5;
AIgames++;
}
// I accidently did this twice, whoops
function testBetterAI() {
if (score > bestScoreAI) {
bestScoreAI = score;
}
}
// Makes the unfinished AI jump when it wants to
function jumpAI() {
if (disObst <= disDeath + jumpFactor) {
charJump();
}
}
// What changes need to be made in order to improve the AI
function decideAdjustments() {
jumpFactor += Math.floor(Math.random() * 10) - 5;
if (jumpFactor < 0) {
jumpFactor = 0;
}
}
// Removing blocks that are off the screen
function removeUnusedObst() {
if (clonePos[0] < -650) {
clonePos.shift();
}
}
// Intervals here
setInterval(function() {
time++;
}, 1000);
setInterval(function() {
runAll();
}, 10);
setInterval(function() {
moveObst();
}, 50);
setInterval(function() {
charGravity();
}, 25);
setInterval(function() {
createObst();
}, 3000);
setInterval(function() {
charBounce();
}, 650);
setInterval(function() {
addingScore();
}, 3500);
setInterval(function() {
addSpeed();
}, 25000);
body { text-align: center; }
#GameScreen {
background-color: CornflowerBlue;
width: 350px; height: 150px;
}
<div id="scoreText"></div>
<canvas id="GameScreen" width="1270px" height="550px"></canvas>

Objects in P5 do not collide when using collide() function

I'm working on getting all the components for my final together using the P5.play engine and while I have made some progress with setting up aspects of my mini game I'm having a hard time with the collision. It should be easy but for whatever reason when I set up my two objects (the fish and the garbage) they do not collide. I am trying to set it up so that when the garbage collides with the fish the fish either get removed or are reset to a place where they can continue to move on the screen while tallying the score. I managed to get the player sprite to collect the garbage and add to the score using overlapPoint and placing the condition in the update for the garbage object. But when I attempt the same technique for the fish on the garbage object an error occurs and everything disappears on the screen. I commented out the portion that is I have tried multiple ways including the collide() function on the objects with the proper conditionals but nothing seems to work. A bit frustrating. I have tried various other ways. So I'm asking for expert advice. Any assistance is appreciated. this is the code that i have thus far:
var bg;
var player;
var player_stand_sprites;
var player_stand;
var fish_swim_sprites;
var fish_swim;
var fish = [];
var garbage_drop_sprites;
var garbage_drop;
var garbage = [];
var score = 0;
function preload() {
bg = loadImage("final-bg.png");
player_stand_sprites = loadSpriteSheet("player2.png", 100, 100, 1);
player_stand = loadAnimation(player_stand_sprites);
fish_swim_sprites = loadSpriteSheet("fish.png", 75, 75, 1);
fish_swim = loadAnimation(fish_swim_sprites);
garbage_drop_sprites = loadSpriteSheet("metal.png", 41, 75, 1);
garbage_drop = loadAnimation(garbage_drop_sprites);
}
function setup() {
createCanvas(720, 360);
player = createSprite(100, 0);
player.addAnimation("stand", player_stand);
player.setCollider("circle", 0, 0, 32, 32);
player.depth = 10;
//player.debug = true;
//to make fish
for (var i = 0; i < 10; i++){
fish.push( new Fish(random(0,width), random(height/2, height)) );
for (var i = 0; i < fish.length; i++) {
fish[i].init();
}
}
//to make garbage
for (var a = 0; a < 5; a++){
garbage.push( new Garbage(random(0,width), random(width/2, width)));
}
}
function draw() {
background(bg);
player.position.x = mouseX;
player.position.y = mouseY;
for (var i = 0; i < fish.length; i++) {
fish[i].update();
}
for (var a = 0; a < garbage.length; a++) {
garbage[a].update();
}
/**for (var b = 0; b < fish.length; b++) {
if(fish[b].collide(garbage[b])){
fish[b].remove;
}
}**/
text(score,100,100);
drawSprites();
}
function Garbage(x,y){
this.sprite = createSprite(x, y);
this.sprite.addAnimation("drop", garbage_drop);
this.sprite.setCollider("circle",0,0,32,32);
this.speed = random(1,2);
this.sprite.debug = true;
this.update = function() {
this.sprite.position.y += this.speed;
if(this.sprite.position.y > height){
this.sprite.position.y = 0;
}
if(this.sprite.overlapPoint(player.position.x, player.position.y)){
this.sprite.position.x = random(0,width);
this.sprite.position.y = -75;
score++;
}
}
}
function Fish(x,y) {
this.sprite = createSprite(x, y);
this.sprite.addAnimation("swim", fish_swim);
this.sprite.setCollider("rectangle",0,0,75,32);
this.speed = 0;
this.sprite.debug = true;
this.init = function() {
if (this.sprite.position.x < width/2) {
this.sprite.mirrorX(-1);
this.speed = random(1, 2);
} else {
this.speed = -random(1,2);
}
}
this.update = function() {
this.sprite.position.x += this.speed;
if(this.sprite.position.x > width){
this.sprite.position.x = 0;
}else if(this.sprite.position.x < -width){
this.sprite.position.x = width;
}
}
}
I actually found the answer to my question a while back but am going to post it here.
The initial problem was that the sprites would not collide but with a simple for loop nested within another for loop and adding a .sprite to each of the objects being checked, I was able to get all the elements to collide properly.
Here is the code I revised to make it work seamlessly using the P5.play.js library:
var bg;
var img;
var dead = false;
var deadFish = 0;
var player;
var player_stand_sprites;
var player_stand;
var fish_swim_sprites;
var fish_swim;
var fish = [];
var garbage_drop_sprites;
var garbage_drop;
var garbage = [];
var score = 0;
//////////////////////////////////////////
function preload() {
bg = loadImage("final-bg.png");
img = loadImage("fish.png");
player_stand_sprites = loadSpriteSheet("player2.png", 100, 100, 1);
player_stand = loadAnimation(player_stand_sprites);
fish_swim_sprites = loadSpriteSheet("fish.png", 75, 75, 1);
fish_swim = loadAnimation(fish_swim_sprites);
garbage_drop_sprites = loadSpriteSheet("metal.png", 41, 75, 1);
garbage_drop = loadAnimation(garbage_drop_sprites);
}
//////////////////////////////////////////
function setup() {
createCanvas(720, 360);
player = createSprite(100, 0);
player.addAnimation("stand", player_stand);
player.setCollider("circle", 0, 0, 32, 32);
player.depth = 10;
//player.debug = true;
//to make fish
for (var i = 0; i < 10; i++){
fish.push( new Fish(random(0,width), random(height/2, height)) );
for (var i = 0; i < fish.length; i++) {
fish[i].init();
}
}
//to make garbage
for (var a = 0; a < 5; a++){
garbage.push( new Garbage(random(0,width), random(width/2, width)));
}
}
function draw() {
scene_start();
}
//////////////////////////////////////////
function scene_start(){
push();
background("green");
fill("white");
textAlign(CENTER);
textSize(50);
textStyle(BOLD);
text("SPOT A FISH", width/2,height/3.5);
image(img, width/2.3, height/3);
textSize(15);
text("Rules: dont let the cans touch the fish. 5 fish die and you must start over", width/2, height/1.5);
textSize(30);
text("press up arrow key to start", width/2, height/1.2);
pop();
if (keyCode == UP_ARROW) {
scene_1();
}
}
function scene_1(){
background(bg);
score_card();
if(!dead){
player.position.x = mouseX;
player.position.y = mouseY;
for (var i = 0; i < fish.length; i++) {
fish[i].update();
}
for (var i = 0; i < garbage.length; i++) {
garbage[i].update();
}
for (var a = 0; a < garbage.length; a++) {
for (var b = 0; b < fish.length; b++) {
if(fish[b].sprite.collide(garbage[a].sprite)){
fish[b].sprite.position.x = random(-500, -100);
deadFish ++;
if(deadFish === 5){
dead = true;
}
}
}
}
drawSprites();
}else{
score_card();
textSize(30);
textStyle(BOLD);
textAlign(CENTER);
text("YOU DIED PLEASE TRY AGAIN",width/2,height/2);
text("press any button to start again",width/2,height/1.5);
if(keyIsPressed === true){
deadFish = 0;
dead = false;
}
}
}
function Garbage(x,y){
this.sprite = createSprite(x, y);
this.sprite.addAnimation("drop", garbage_drop);
this.sprite.setCollider("circle",0,0,32,32);
this.speed = random(1,2);
//this.sprite.debug = true;
this.update = function() {
this.sprite.position.y += this.speed;
if(this.sprite.position.y > height){
this.sprite.position.y = 0;
}
if(this.sprite.overlapPoint(player.position.x, player.position.y)){
this.sprite.position.x = random(0,width);
this.sprite.position.y = random(-200,-75);
score++;
}
if(score === 100){
this.speed = random(2,3);
score += 1000;
}else if(score === 1200){
this.speed = random(3,3.5);
score += 1000;
}
}
}
var score_card = function(){
fill("black");
rect(0,0,width,30);
textStyle(BOLD);
fill("white");
text("SCORE: "+score,10,20);
text("DEAD FISH: "+deadFish,width/1.2,20)
}
function Fish(x,y) {
this.sprite = createSprite(x, y);
this.sprite.addAnimation("swim", fish_swim);
this.sprite.setCollider("rectangle",0,0,75,32);
this.speed = 0;
this.sprite.debug = true;
this.init = function() {
if (this.sprite.position.x < width/2) {
this.sprite.mirrorX(-1);
this.speed = random(1, 2);
} else {
this.speed = -random(1,2);
}
}
this.update = function() {
this.sprite.position.x += this.speed;
if(this.sprite.position.x > width){
this.sprite.position.x = 0;
}else if(this.sprite.position.x < -width){
this.sprite.position.x = width;
}
}
}

Categories