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;
}
}
}
Related
For my space invader like game I want to make bullets that get shot by the enemies but the problem is that the bullets dont appear in this loop that I made. I tried several things like making only one bullet appear while that works it is not the result that I want. My idea behind the code is that a new bullet gets shot from the position of the enemies when the enemybullet.position == 1 and if it exceeds the height of the canvas I want the bullet to return to the enemies and be shot again.
The code that I used for this result is here:
sketch.js
var enemies = [];
var enemybullet = [];
function setup() {
createCanvas(800, 600);
for (var i = 0; i < 2; i++) {
enemies[i] = new Enemy(i*300+300, 100);
}
// I tried enemybullet = new Enemybullet(120, 200); and that drew the bullet but it wasnt assigned to the enemy
rectMode(CENTER);
}
function draw() {
background(0);
// enemybullet.show(); this is wat I used to draw the single projectile
// enemybullet.move();
var edge = false;
for (var i = 0; i < enemies.length; i++) {
enemies[i].show();
enemies[i].move();
if(enemies[i].x > width || enemies[i].x < 0) {
edge = true;
}
}
if (edge) {
for (var i = 0; i < enemies.length; i++) {
enemies[i].shiftDown();
}
}
for (var i = 0; i < enemybullet.length; i++) {
enemybullet[i].show();
enemybullet[i].move();
for (var j = 0; j < enemies.length; j++) {
if(enemybullet[i].position == 1){
var enemybullets = new Enemybullet(enemies[j].x(), enemies[j].y());
enemybullet.push(enemybullets);
enemybullet[i].x = enemybullet[i].x;
enemybullet[i].y = enemybullet[i].y + enemybullet[i].speed;
if(enemybullet[i].y >= height){
enemybullet[i].position = 2;
}
}
else{
enemybullet[i].y = enemies[i].y;
enemybullet[i].x = enemies[i].x;
}
if(enemybullet[i].position == 2 ){
enemybullet[i].y = enemies[i].y;
enemybullet[i].x = enemies[i].x;
enemybullet[i].position = 1;
}
}
}
enemybullet.js
function Enemybullet(x, y) {
this.x = x;
this.y = y;
this.width = 10;
this.height = 20;
this.position = 1;
this.speed = 2;
this.show = function() {
fill('#ADD8E6');
rect(this.x, this.y, this.width, this.height);
}
this.move = function() {
this.x = this.x;
this.y = this.y + this.speed;
}
}
enemy.js
function Enemy(x, y) {
this.x = x;
this.y = y;
this.r = 100;
this.xdir = 1;
this.shot = function() {
this.r = this.r * 0;
this.xdir = this.xdir * 0;
}
this.shiftDown = function() {
this.xdir *= -1;
this.y += this.r/2;
}
this.show = function() {
fill('#0000FF');
rect(this.x, this.y, this.r, this.r);
}
this.move = function() {
this.x = this.x + this.xdir;
}
}
Rather than having the bullets be in their own global array, try having the bullets be a variable in the Enemy class.
this.bullet = new Enemybullet(this.x, this.y);
Then you can give the enemies functions such as the following to update the bullets.
this.updateBullet = function() {
this.bullet.move();
this.bullet.show();
}
this.resetBullet = function() {
this.bullet = new Enemybullet(this.x, this.y);
}
Where you were looping through each bullet before, you can instead call enemies[i].updateBullet(); when you move and show the enemies.
And when you want the enemies to shoot another shot, call enemies[i].resetBullet();
You can see my implementation here.
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 have the following code for making a 2048 game with a onkeydown function to detect when user presses arrow keys. I thought the code is executed in sequential order but the onkeydown doesn't work if i put it at the end but only works if i put it first, even before canvas and tiles array declaration. How can i fix this so the order of execution makes more sense to me.
<script type="text/javascript">
var canvas = document.getElementById("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var ctx = canvas.getContext("2d");
var Tile = function(x, y) {
this.x = x;
this.y = y;
this.value = "";
}
Tile.prototype.draw = function() {
ctx.fillStyle = "green";
ctx.fillRect(this.x, this.y, 100, 100);
}
Tile.prototype.setX = function(x) {
this.x = x;
}
Tile.prototype.setY = function(y) {
this.y = y;
}
Tile.prototype.getY = function() {
return this.y;
}
Tile.prototype.getX = function() {
return this.x;
}
var tiles = [];
for(let i = 1; i <= 4; i++) {
for(let j = 1; j <= 4; j++) {
tiles.push(new Tile(j * 110, i * 110));
}
}
for(let i = 0; i <= tiles.length; i++) {
tiles[i].draw();
}
document.onkeydown = function(e) {
e.preventDefault();
ctx.fillStyle = "white";
ctx.fillRect(0, 0, canvas.width, canvas.height);
if (e.keyCode == '38') {
for(let i = 0; i < tiles.length; i++) {
tiles[i].setY(tiles[i].getY() - 50);
tiles[i].draw();
}
}
else if (e.keyCode == '40') {
for(let i = 0; i < tiles.length; i++) {
tiles[i].setY(tiles[i].getY() + 50);
tiles[i].draw();
}
}
else if (e.keyCode == '37') {
for(let i = 0; i < tiles.length; i++) {
tiles[i].setX(tiles[i].getX() - 50);
tiles[i].draw();
}
}
else if (e.keyCode == '39') {
for(let i = 0; i < tiles.length; i++) {
tiles[i].setX(tiles[i].getX() + 50);
tiles[i].draw();
}
}
};
</script>
I am new to Javascript. I am trying to make a canvas game similar to Snake, but without the fruits.
The game is over if the player crosses his own path. The following is my code. Do you know how can I determine when the red rectangle crosses its own path and use the game over function?
Thank you!
var player;
var touch = 0;
function startGame() {
myGameArea.start();
player = new component(30, 30, "red", 270, 270);
}
var myGameArea = {
canvas: document.createElement("canvas"),
start: function() {
this.canvas.width = 600;
this.canvas.height = 600;
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
this.interval = setInterval(updateGameArea, 20);
window.addEventListener('keydown', function(e) {
myGameArea.key = e.keyCode;
})
},
clear: function() {
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
}
function component(width, height, color, x, y) {
this.gamearea = myGameArea;
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.update = function() {
ctx = myGameArea.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
}
}
function updateGameArea() {
/*myGameArea.clear();*/
player.speedX = 0;
player.speedY = 0;
if (myGameArea.key == 37) {
player.speedX = -10;
}
if (myGameArea.key == 39) {
player.speedX = 10;
}
if (myGameArea.key == 38) {
player.speedY = -10;
}
if (myGameArea.key == 40) {
player.speedY = 10;
}
if (player.x <= 0 || player.x >= 570 || player.y <= 0 || player.y >= 570) { //When the player goes out of the canvas
gameOver();
}
player.newPos();
player.update();
}
function gameOver() {
var r = confirm("GAME OVER. Restart?");
if (r == true) {
window.location.reload();
} else {
window.open("https://www.google.ca");
}
}
canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
background-color: #000;
}
<body onload="startGame()">
</body>
Array as a Queue.
The way this game is traditionally done is using a special array type called a queue. Like a real queue you have items added at one end and removed at the other, or first in first out.
Javascript does not have a special array type for a queue but it has all the functions needed to implement a queue.
Push and shift
Array.push(item); // pushes an item onto the top of the array
Array.shift(); // removes an item from the start of the queue
So for the snake game imagine the head as the end of the queue. Every time it moves one forward you place another item on the queue. At the other end you remove an item if the length of the array is longer than the snake length;
var snake = [];
var snakeLength = 10;
function snakeMove(x,y){ // position to move head
checkForHit(x,y); // see below
snake.push({x:x,y:y}); // put another headpiece on the queue
if(snake.length > snakeLength){ // is the length longer than it should be
snake.shift(); // remove a tail item
}
}
To draw the snake you just iterate each part drawing it at the X,y position
To test if the snake has run its self over use the following function
function checkForHit(x,y){
for(var i = 0; i < snake.length; i++){
if(snake[i].x === x && snake[i].y === y){
// Snake has hit its self
}
}
}
When the snake eats something it traditionally grows in length. this is easily done by simply increasing the length variable. snakeLength += 1 makes the queue longer.
And a demo as i have not played the game in so long why not.
"use strict";
var score = 0;
var canvas = document.createElement("canvas");
var scoreE = document.createElement("div");
scoreE.style.color = "white";
scoreE.style.font = "16px arial";
scoreE.style.position = "absolute";
scoreE.style.top = "10px";
scoreE.style.left = "10px";
scoreE.style.width = "600px";
scoreE.style.textAlign = "center";
scoreE.textContent = "Click canvas area to get focus";
canvas.width = 600;
canvas.height = 200;
var ctx = this.canvas.getContext("2d");
document.body.appendChild(canvas);
document.body.appendChild(scoreE);
var lastKeyDown = 0;
window.addEventListener('keydown', function(e) {
lastKeyDown = e.keyCode;
e.preventDefault()
})
var snakePartSize = 8;
var playWidth = canvas.width /snakePartSize;
var playHeight = canvas.height /snakePartSize;
var snake = [];
var snakeLength = 10;
var snakePosX = 0;
var snakePosY = 0;
var snakeDirX = 0;
var snakeDirY = 0;
var snakeSpeed = 16; // number of frame between moves
var gameOver = true;
var instDrawn = false;
var food = [];
var foodFreq = 60;
var yum = 0;
var yumCol = ["red","orange","yellow"];
function startSnake(){
ctx.fillStyle = "black";
ctx.fillRect(0,0,canvas.width,canvas.height);
snakePosX = Math.floor(playWidth / 2);
snakePosY = Math.floor(playHeight / 2);
snakeDirX = 0;
snakeDirY = 0;
snakeLength = 10;
snake = [];
snakeSpeed = 16;
move(snakePosX,snakePosY); // set first pos
food = [];
score = 0;
}
function testHit(x,y){
if(x < 0 || y < 0 || y >= playHeight || x >= playWidth ){
return true;
}
for(var i = 0; i < snake.length; i ++){
if(snake[i].x === x && snake[i].y === y){
return true;
}
}
}
function testFood(x,y){
for(var i = 0; i < food.length; i ++){
if(food[i].x === x && food[i].y === y){
food.splice(i,1);
i --;
yum = 4;
score += 100;
snakeLength += 1;
if(snakeLength % 4 === 0){
snakeSpeed -= snakeSpeed > 1 ? 1:0;
}
}
}
}
function addFood(){
var x = Math.floor(Math.random() * playWidth );
var y = Math.floor(Math.random() * playHeight );
if(!testHit(x,y)){
food.push({x:x,y:y});
drawFood();
}
}
function move(x,y){
if(testHit(x,y)){
gameOver = true;
return;
}
testFood(x,y);
snake.push({x : x, y : y});
drawSnakeHead();
if(snake.length > snakeLength){
drawSnakeTail();
snake.shift();
}
}
function drawYum(){
for(var i = 0; i < snake.length; i ++){
ctx.fillStyle = yumCol[yum];
ctx.fillRect(snake[i].x*snakePartSize, snake[i].y*snakePartSize, snakePartSize, snakePartSize);
}
}
function drawFood(){
var f = food[food.length-1];
ctx.fillStyle = "green";
ctx.fillRect(f.x*snakePartSize, f.y*snakePartSize, snakePartSize, snakePartSize);
}
function drawSnakeHead(){
var head = snake[snake.length-1];
ctx.fillStyle = "red";
ctx.fillRect(head.x*snakePartSize, head.y*snakePartSize, snakePartSize, snakePartSize);
}
function drawSnakeTail(){
var head = snake[0];
ctx.fillStyle = "black";
ctx.fillRect(head.x*snakePartSize, head.y*snakePartSize, snakePartSize, snakePartSize);
}
var counter = 0;
function update(){
counter += 1;
if(!gameOver){
if(snakeDirX === 0){
if(lastKeyDown === 37){ // left
snakeDirX = -1;
snakeDirY = 0;
}
if(lastKeyDown === 39){ // right
snakeDirX = 1;
snakeDirY = 0;
}
}
if(snakeDirY === 0){
if(lastKeyDown === 38){ // up
snakeDirY = -1;
snakeDirX = 0;
}
if(lastKeyDown === 40){ // down
snakeDirY = 1;
snakeDirX = 0;
}
}
lastKeyDown = 0;
if(counter % foodFreq ===0){
addFood();
}
if(counter % snakeSpeed === 0){
snakePosX += snakeDirX;
snakePosY += snakeDirY;
score += 1;
move(snakePosX ,snakePosY);
}
if((counter % 2 === 0) && yum > 0){
yum -= 1;
drawYum();
}
scoreE.textContent = "Score : "+ score;
}
if(gameOver){
if(!instDrawn){
instDrawn = true;
ctx.fillStyle = "white";
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.fillText("GAME OVER",canvas.width /2, canvas.height /2);
ctx.font = "16px arial";
ctx.fillText("Press a direction key to start.",canvas.width /2, canvas.height /2+32);
}
if(lastKeyDown >= 37 && lastKeyDown <= 40){
gameOver = false;
instDrawn = false;
counter = -1;
startSnake();
}
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
startSnake();
I'm making a javascript game using p5 and p5.play and for some reason after the simulation runs for more than 20 seconds the entire thing really slows down. I think it may be a data leak but am unsure of what is truly harming performance.
Update: After some poking around I found that I was successfully removing the sprites from the plain group however there is some other Object called allSprites that is collecting the sprites no matter what. How I remove said sprites from this object is still unknown.
Update: Came up with way to remove them from object, still did not fix data leak.
var players;
var deadly;
var powerUp;
var plain;
var penguinSheet;
var penguinAnimation;
var willLoad;
var harmless;
var score = 0;
function preload(){
penguinSheet = loadSpriteSheet('./assets/BoxPenguinSprites.png', 64, 64, 3);
penguinAnimation = loadAnimation(penguinSheet);
}
function setup() {
createCanvas(700, 600);
// players = new Group();
// deadly = new Group();
// powerUp = new Group();
// harmless = new Group();
plain = new Group();
useQuadTree(true);
player = createSprite(100, 100, 20, 20);
player.debug = true;
}
function update(){
for (var i = 0; i < 10; i++) {
var c = createSprite(
random(width), 0,
random(25, 75), random(10, 30));
c.addSpeed(random(1,3), 90);
c.shapeColor = color(random(30, 50), random(180, 220), random(80, 130));
plain.add(c);
}
// for (var k = 0; k < 3; k++) {
// var d = createSprite(
// random(width), 0,
// random(25, 75), random(10, 30));
// d.addSpeed(random(1,3), 90);
// d.shapeColor = color(random(0, 30), random(150, 160), random(50, 80));
// harmless.add(d);
// }
}
function cleanUp(){
for (var j = 0; j < plain.length; j++){
if (plain[j].newPosition.y > height){
plain.remove(plain[j]);
}
}
// for (j = 0; j< harmless.length; j++){
// if (harmless[j].newPosition.y > height){
// harmless.remove(harmless[j]);
// }
// }
}
function pixleBuffer(){
var offsetX = 0;
var offsetY = 0;
if (keyIsDown(LEFT_ARROW)){
offsetX = -3;
}
if (keyIsDown(RIGHT_ARROW)){
offsetX = 3;
}
if (keyIsDown(UP_ARROW)){
offsetY = -3;
}
if (keyIsDown(DOWN_ARROW)){
offsetY = 3;
}
player.setCollider("rectangle", offsetX , offsetY, 20, 20);
}
//
function draw() {
if (frameCount == 1 || frameCount % 100 == 0){
update();
}
// player.overlap(harmless);
// plain.collide(harmless);
// harmless.collide(plain);
// harmless.collide(harmless);
player.collide(plain);
plain.collide(plain);
if(keyIsDown(LEFT_ARROW)){
player.position.x -= 3
}
if(keyIsDown(RIGHT_ARROW)){
player.position.x += 3
}
if(keyIsDown(UP_ARROW)){
player.position.y -=3
}
if(keyIsDown(DOWN_ARROW)){
player.position.y += 3
}
pixleBuffer();
clear();
cleanUp();
drawSprites();
}