In this project, we are creating a Particle World, an imaginary space that is filled with numerous particles, utilizing Object-Oriented Programming (OOP) to visualize and simulate a real-world shape, pattern, movement, or natural phenomenon.
The particle phenomenon I created was the sparkles from a campfire that are flying into the dark sky. By not only mimicking the movement and appearance of real sparkles but also adding more alive and free motions to it, I tried to create this more fictional particle world with this almost creature-like campfire.
In my Dance Floor project, I learned that adding two layers of color is a good strategy to mimic the appearance of flame, so for the sparkles I also created both inner and outer colors.
I also manipulated the opacity of the colors and the background to make them gradually disappear with a certain amount of trace behind them.
Moreover, to make the texture richer and more sparkly, I added very small circles around the main flame.
First color layer with sparkles.
let outerColor = color(255, 70, 0, this.life * 0.5);
fill(outerColor);
for (let i = 0; i < 5; i++) {
push();
translate(this.x, this.y);
rotate(frameCount * 0.02 + i * (TWO_PI / 5));
triangle(
0, -this.size/2,
-this.size/3, this.size/2,
this.size/3, this.size/2
);
pop();
}
let innerColor = color(255, 200, 50, this.life * 0.8);
fill(innerColor);
for (let i = 0; i < 3; i++) {
push();
translate(this.x, this.y);
rotate(-frameCount * 0.03 + i * (TWO_PI / 3));
triangle(
0, -this.size * 0.3,
-this.size * 0.2, this.size * 0.3,
this.size * 0.2, this.size * 0.3
);
pop();
}
fill(255, 255, 200, this.life);
let sparkleSize = this.size / 8;
for (let i = 0; i < 3; i++) {
let sparkleX = this.x + random(-this.size/2, this.size/2);
let sparkleY = this.y + random(-this.size/2, this.size/2);
circle(sparkleX, sparkleY, sparkleSize);
}
pop();
I initially built the shape with circles but they looked too rigid and thus didn't look like flames or sparkles.
After trying different shapes, the final solution I found was adding internal motions to the patterns with triangles. It turned out quite sparkly and the shapes of triangles are actually not very recognizable without zooming in so I was satisfied with it.
I tried to create a star-like pattern with 5 evenly spaced triangles rotating around a central point with i * (TWO_PI / 5).
To make them constantly rotating, the key was just using framecount. The frameCount * 0.02 part adds continuous rotation to this pattern over time.
Zoom-in of the shapes.
let outerColor = color(255, 70, 0, this.life * 0.5);
fill(outerColor);
for (let i = 0; i < 5; i++) {
push();
translate(this.x, this.y);
rotate(frameCount * 0.02 + i * (TWO_PI / 5));
triangle(
0, -this.size/2,
-this.size/3, this.size/2,
this.size/3, this.size/2
);
pop();
}
let innerColor = color(255, 200, 50, this.life * 0.8);
fill(innerColor);
for (let i = 0; i < 3; i++) {
push();
translate(this.x, this.y);
rotate(-frameCount * 0.03 + i * (TWO_PI / 3));
triangle(
0, -this.size * 0.3,
-this.size * 0.2, this.size * 0.3,
this.size * 0.2, this.size * 0.3
);
pop();
}
Floating upward
Drifting side to side
Having a slight random horizontal movement
Fading out over time
Getting smaller as they rise
update() {
this.y += this.speedY;
this.x += this.speedX;
this.x += random(-1, 1);
this.life -= 0.9;
this.size *= 0.99;
}
This is a new trick I learned in this project that I think is quite essential to the final result. "this.life" is a property that acts like a lifetime or lifespan counter for each particle. In the update, the opacity it controls decreases by 0.9 each frame.
update() {
this.life -= 0.9;
}
I really enjoyed the flexibility and modularity OOP provides. I could easily add more things to the pattern without disturbing other code and could easily navigate both the internal and external motions of the particles. I also like how clear the structure is. I hope I will have the structure in mind without the help of the template as well.
Tips I learned:
this.y += this.speedY is equivalent to this.y = this.y + this.speedY;
this.y -= this.speedY is equivalent to this.y = this.y - this.speedY;
if (p.y < 0) {
particles[i] = new Particle(random(width/2-50, width/2+50), height);
}
Check if a particle has moved above the top of the canvas (p.y < 0). If it has, creates a new particle at the bottom of the screen (height).
What is Object-Oriented Programming (OOP), a Class and an Instance of the Class?
According to the reading and what we learned in class:
"Object-Oriented Programming (OOP) is a paradigm that structures software by organizing data and behaviors into objects created from classes. A class is a template that defines the attributes and behaviors shared by all objects of that type. An instance is a specific object created from a class, containing its own data but sharing the methods defined in the class."
Discuss the effectiveness of OOP. When is OOP useful? In what way can it be utilized?
We used OOP for the Dance Floor project as well. As I was only dealing with one object but not organizing the entire dance floor, I didn't quite see the point of using OOP because I didn't really need to duplicate any pattern or motion. However, in this particle project I found OOP very necessary. It is very convenient to manipulate the behaviour and appearance individually with OOP, another key to particles, scale is also easy to adjust.
OOP can be utilized to create and organize clear, reusable and scalable components as well as model behaviors and states of objects, ensuring easy maintenance and enhancement over time.
Describe the objects you have created. What properties and methods were implemented? What kind of behaviors did you create by manipulating them?
Simply speaking, the major pattern of the particles is rotating triangles, that's the internal structure. While the external structure is the particles coming out of the center of the bottom edge of the canvas and spread out while rising up. Thanks to how OOP allows me to abstract these designs, I was able to organize them easily.