I’m trying to write a game engine using p5, but I’ve hit a huge snag: unless I’m doing something wrong (which is definitely possible), the image
function seems really slow. If I call it even just about 40 or 50 times per frame, the frame rate starts to tank, certainly so if I’m calling image
hundreds of times per frame as I was expecting to do. Am I doing something silly, or is this the expected behavior?
Here is the code for a sample I put together:
let img;
let heroX = 350;
let heroY = 350;
let speed = 256;
let desiredFrameRate = 60;
function preload()
{
img = loadImage("TestSprite.png");
}
function setup()
{
createCanvas(400, 400);
frameRate(desiredFrameRate);
}
function draw()
{
background(20);
imageMode(CENTER);
push();
{
for (let i = 0; i < 10; ++i)
{
for (let j = 0; j < 5; ++j)
{
tint(0, 0, 255, 255);
image(img, 8 + i * 16, 8 + j * 16);
}
}
}
pop();
let movement = createVector();
if (keyIsDown(RIGHT_ARROW))
movement.x += 1;
if (keyIsDown(LEFT_ARROW))
movement.x -= 1;
if (keyIsDown(DOWN_ARROW))
movement.y += 1;
if (keyIsDown(UP_ARROW))
movement.y -= 1;
movement = movement.normalize().mult(speed / desiredFrameRate);
heroX += movement.x;
heroY += movement.y;
push();
{
image(img, heroX, heroY);
}
pop();
}
what’s the image size? can you post the code and assets on the web editor?
tint
is a pixel-wise operation (on the spot, no caching) so it’s very slow. If you want to have fixed values for tint
, I highly recommend rendering the images already with a tinted color in a graphics editor, e.g., gimp. Another way is to prepare tinted p5.Graphics (ref), but I recommend the former.
2 Likes
I’m really sorry it took me so long to reply to this. I want to mention that I inadvertently had things set up so that Chrome wasn’t using my GPU, so it was being X-tra slow. Having said that, here is my project:
https://editor.p5js.org/modusponens/sketches/iJ7bp3lVS
Note that it’s still kind of slow if you set useWebGl
to true
and you have the number of rows and columns turned up kind of high. I want to try to determine how many times I actually can call image
per frame and have it not bring down performance.
1 Like
Try to store the background into a separate graphics object.
This way you only have to call the image function once instead of many times (cols x rows).
https://p5js.org/reference/#/p5/createGraphics
3 Likes
Here is a working demo:
https://editor.p5js.org/zuvala/sketches/TT80-whMO
let pg;
let img;
function preload() {
img = loadImage('https://picsum.photos/20/20'); // Load the image
}
function setup() {
createCanvas(400, 400);
pg = createGraphics(400, 400); // <- Create the graphics object
drawPG(); // <- Function that draws the background
}
function drawPG() {
for (let i = 0; i < 20; i++) {
for (let j = 0; j < 20; j++) {
pg.image(img, i*20, j*20); // <- Note that this draws the image to the pg instead of the canvas.
}
}
}
function draw() {
image(pg, 0, 0); // <- Display the graphics as an image.
ellipse(mouseX, mouseY, 40, 40);
}
I do like this idea… So if I want to change any of the background tiles at runtime, I would just overwrite that region of the background image and then still draw the image to the screen the same way as ever, right? This seems like good advice.
I dont know your exact case, but this could work.
Are you working on a game? Maybe you have some more “layers” like for the enemies, the interactive elements, the hero, the menu?
Have you checked this library?
1 Like
Hey, this looks pretty cool. I am trying to build my own engine, so this probably does a bunch of stuff that I want to do myself in my own way, but I will certainly peruse it to see how they do things.