Week 7 - Ecosystem Project [CONTINUED]

FINAL VERSION of my code.
This week, I am continuing where I had left off with my graffiti ecosystem. I’ve got quite a lot more to add to the project.
STEP ONE - MAKING A GRAFFITI CLASS & FIXING PRELOAD
My previous sketches were made to test my ideas for how the ecosystem was to ultimately function and subsequently, I neglected to tie all of my graffiti-related code to its own graffiti class. I also had a terrible array in preload, with all 40 pngs laid out in a row. I definitely needed to fix that, haha.
Here’s what I did:
function preload() {
for (let i = 0; i < 40; i++) {
graffitiImages[i] = loadImage(`graffiti/${nf(i + 1, 2)}.png`);
}
}
Since all of the image file names follow the same format (01.png, 02.png, etc…), I needed to include ‘nf(i + 1, 2)’ to ensure that each image in the array appropriately matches the naming configuration.
GRAFFITI CLASS STUFF
There were a lot of updates made in this section of my project, so I’d like to go through each part individually.
NUMBER ONE
class Graffiti {
constructor(images, canvasWidth, canvasHeight) {
this.images = images; //all preloaded imgs
this.displayedImages = [];
this.yOffset = 0;
this.dragging = false;
this.speed = 2.6;
this.lastUpdateTime = millis();
this.lastDragTime = millis();
this.updateInterval = 10000; //10s before new set is drawn
this.dragDelay = 1500; //the delay before that happens
this.canvasWidth = canvasWidth;
this.canvasHeight = canvasHeight;
this.generateNewImages();
}
So here is the constructor of the Graffiti class I’ve made. This portion is basically just moving all of the previous variables inside of this new class, however, there are some new variables like updateInterval and dragDelay that I’ve added. These are for graffiti dragging automation after a set time (I want to create the illusion that the art is repeatedly being power washed off of the wall). Right now, I have the graffiti update interval set to 10 seconds because it made it easier to test my code, though I plan on increasing this variable in my final sketch.
NUMBER TWO
update() {
let currentTimeg = millis();
//start dragging automatically after updateInterval
if (currentTimeg - this.lastUpdateTime > this.updateInterval) {
this.dragging = true;
}
//move images downward when dragging
if (this.dragging) {
this.yOffset += this.speed;
}
//check if all images are off-screen
if (this.yOffset > this.canvasHeight) {
this.dragging = false;
if (currentTimeg - this.lastDragTime > this.dragDelay) {
this.generateNewImages();
}
}
}
What this update portion does is draw a new set of graffiti images (6 pngs) after the previous set has been translated entirely off of the canvas, and a brief delay has passed. It will also automatically drag the art down if it 10 seconds [to be updated] have passed since the last set was displayed.
NUMBER THREE
display() {
for (let i = 0; i < this.displayedImages.length; i++) {
image(this.displayedImages[i], 0, this.yOffset, this.canvasWidth, this.canvasHeight);
}
}
generateNewImages() {
this.lastUpdateTime = millis();
this.lastDragTime = millis();
this.displayedImages = [];
for (let i = 0; i < 6; i++) {
let randomIndex = floor(random(this.images.length));
this.displayedImages.push(this.images[randomIndex]);
}
this.yOffset = 0; //reset position
}
I’m grouping both the display() and generateNewImages() portion of my Graffiti class in the same segment to save some space here in my devlog. This display is a forloop that will pull data from the array for the 6 random pngs selection, and then draw said images. generateNewImages() is where our 6 random graffiti pieces are selected and where timing and positioning of new sets are reset (sorry for the very confusing wording here).
A NOTE
I plan on adding gravity to the image assets as they are dragged off the canvas to simulate them being “washed” a little better. That will come later once I have my other classes added to the sketch.
STEP TWO - WE NEED AN ARTIST
I made a gif of a graffiti artist appearing on screen, painting it, then sliding off like a smooth criminal. Working with gifs was certainly tricky but I’d like to share what I came up with:
CONSTRUCTOR
class graffitiArtist {
constructor(img, x, y, width, height, duration) {
this.img = img;
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.visible = false;
this.startTime = 0;
this.duration = 8500;
this.ready = true;
}
Essentially all this is doing is setting the parameters for my gif.
APPEAR
appear() {
if (this.ready) {
//only allow appearing if ready
this.visible = true;
this.startTime = millis();
this.ready = false;
//hide the artist after one loop
setTimeout(() => {
this.visible = false;
}, this.duration);
}
}
I wanted the gif to only play once per new graffiti set generation (it’s about 8.5s long) without any chance of a loop occurring. I did not fully succeed but I am too lost to spend any more time trying to remedy the issue. Plus, the gif playback’s erratic nature is definitely not a bug.
UPDATE, RESET, DISPLAY
update() {
if (this.visible && millis() - this.startTime > this.duration) {
this.visible = false;
}
}
reset() {
this.ready = true;
}
display() {
if (this.visible) {
image(this.img, this.x, this.y, this.width, this.height);
}
}
I’ve grouped these three parts of the class together since they are relatively short. What update does is check if the artist has been visible for longer than 8.5 seconds. If it has, then the gif becomes hidden. Reset is the part of my code where I think the gif loop problem lies. I have artist.reset() written into the update() of my Graffiti class because I am looking to sync the appearance of the graffiti artist to the graffiti itself. If there are any suggestions for how to fix this, I’m all ears. Until then, the gif being a bit buggy is a FEATURE!
Here is a link to my sketch as it currently stands.
STEP THREE - CLEANUP CREW
In one of my other classes, Intro to 2D Animation, we were tasked with creating a flipbook animation. I figured I’d kill two birds with one stone and make my power washer gif for this project. I’ve attached what that looks like above and now, I just need to code him into my sketch. I am going to adopt parts of my graffitiArtist() class for this portion of the sketch.
WHAT TO KNOW
I’m going to keep the explanation of this portion of the code brief because it was highly comparable to the graffitiArtist process–nothing new was learned, really. The primary difference is that I was able to trouble shoot my gif problems a little bit more precisely–setting the splash gif’s duration to 6900 (meme number, I know) was the magic fix here.
STEP FOUR - GRAVITY
The idea for this part of my project is as follows: each piece of graffiti will be assigned a random mass between 1 and 3 and will thus be affected by the powerwasher differently. The graffiti is only affected by gravity once image dragging begins. To accomplish this, I needed to rewrite my initial if(this.dragging){} if statment. Here’s what that looks like now:
if (this.dragging) {
for (let graffitiO of this.displayedImages) {
let gravityForce = graffitiO.mass * this.gravity;
graffitiO.velocity += gravityForce;
graffitiO.yOffset += graffitiO.velocity;
}
}
graffitiO is the variable I chose for our image objects. It’s now also the name of a space cereal brand–I’m going to start an intergalactic empire. This if statement calculates force by multiplying mass by gravity. It then will increase velocity by force, and take our yOffset and updates it by adding velocity, which in turn drags graffiti off of the canvas at different speeds based on their mass.
Next step was to tweak my image drag check:
if (this.displayedImages.every(graffitiO => graffitiO.yOffset > this.canvasHeight)) {
this.dragging = false;
every() is very helpful because it will only return true if all parts of the array satisfy the condition that each image (graffitiO) has a greater yOffset than the canvas. If they all do, dragging stops.
Display also needed a revamp because my images are now objects.
display() {
for (let graffitiO of this.displayedImages) {
image(graffitiO.img, 0, graffitiO.yOffset, this.canvasWidth, this.canvasHeight);
}
}
This is just a more compressed, cleaner way to parse the array and display new images.
Finally, I needed to update the for loop in setTimeout.
for (let i = 0; i < 6; i++) {
let randomIndex = floor(random(this.images.length));
let mass = random(1, 3);
this.displayedImages.push({
img: this.images[randomIndex],
mass: mass,
yOffset: 0,
velocity: 0
});
}
To explain briefly, since I feel like I’ve unfortunately made this too long (it’s mainly for myself anyway, right?) This for loop remains the same in that it will parse 6 random graffiti images, however, now it will also assign a random mass to each and then add said images to the displayedImages array.
Get Drawing, Moving and Seeing with Code - Spring 2025
Drawing, Moving and Seeing with Code - Spring 2025
Jack Fleming's work for class
More posts
- Week 9 - Hydra and P5Live18 days ago
- Week 6 - Ecosystem [DRAFT]40 days ago
- Week 5 - Smart Robot ALFIE47 days ago
- Week 4 - Generative Daily Project54 days ago
- Week 3 - Creature Class61 days ago
- Week 2 - Iceberg Simulation68 days ago
- Week 1 - A LOGO Crazy Quilt75 days ago
Leave a comment
Log in with itch.io to leave a comment.