Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/seoproductions/sand-demo
Quick and Easy sand simulation built in C++ using olc's PixelGameEngine
https://github.com/seoproductions/sand-demo
cplusplus-17 demo-app olcpixelgameengine
Last synced: about 18 hours ago
JSON representation
Quick and Easy sand simulation built in C++ using olc's PixelGameEngine
- Host: GitHub
- URL: https://github.com/seoproductions/sand-demo
- Owner: seoProductions
- Created: 2024-03-20T14:38:20.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2024-05-16T23:29:18.000Z (6 months ago)
- Last Synced: 2024-05-17T22:43:17.592Z (6 months ago)
- Topics: cplusplus-17, demo-app, olcpixelgameengine
- Language: C++
- Homepage:
- Size: 427 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Welcome to my Sand Demo, take a look!!
A simple project that simulates sand and water particles acting on a 2D world. This project utilizes the concept of a cellular automata, combined with Object Oriented and Function programing.
# Features
#### Sand
![sand_demonstration](https://github.com/seoProductions/Sand-Demo/assets/111206081/c46b3575-7001-45c1-91c8-3eb74aef66df)#### Water
![water_demonstration](https://github.com/seoProductions/Sand-Demo/assets/111206081/f9902f85-b0b3-4a31-a1d5-f9c2f65e2d69)#### Solid (WALL)
![water_pour](https://github.com/seoProductions/Sand-Demo/assets/111206081/5dedddaf-0efa-4da3-af5d-78d6465fee62)#### Here are some more demonstrations:
![stream_demonstration](https://github.com/seoProductions/Sand-Demo/assets/111206081/b16c889f-c8e7-4672-9f94-90b2b38066bf)![Cube Demonstration](https://github.com/seoProductions/Sand-Demo/assets/111206081/494bbe5f-07b4-42a3-a54a-9f9a033c2324)
#### This is a messy one!
![messy_one](https://github.com/seoProductions/Sand-Demo/assets/111206081/ed71eea2-67c8-49b4-84a2-0453b6407f99)## Lessons Learned
While building this project, I both learned and tested many skills including
- Project Design
- This project had to be drawn out and well thought about before execution!- Memory manegment
- I dont want to eat up my computers memory!- Dynamic memory allocation
- Every particle on screen is allocated onto the Heap
- Used smart pointers for saftey- Debugging with memory issues
- Segmentation Faults!- Naming things! I am working on this one!
- Polymorphism and Inheritance
- My particle system is built entirely from OOP
- Working with olc::PixelGameEngine derived classes and methods- Shell Scripting on linux
- Automated compiling system using bash scripting- Basics of version controll using git
- Learning to use git thru terminal will come in handy!Here is a birds eye view of the project and its structure. Included is a UML Diagram
![SandSimulationUML](https://github.com/seoProductions/Sand-Demo/assets/111206081/e05571c7-4e0b-4b86-a1c3-d5505d28898a)
# Gist of the program
The program first launches into the main function where I have created a class called Engine.
```c++
class Engine : public olc::PixelGameEngine
```This class is derived directly from the PixelGameEngine's Base class. The base class handles nessesary functionality such as
- Window creation
- Drawing
- Keyboard and Mouse InputsLooking into the Engine Class, I have a collection of Pointers of type "Particle" (More info on that later). I have these pointers held into std::vector simply due to simplicity and efficiency.
```c++
std::vector> particles;
```During the game loop, the Engine checks for a Left click from the user. If sucessfull, new "Particle" pointers are dynamically allocated into the std::vector container.
```c++
if (GetMouse(0).bHeld)
{
switch (CurrentKeyDown)
{
case SandDown:
particles.push_back(
std::make_shared(GetMouseX(), GetMouseY()));
break;
case WaterDown:
particles.push_back(
std::make_shared(GetMouseX(), GetMouseY()));
break;
case SolidDown:
particles.push_back(
std::make_shared(GetMouseX(), GetMouseY()));
break;
}
}
```Each Particle is iterated over as shown here:
```c++
for (auto particle: particles)
{
// check bounds and idle status
if (particle->y < ScreenHeight() - 1 && !particle->idle)
particle->updateParticle(); //update
//draw a pixel depending on the particle's type
switch (particle->getDrawType())
{
case DrawSand:
Draw(particle->x, particle->y, sandColor);
break;
case DrawWater:
Draw(particle->x, particle->y, waterColor);
break;
case DrawSolid:
Draw(particle->x, particle->y, solidColor);
break;
}
}
```
the virtual updateParticle() method is invoked, and the Engine chooses a pixel color and pixel position to draw onto the screen.## Particle
This is the meat and Potatoes. The Particle class is the parent class for all particle types.```c++
class Particle
```
this class contains
- x and y position
- idle status
- generic "move" methods
- virtual methodsBase classes are
```c++
class Sand : public Particle
class Water: public Particle
class Solid: public Particle```
They each contain
- specific update function
- specific DrawType### Particle Rules and behavior
- Solid particles never move and are always idle
- Sand particles will try to move below, then below to the (left/right)
- Water particles do the same as sand, exept they also try to move directly (left/right)The implementation for the rules was the most tedious part of my project, including many long and painfull debugging sessions, and crazy unexpected bugs. At the end, I got a working prototype! Far from perfect, but much more better than what I started off with.
### Special case:
Each water particle has a structure called "OscilationDetector". It simply aids in determining when to put a water particle into idle.```c++
struct OscillationDetector
{
bool bIsLeft = rand() % 2; //random
short count = 0;
};
//Once occil_count reaches max, water particle will be set to idle
const int max_Oscilations = 2;
```
Each water particle stores its current direction, and a count for direction changes ( hence the name: "Oscilations" )
The counter only works at a constant Y level, thus at every vertical movement, the counter is reset. Once the max_Oscilations value is met, the particle is put into idle.## Collision Detection using "CollisionBoard"
Each particle has a static member of a CollisionBoard. This variable is set in the Engine class, and is used by all particles when checking their movements. Methods include:
```c++
PixelType CheckBelow (int x, int y);
PixelType CheckBelowLeft (int x, int y);
PixelType CheckBelowRight (int x, int y);
PixelType CheckLeft (int x, int y);
PixelType CheckRight (int x, int y);void setPixelType(int x, int y, PixelType type);
```The whole std::vector or "board" is initialized to FreeSpace inside the constructor.+
## Enumerations
Looking at the UML, you can see I have created three Enumerations scattered around my program. These are helpfull features that I used to develop this program
- The "KeyDown" enum is used to track which keyboard buttons have been recently pressed
- The "DrawType" enum is used to identify particle types present in the std::vector of Particles. I figured this was the simplest way to impliment this, wanting to avoid dynamic casting and other perplexing methods capable of throwing exeptions...
- "PixelType" enum is primarily used in the "CollisionBoard" class. It servers as the collection type used in a 2D std::vector called "board". With this, the CollisionBoard class has a sence of - what particles are in the 2D worlds and the position in which it is at. This is crucial for simulating real-time collision```c++
std::vector> board;
```## Running the program
To run the program, run the following command
```bash
chmod +x run.sh
./run.sh
```Or simply compile with your compliler of choice. I am using g++ here
```bash
#!/bin/bash
g++ -o driver driver.cpp \
collision.h \
collision.cpp \
particles.h \
particles.cpp \
-lX11 -lGL -lpthread -lpng -lstdc++fs -std=c++17
./driver
```## Q&A
#### What made you choose c++ for this project?
I had been using c++ for close to a year now - at the time of making this project (2023). I had grown fairly comfortorable with the language, but not to the point where I could develop larger scale projects. I took on this project our of pure curiosity and initiative. As a result, I ended up learning much more than I anticipated. And lets not forget the great performance c++ has!
#### What made you choose olc's PixelGameEngine?
The developer of the game engine is a favorite youtuber of mine, and I take great inspiration from him. I picked up the game engine during Highschool - a time when I was exploring many fields in computing. This included: Reverse-Engineering, 3D graphics, Game Developement, and much more. I was exploring at the time, and I just so happened to be familiar with the PixelGameEngine I used in my Sand Demo.
#### I see your std::vector uses shared_ptr's , why not unique_ptr's?
I am using shared pointers because the iterator generated from the code block above - incriments the total instances of this pointer. A unique ptr woudnt allow me to generate an iterator of Particles, and I simply wanted to keep things simple
#### I have another question!!
Feel free to reach out to me through my email or LinkedIn:
- [[email protected]]([email protected])
- [LinkedIn](https://www.linkedin.com/in/eliseo-duque)## Related
Here are some related projects:
[Physics-Simulation in C++](https://github.com/seoProductions/Sandy---Physics-Simulation)
## Authors
[@seoProductions](https://github.com/seoProductions)
## License
[MIT](https://choosealicense.com/licenses/mit/)