annoyingmouse
annoyingmouse

Reputation: 5699

Issues with multiple p5.image

I'm playing around with creating some optical art with p5 and I'm running into issues with the image function. This is mt sketch.js file:

import Tile from "./Tile.js";

new p5(p5 => {

    const rows = 14;
    const columns = 14;
    const dimension = 40
    const height = rows * dimension;
    const width = columns * dimension;
    const framerate = 1;
    const tiles = [];

    p5.setup = () => {
        p5.createCanvas(width, height);
        p5.frameRate(framerate);
        for (let r = 0; r < rows; r++) {
            for (let c = 0; c < columns; c++) {
                tiles.push(new Tile(p5, c * dimension, r * dimension, dimension, r, c));
            }
        }
    };

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

And this is Tile.js:

export default class Tile {

    constructor(p5, x, y, dimension, row, column) {
        this.p5 = p5;
        this.x = x;
        this.y = y;
        this.dimension = dimension;
        this.row = row;
        this.column = column;
        this.onFirst = true;
        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 = this.p5.createGraphics(dimension, dimension)
        this.pg.noStroke();
    }

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

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

While I starting out I just had the one image and that was displayed on the top left as I wanted... subsequent images are not though, artefacts appear in odd places though (as you can see here: https://jsfiddle.net/annoyingmouse/Lbs9v8f4/). I've tried all sorts of things like exporting the image as a Base64 image and using loadImage but I think I might've been barking up the wrong tree.

Any help would be greatly appreciated :-)

Upvotes: 1

Views: 681

Answers (1)

Rabbid76
Rabbid76

Reputation: 211278

Note, the method Tile.draw draws to an image (.pg) with a size of (.dimension, .dimension) rather than the canvas. So the the origin has to be (0, 0) rather than (.x, .y), because the final image (.pg) is placed on the canvas at (.x, .y).

Change the code as follows, to solve the issue:

draw() {
    this.pg.fill(this.onFirst ? this.off : this.on);

    // this.pg.rect(this.x, this.y, this.dimension, this.dimension);
    this.pg.rect(0, 0, this.dimension, this.dimension); 

    this.pg.fill(this.onFirst ? this.on : this.off);

    // this.pg.circle(this.x + this.dimension / 2, this.y + this.dimension / 2, this.diameter);
    this.pg.circle(this.dimension / 2, this.dimension / 2, this.diameter);

    return this.pg;
}

See the example:

new p5(p5 => {

const rows = 14;
const columns = 14;
const dimension = 40
const height = rows * dimension;
const width = columns * dimension;
const framerate = 60;
const tiles = [];

p5.setup = () => {
    p5.createCanvas(width, height);
    p5.frameRate(framerate);
    for (let r = 0; r < rows; r++) {
        for (let c = 0; c < columns; c++) {
            tiles.push(new Tile(p5, c * dimension, r * dimension, dimension, r, c));
        }
    }
};

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

class Tile {

    constructor(p5, x, y, dimension, row, column) {
        this.p5 = p5;
        this.x = x;
        this.y = y;
        this.dimension = dimension;
        this.row = row;
        this.column = column;
        this.onFirst = true;
        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 = this.p5.createGraphics(dimension, dimension)
        this.pg.noStroke();
    }

    update() {
        if (this.diameter < 0) {
            this.diameter = Math.sqrt(Math.pow(this.dimension, 2) * 2);
            this.onFirst = !this.onFirst
        }
        else {
            this.diameter -= 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;
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.js"></script>

Upvotes: 1

Related Questions