Skip to content

Instantly share code, notes, and snippets.

@Sam-Belliveau
Last active November 26, 2017 21:03
Show Gist options
  • Save Sam-Belliveau/edd8558d057495cdf2ed7cf0994514a2 to your computer and use it in GitHub Desktop.
Save Sam-Belliveau/edd8558d057495cdf2ed7cf0994514a2 to your computer and use it in GitHub Desktop.
You need sfml to run this. Change line 25 to change particals
/*
CONTROLS:
Up - Move Up
Down - Move Down
Left - Move Left
Right - Move Right
W - Zoom In
S - Zoom Out
Left Click - Attract
Right Click - Expand
*/
/* Include */
#include <SFML/Graphics.hpp> // For making art
#include <cmath> // abs, sqrt, fmaxf
#include <vector> // FOR VECTORS
#include <omp.h>
/* VARS */
// Amount of particals
const float amount = 1000000;
// Speed of actions
const float force = 512;
const float speed = 512;
const float zoomSpeed = 1;
// Minimums
const float minZoom = 0.0625;
const float minDis = 0.5;
// Window
const int width = 1280;
const int height = 720;
// Halfs (for cam)
const float widthHalf = width / 2;
const float heightHalf = height / 2;
const float sqrtHalf = sqrt(amount) / 2;
// Mouse States
enum mousePosition { none, away, closer };
// Camera data
struct camData
{
sf::Vector2f offSet = sf::Vector2f(0, 0);
float zoom = 1;
}; camData cam;
// Vel and Pos of a partical
struct particalData
{
sf::Vector2f pos = sf::Vector2f(0, 0);
sf::Vector2f vel = sf::Vector2f(0, 0);
}; std::vector<particalData> particals;
// What you draw too
sf::VertexArray drawBuffer = sf::VertexArray(sf::Points, amount);
// The Window
sf::RenderWindow app(sf::VideoMode(width, height), "Particals", sf::Style::Close);
/* METHODS */
void reset()
{
// Reset Camera
cam.offSet = sf::Vector2f(sqrtHalf - widthHalf, sqrtHalf - heightHalf);
cam.zoom = 1;
// Clear Particals
particals.clear();
for (unsigned long i = 0; i < amount; i++)
{
particalData temp;
// Set Position In a Square
temp.pos.x = (float)(i % (long)sqrt(amount));
temp.pos.y = (float)((i - (i % (long)sqrt(amount))) / sqrt(amount));
// COLORS!!
drawBuffer[i].color = sf::Color((temp.pos.x * 255.f) / sqrt(amount), (temp.pos.y * 255.f) / sqrt(amount), 255.f - ((temp.pos.x * 255.f) / sqrt(amount)));
// Allocate one by one to prevent overflow
particals.push_back(temp);
}
}
void draw(mousePosition mouse, sf::Vector2i &mousePosition, float fps)
{
if (mouse == mousePosition::none) // mouse up
{
#pragma omp parallel for
for (unsigned long i = 0; i < amount; i++)
{
// move partical
particals[i].pos.x += particals[i].vel.x / fps;
particals[i].pos.y += particals[i].vel.y / fps;
// show partical based on camera
drawBuffer[i].position.x = (particals[i].pos.x - cam.offSet.x) / cam.zoom;
drawBuffer[i].position.y = (particals[i].pos.y - cam.offSet.y) / cam.zoom;
}
} else
{
if (mouse == mousePosition::closer)
{
#pragma omp parallel for
for (unsigned long i = 0; i < amount; i++)
{
// Calculate mouse with camera stuff
const float mouseX = (float)mousePosition.x * cam.zoom + cam.offSet.x;
const float mouseY = (float)mousePosition.y * cam.zoom + cam.offSet.y;
// So access is faster
const float posX = particals[i].pos.x;
const float posY = particals[i].pos.y;
// Since we use abs() we half to find what side the mouse is on
const bool sideX = posX > mouseX;
const bool sideY = posY > mouseY;
// Distance of x and y
const float disX = abs(posX - mouseX);
const float disY = abs(posY - mouseY);
// Get a greak guy to use a ruler
const float dis = sqrt((disX*disX) + (disY*disY));
// find ratio AKA direction
const float rat = ((disX * cam.zoom * force) / (disX + disY)) / dis;
const float invertRat = ((cam.zoom * force) / dis) - rat;
// if the mouse is right click, flip distance and make it go away
// MAGIC
// move the vel with formula
if (sideX) { particals[i].vel.x -= rat; }
else { particals[i].vel.x += rat; }
if (sideY) { particals[i].vel.y -= invertRat; }
else { particals[i].vel.y += invertRat; }
// actually update partical
particals[i].pos.x += particals[i].vel.x / fps;
particals[i].pos.y += particals[i].vel.y / fps;
// move the drawn partical
drawBuffer[i].position.x = (particals[i].pos.x - cam.offSet.x) / cam.zoom;
drawBuffer[i].position.y = (particals[i].pos.y - cam.offSet.y) / cam.zoom;
}
} else
{
#pragma omp parallel for
for (unsigned long i = 0; i < amount; i++)
{
// Calculate mouse with camera stuff
const float mouseX = (float)mousePosition.x * cam.zoom + cam.offSet.x;
const float mouseY = (float)mousePosition.y * cam.zoom + cam.offSet.y;
// So access is faster
const float posX = particals[i].pos.x;
const float posY = particals[i].pos.y;
// Since we use abs() we half to find what side the mouse is on
const bool sideX = posX > mouseX;
const bool sideY = posY > mouseY;
// Distance of x and y
const float disX = abs(posX - mouseX);
const float disY = abs(posY - mouseY);
// Get a greak guy to use a ruler
const float dis = sqrt((disX*disX) + (disY*disY));
// find ratio AKA direction
const float rat = ((disX * cam.zoom * force) / (disX + disY)) / dis;
const float invertRat = ((cam.zoom * force) / dis) - rat;
// if the mouse is right click, flip distance and make it go away
// MAGIC
// move the vel with formula
if (sideX) { particals[i].vel.x += rat; }
else { particals[i].vel.x -= rat; }
if (sideY) { particals[i].vel.y += invertRat; }
else { particals[i].vel.y -= invertRat; }
// actually update partical
particals[i].pos.x += particals[i].vel.x / fps;
particals[i].pos.y += particals[i].vel.y / fps;
// move the drawn partical
drawBuffer[i].position.x = (particals[i].pos.x - cam.offSet.x) / cam.zoom;
drawBuffer[i].position.y = (particals[i].pos.y - cam.offSet.y) / cam.zoom;
}
}
}
app.draw(drawBuffer); // TAKE A GUESS
}
int main()
{
sf::ContextSettings settings;
settings.antialiasingLevel = 16;
app.create(sf::VideoMode(width, height), "Particals", sf::Style::Close, settings);
reset();
// FPS STUFF YAY
// MAKES STUFF CONSISTANT
sf::Clock clock;
float currentTime = clock.restart().asSeconds();
float fps = 1.f / currentTime;
while (app.isOpen())
{
// Process events
sf::Event event;
while (app.pollEvent(event))
{
// Close window : exit
if (event.type == sf::Event::Closed)
app.close();
}
// Controls
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
{
reset();
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
cam.offSet.y -= (speed*cam.zoom) / fps;
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
cam.offSet.y += (speed*cam.zoom) / fps;
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
cam.offSet.x -= (speed*cam.zoom) / fps;
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
cam.offSet.x += (speed*cam.zoom) / fps;
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
if (cam.zoom > minZoom)
{
cam.zoom /= 1.f + zoomSpeed / fps;
}
} if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
cam.zoom *= 1.f + zoomSpeed / fps;
}
// Clear screen
app.clear();
// Move Particals
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
draw(mousePosition::closer, sf::Mouse::getPosition(app), fps);
} else if (sf::Mouse::isButtonPressed(sf::Mouse::Right))
{
draw(mousePosition::away, sf::Mouse::getPosition(app), fps);
} else
{
draw(mousePosition::none, sf::Vector2i(), fps);
}
// Update the window
app.display();
currentTime = clock.restart().asSeconds();
fps = 1.f / currentTime;
}
return EXIT_SUCCESS;
}
@Sam-Belliveau
Copy link
Author

SICK

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment