Sunday, 5 May 2019

Op Art with p5

My Dad and I both love Op art, and he recently forwarded an email from Tumblr with this link. It piqued my interest as I'm playing with p5 an awful lot at the minute in my spare time as you'll see from previous posts.

So I got to it but clocked that there might be an issue in terms of masking the squares which make up the image. A little judicious playing with Gimp meant that I knew the graphic would be made up of multiple squares. The squares either started with a black or yellow background and they changed after a delay. To get around the issue of masking, I opted to use createGraphics() and then embed that graphic in the main body of the image using the image() function. I ended up making a simple error though, but Stack Overflow came to my rescue, and I'm quite pleased with the result:

The code, which is also up on GitHub and as a single file on JSFiddle:

class Tile {

    constructor(p5, x, y, dimension, row, delay) {
        this.p5 = p5;
        this.x = x;
        this.y = y;
        this.dimension = dimension;
        this.delay = delay;
        this.onFirst = row % 2;
        this.on = p5.color(255, 184, 0);
        this.off = p5.color(26, 17, 16);
        this.diameter = Math.sqrt(Math.pow(dimension, 2) * 2)
        this.pg = p5.createGraphics(dimension, dimension)
        this.pg.noStroke();
    }

    update() {
        if (this.delay === 0) {
            if (this.diameter < 0) {
                this.diameter = Math.sqrt(Math.pow(this.dimension, 2) * 2);
                this.onFirst = !this.onFirst;
                this.delay = 120;
            }
            else {
                this.diameter -= 1;
            }
        } else {
            this.delay -= 1;
        }
        return this.draw();
    }

    draw() {
        this.pg.fill(this.onFirst ? this.off : this.on);
        this.pg.rect(0, 0, this.dimension, this.dimension);
        this.pg.fill(this.onFirst ? this.on : this.off);
        this.pg.circle(this.dimension / 2, this.dimension / 2, this.diameter);
        return this.pg;
    }
}

new p5(p5 => {

    const rows = 14;
    const columns = 14;
    const dimension = 40;
    const framerate = 20;
    const tiles = [];
    const delay = 30;

    p5.setup = () => {
        p5.createCanvas(columns * dimension, rows * dimension);
        for (let row = 0; row < rows; row++) {
            for (let column = 0; column < columns; column++) {
                tiles.push(new Tile(
                    p5,
                    column * dimension,
                    row * dimension,
                    dimension,
                    row,
                    column % 2 ? ((rows - row) * 5) + 80 : row * 5
                ));
            }
        }
    };

    p5.draw = () => {
        p5.background(200);
        tiles.forEach((tile) => {
            p5.image(tile.update(), tile.x, tile.y);
        });
    };
});

No comments:

Post a Comment