0
\$\begingroup\$

I'm coding this starry background for a website using p5.js, and it has 3 elements:

  1. There is a background that slowly intervals between black and white. This is done by drawing many white circles with varying levels of brightness over a black background

  2. There are many small white stars that decrease in alpha values, and once the alpha hits zero, the star randomly moves to another part of the screen and the alpha resets

  3. Stars within a short distance of the cursor will connect a line from the star's position to the cursor's position

Visualization (the intersection between the lines is where the cursor is; the letter "N" and the word "night" are HTML elements):

enter image description here

However, this can cause a bit of lag on some devices/browsers, so I'm looking to speed it up. Are there optimizations I could do to improve the performance?

let time = 0;
let stars = [];

class Star {
    constructor() {
        this.x = random(0, width);
        this.y = random(0, height);
        this.brightness = random(0, 255);
        this.inc = random(3, 5);
        if (random() < 0.5)
            this.inc *= -1;
    }

    display() {
        fill(255, 255, 255, this.brightness);
        noStroke();
        circle(this.x, this.y, 1.5);

        this.brightness += this.inc;

        if (this.brightness >= 255) {
            this.inc *= -1;
        }
        else if (this.brightness <= 0) {
            this.inc *= -1;
            this.x = random(0, width);
            this.y = random(0, height);
        }
    }
}

function setup() {
  createCanvas(windowWidth - 17, 500);

    for (let a = 0; a < 50; ++a)
        stars.push(new Star());
}

function draw() {
    // background

    clear();

    fill(0);
    rect(0, 0, width, height);

    // circles (white gradient)

    noStroke();

    let clr = (Math.sin(time) * 50) + 10;
    for (let d = (clr + 150); d >= 0; d -= 1) {
        fill(128 - (d / (clr + 150)) * 128);
        circle(0, 0, d * (height / 50));
    }

    time += 0.005;

    // stars and cursor lines

    for (let a = 0; a < stars.length; ++a) {
        stars[a].display();
        
        // `a % 2 == 0` is just to add some randomness to which stars get chosen to form a line
        if (a % 2 == 0 && dist(stars[a].x, stars[a].y, mouseX, mouseY) < 200) {
            stroke(255);
            strokeWeight(2);
            line(stars[a].x, stars[a].y, mouseX, mouseY);
        }
    }
}
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

Reduce state changes

There are two ways that you can improve performance and they depend on what render engine you use (WebGL or Canvas2D). However this is code review and I can not tell you how, only how to improve your code.

The inner loop that renders stars and the lines needs to separate the render states to reduce the number of state changes.

State changes are the main source of slowdown Things like changing color, images, draw type all involve a state change.

Thus you can render the stars and lines using 2 loops. Both identical you your one loop. However each loop not needing to constantly change render state.

Example

// draw stars
for (const star of stars) { star.display(); }

var i = 0;
var distSqrt = 200 * 200;

// setup line state
stroke(255);
strokeWeight(2);

// Find and draw lines
for (const star of stars) { 
    if (i % 2 === 0) {
        const x = star.x - mouseX;
        const y = star.y - mouseY;
        if (x * x + y * y < distSqrt) {
            line(star.x, star.y, mouseX, mouseY);
        }
   }
   i++;
}
    

Result??

How much of an improvement this will be will depend on many factors. Give it a try. If you are not happy with the result please ask the question at stack overflow rather than code review. Good luck.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.