Is it possible to create hundreds of p5 canvases? - javascript

I'm working on a neuroevolution snake game. I wanted to display all the individuals of the current generation on the screen. However it's really slowing things down. Here's the code which creates the canvas.
play_game() {
let game = this;
new p5(p => {
p.setup = function() {
p.createCanvas(game.width, game.width);
p.strokeWeight(1);
tf.setBackend('cpu');
p.frameRate(game.frameRate);
}
p.draw = function() {
p.background("#ddd");
game.snake.display(game.unit, p);
game.snack.display(game.unit, p);
let inputs = game.vision();
game.snake.think(inputs);
let dead = game.check_conditions();
if(dead) {
game.snake.brain.dispose();
game.snake = new Snake([5,5], "#000");
}
};
});
}
Here is the code calling it:
game_array = [];
for(let i = 0; i < 500; i++) {
game_array.push(new Game(100, 20, 10));
}
for(let i = 0; i < 500; i++) {
game_array[i].play_game();
}
Is there a better way to do this or is it even possible?

It is possible to create hundreds of p5 canvases. The key is to run p5 in instance mode. Here is the code to create 400 canvases.
let sketch = function (p) {
p.setup = function () {
p.createCanvas(50, 50);
p.background(p.random(255), p.random(255), p.random(255));
p.stroke(p.random(255), p.random(255), p.random(255));
};
p.draw = function () {
p.point(p.random(p.width), p.random(p.height));
};
};
for (let i = 0; i < 400; i++) {
new p5(sketch);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
An idea for speeding up is to combine contents on 400 canvases and draw on 1 canvas.
400 separated canvases
rendering speed on my computer: 19 fps
demo: https://glitch.com/~400-canvases
combine contents on 400 canvases and draw on 1 canvas
rendering speed: 37 fps
demo: https://glitch.com/~400-canvases-faster

Related

html canvas element blinking and then bugging out

I'm trying to have asteroids moving across the screen for a game. The first few asteroids work and then each asteroid will start blinking and bugging out to the point where they won't move across the screen. The variables acx and acy are the x and y coordinates for the asteroids respectively.
setInterval(throwAsteroid1A, 5000);
function throwAsteroid1A() {
var asteroidCanvas = document.getElementById('asteroidCanvas');
var context = asteroidCanvas.getContext('2d');
var acx = Math.floor(Math.random() * 200);
var acy = Math.floor(Math.random() * 10);
setInterval( () => {
asteroid.onload = function() {
context.drawImage(asteroid, asx, asy, aswidth, asheight, acx, acy, 20, 20);
acx += 1;
acy += 1;
}
asteroid.src = 'https://i.imgur.com/WfQKE6T.png';
}, 10)
setInterval(asteroidPath, 50)
}
function asteroidPath() {
// let computedStyle = getComputedStyle(canvasDisplay)
var asteroidCanvas = document.getElementById('asteroidCanvas');
let ctx = asteroidCanvas.getContext("2d");
ctx.clearRect(acx,acy, canvasDisplay.width, canvasDisplay.height);
}
Well there's obviously something conceptually wrong with your approach. I think the blinking is caused by a timing issue in-between the numerous individual interval timers you set up. The callback function asteroidPath() clears a part of the canvas and this might happen at the same time a new Asteroid has been added to the screen - which will delete it either entirely or partly depending on it's screen position.
To work around it you should:
keep a list of all asteroid objects
clear the screen completely once
update all asteroid's at once - not each one with it's own timer
So an example based on your code might look a little something like this (just click 'Run code snippet'):
Asteroid = function() {
this.acx = Math.floor(Math.random() * 200);
this.acy = Math.floor(Math.random() * 10);
this.image = new Image();
this.image.onload = function(e) {
this.loaded = true;
this.aswidth = e.target.naturalWidth;
this.asheight = e.target.naturalHeight;
}
this.image.src = 'https://i.imgur.com/WfQKE6T.png';
}
var asteroidCanvas = document.getElementById('asteroidCanvas');
var context = asteroidCanvas.getContext('2d');
let asteroids = [];
function spawnAsteroid() {
asteroids.push(new Asteroid());
}
function updateCanvas() {
context.clearRect(0, 0, asteroidCanvas.width, asteroidCanvas.height);
let asteroid;
for (let a = 0; a < asteroids.length; a++) {
asteroid = asteroids[a];
if (asteroid.image.loaded) {
context.drawImage(asteroid.image, 0, 0, asteroid.image.aswidth, asteroid.image.asheight, asteroid.acx, asteroid.acy, 20, 20);
asteroid.acx += 1;
asteroid.acy += 1;
}
}
}
setInterval(spawnAsteroid, 2000);
setInterval(updateCanvas, 50);
spawnAsteroid();
<canvas id="asteroidCanvas"></canvas>

How to separate created group sprites into individual sprites

I'm trying to create a small game that has a soldier moving around a small area and fires bullets. I'm a new programmer who just started javascript not but a few months ago, and so I apologize if my question is poorly worded or my code is clunky.
I've tried using [group].get(i) to isolate each individual sprite that comes out of the gun, but it simply breaks and crashes the program.
Here is all of the code for my (small) program:
var soldier = createSprite(200, 200);
soldier.setAnimation("soldier_still");
var bullet = createGroup();
function draw() {
background(rgb(100, 85, 45));
move();
attack();
drawSprites();
}
function attack() {
if (mouseWentDown("leftButton")) {
for (var i = 0; i < 3; i++) {
bullet.add(createSprite(soldier.x, soldier.y));
bullet.setAnimationEach("bullet");
bullet.pointToEach(World.mouseX, World.mouseY);
bullet.setLifetimeEach(50);
bullet.setSpeedAndDirectionEach(20, World.mouseX, World.mouseY);
}
}
}
function move() {
createEdgeSprites();
World.allSprites.bounceOff(topEdge);
World.allSprites.bounceOff(bottomEdge);
World.allSprites.bounceOff(leftEdge);
World.allSprites.bounceOff(rightEdge);
soldier.pointTo (World.mouseX,World.mouseY);
if (keyDown() == false) {
soldier.setAnimation("soldier_still");
soldier.velocityX = 0;
soldier.velocityY = 0;
}
if (keyDown("up")) {
soldier.setAnimation("soldier_move");
soldier.velocityY = -5;
}
if (keyDown("down")) {
soldier.setAnimation("soldier_move");
soldier.velocityY = 5;
}
if (keyDown("left")) {
soldier.setAnimation("soldier_move");
soldier.velocityX = -5;
}
if (keyDown("right")) {
soldier.setAnimation("soldier_move");
soldier.velocityX = 5;
}
}
The program either crashes, or all bullet sprites face the mouse's position. Is there anyway I can improve my code, or a solution to making each group (bullet) sprite its own individual sprite?

How do you blur a single object in Matter.js?

I'm trying to create a fire effect for a game in Matter.js, and I need to blur a circle to make it look more realistic. However, I need to make it so it only blurs the fire, not the whole canvas. How can I do this?
This is the code I have so far:
function setOnFire(object) {
var fireX = object.position.x;
var fireY = object.position.y;
var fire = Bodies.circle(fireX, fireY, vw*1, {
isStatic: true,
render: {
fillStyle: "rgba(255,130,0,1)"
}
});
World.add(world, fire);
}
This is not exactly what I had in mind, but it is as close as you can get.
Start by going to matter.js and go to this section:
for (k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
part = body.parts[k];
if (!part.render.visible)
continue;
Add this code after the continue;:
if (body.bloom) {
c.shadowColor = body.render.fillStyle;
c.shadowOffsetX = 0;
c.shadowOffsetY = 0;
c.shadowBlur = body.bloom;
}
Then, go to the very end of the loop and add this:
if (body.bloom) {
c.shadowColor = "transparent";
c.shadowOffsetX = 0;
c.shadowOffsetY = 0;
c.shadowBlur = 0;
}
Then, just add the bloom while making your body. For instance:
let fireParticle = Bodies.circle(0, 0, {
bloom: 25
});

How to create objects on runtime and move them?

I'm trying to create objects on my game update and move them. This is my banana object:
function Banana() {
this.height = 1.96;
this.width = 3.955;
this.pos_x = CENTER - this.width/2;
this.pos_y = -475;
this.banana_image = banana_image;
};
And this is the Move method:
Banana.prototype.move = function(){
if (this.pos_y > 500) {
//this.banana_image.parentElement.removeChild(this.banana_image);
}
this.height += ZOOM_RATE;
this.width += ZOOM_RATE;
this.pos_y += 3;
this.pos_x -= SIDES_RATE;
};
This is the Game Update part:
Game.update = function() {
this.player.move();
//creating bananas
if (objs.lenght <= 0) {
this.banana = new Banana();
} else {
for (i = 0; i < 10; i++) {
objs.push(new Banana());
}
}
//moving bananas
for (i = 0; i < objs.lenght; i++) {
this.objs[0].move();
}
};
Game Draw:
function Game.draw = function() {
this.context.drawImage(road, 0,0, rw, rh);
this.context.drawImage(
this.player.player_image,
this.player.pos_x, this.player.pos_y,
this.player.width, this.player.height);
this.context.drawImage(
this.banana.banana_image,
this.banana.pos_x, this.banana.pos_y,
this.banana.width, this.banana.height);
};
I tried to ask this to multiple people, but I can't find an answer for it.
Let's say you want to move the objects 10 times and then stop.
First you need to add a line to the start of Game.draw, so that it clears the canvas making you always start drawing from scratch:
this.context.clearRect(0,0,500,500); // clear canvas, adjust box size if needed
Then make a function to call both update and draw, and queue that function to be called again:
var count = 10;
function updateAndDraw() {
Game.update();
Game.draw();
count--;
if (count) requestAnimationFrame(updateAndDraw);
}
// start moving:
requestAnimationFrame(updateAndDraw);
The movement may go too fast to your liking, so then adjust the move method to make smaller changes, or use setTimeout instead of requestAnimationFrame (but that will make the animation less fluent).
Note that you have a few errors in your code, which you will need to fix first:
lenght should be length
function Game.draw = function() {: remove function before Game.draw.
... check the error messages you get in console.

Canvas game only starts drawing when the window is inactive

I noticed something weird in my canvas code: Im making a game with little flying ghosts. The class for the ghost is below. When I just draw 1 or 2 of em by manually adding the code and having em fly to the right by updating the x every frame for example everything runs smoothly and fine.
Now I ran another test and added a ghost every 100 frames to an array, update its x by 100 and then draw that ghost to the frame. (code is below the first block, the draw function).
Now the problem is that they are actually added and drawn, but I dont see em on the board until I make the window inactive by clicking on the taskbar for example.
Any1 got a clue what is going wrong here?
/*
* Class for little ghosts
*/
function Ghost (name) {
this.name = name;
this.ghost = new Image();
this.ghost.src = "img/ghost.png";
this.ghostWidth = 150;
this.ghostHeight = 100;
this.ghostSpriteOffsetX = 0;
this.ghostSpriteOffsetY = 0;
this.ghostX = 0;
this.ghostY = 0;
}
Ghost.prototype.drawGhost = function() {
context2D.drawImage(this.ghost, this.ghostSpriteOffsetX, this.ghostSpriteOffsetY, this.ghostWidth, this.ghostHeight, this.ghostX, this.ghostY, this.ghostWidth, this.ghostHeight);
};
Ghost.prototype.goToX = function(x) {
this.ghostX = x;
};
Ghost.prototype.goToY = function(y) {
this.ghostY = y;
};
Ghost.prototype.turnPink = function() {
this.ghostSpriteOffsetX = 0;
};
Ghost.prototype.turnBlue = function() {
this.ghostSpriteOffsetX = 150;
};
Ghost.prototype.turnPurple = function() {
this.ghostSpriteOffsetX = 300;
};
-
function draw()
{
// clear board
context2D.clearRect(0, 0, canvas.width, canvas.height);
if(frame%100==0){
ghosts[ghostId] = new Ghost("g-"+frame);
ghosts[ghostId].goToX(frame-100);
ghostId++;
}
// Draw ghost
for (i=0; i<ghosts.length; i++)
{
ghosts[i].drawGhost();
}
frame++;
}

Categories

Resources