From 6115b7d029ddae1867a403cbf296f25623ead868 Mon Sep 17 00:00:00 2001 From: abhayMore Date: Mon, 19 Apr 2021 11:13:34 +0530 Subject: [PATCH] Added classes --- Boids.cpp | 215 +++++++++++++++++++++++++++++++++++++++++++++++++ Boids.h | 39 +++++++++ Makefile | 11 ++- main.cpp | 237 +++--------------------------------------------------- 4 files changed, 272 insertions(+), 230 deletions(-) create mode 100644 Boids.cpp create mode 100644 Boids.h diff --git a/Boids.cpp b/Boids.cpp new file mode 100644 index 0000000..2ac2b2f --- /dev/null +++ b/Boids.cpp @@ -0,0 +1,215 @@ +#include "Boids.h" +#include + +#define PI 3.14159265 + +int ReturnIntRandom(int lower, int upper) +{ + return (rand() % (upper - lower + 1)) + lower; +} + +float ReturnFloatRandom(float lower, float upper) +{ + float r3 = lower + static_cast(rand()) / (static_cast(RAND_MAX / (upper - lower))); +} + +Boids::Boids() +{ + texture.loadFromFile("arrow.png"); + sprite.setTexture(texture); + sprite.setOrigin(sf::Vector2f(texture.getSize().x/2,texture.getSize().y/2)); + + sprite.setScale(0.02f, 0.02f); + position = Vector2f(ReturnIntRandom(0, 800), ReturnIntRandom(0, 500)); + sprite.setPosition(position.ConverttoSF()); + auto pi = 4.0 * atan(1.0); + auto phi = rand() / (double)(RAND_MAX); + phi *= 2.0 * pi; + velocity = Vector2f(sin(phi), cos(phi)); + + velocity = velocity.setMag(ReturnIntRandom(2, 4)); + acceleration = Vector2f(0.0f, 0.0f); + maxForce = 1.5f; + maxSpeed = 5.0f; +} + + +void Boids::AvoidEdges(const int& HEIGHT, const int& WIDTH) +{ + if (position.x > WIDTH) + { + position.x = 0; + } + else if (position.x < 0) + { + position.x = WIDTH; + } + if (position.y > HEIGHT) + { + position.y = 0; + } + else if (position.y < 0) + { + position.y = HEIGHT; + } +} + +template +Vector2f Boids::align(Boids (&otherBoids)[S], int alignmentRadius) +{ + int perceptionRadius = alignmentRadius; + Vector2f steering = Vector2f(0.f, 0.f); + int total = 0; + + for (int i = 0; i < sizeof(otherBoids) / sizeof(otherBoids[0]); i++) + { + auto distance = position.dist(otherBoids[i].position); + if (*this != otherBoids[i] && distance < perceptionRadius) + { + steering = steering.add(otherBoids[i].velocity); + total++; + } + } + if (total > 0) + { + steering = steering.divide(total); + steering = steering.setMag(maxSpeed); + steering = steering.sub(velocity); + steering = steering.limit(maxForce); + } + return steering; +} + + +template +Vector2f Boids::separation(Boids (&otherBoids)[S], int separationRadius) +{ + int perceptionRadius = separationRadius; + Vector2f steering = Vector2f(0.f, 0.f); + + int total = 0; + for (int i = 0; i < sizeof(otherBoids) / sizeof(otherBoids[0]); i++) + { + float distance = position.dist(otherBoids[i].position); + if ((*this != otherBoids[i]) && (distance < perceptionRadius) && (distance > 0.0f)) + { + + Vector2f diff = position.sub(otherBoids[i].position); + if (distance < 1.0f) + diff = diff.mult(1 / (distance * distance)); + steering = steering.add(diff); + total++; + } + } + if (total > 0) + { + steering = steering.divide(total); + steering = steering.setMag(maxSpeed); + steering = steering.sub(velocity); + steering = steering.limit(maxForce); + } + return steering; +} + +Vector2f Boids::collision(std::vector &shape) +{ + int perceptionRadius = 50; + Vector2f steering = Vector2f(0.f, 0.f); + + int total = 0; + for (int i = 0; i < shape.size(); i++) + { + float distance = position.dist(Vector2f(shape[i].getPosition().x, shape[i].getPosition().y)); + if ((distance < perceptionRadius) && (distance > 0.0f)) + { + + Vector2f diff = position.sub(Vector2f(shape[i].getPosition().x, shape[i].getPosition().y)); + if (distance < 1.0f) + diff = diff.mult(1 / (distance * distance)); + steering = steering.add(diff); + total++; + } + } + if (total > 0) + { + steering = steering.divide(total); + steering = steering.setMag(maxSpeed); + steering = steering.sub(velocity); + steering = steering.limit(maxForce); + } + return steering; +} + +template +Vector2f Boids::cohesion(Boids (&otherBoids)[S], int cohesionRadius) +{ + int perceptionRadius = cohesionRadius; + Vector2f steering = Vector2f(0.f, 0.f); + int total = 0; + for (int i = 0; i < sizeof(otherBoids) / sizeof(otherBoids[0]); i++) + { + auto distance = position.dist(otherBoids[i].position); + if (*this != otherBoids[i] && distance < perceptionRadius) + { + steering = steering.add(otherBoids[i].position); + total++; + } + } + if (total > 0) + { + steering = steering.divide(total); + steering = steering.sub(position); + steering = steering.setMag(maxSpeed); + steering = steering.sub(velocity); + steering = steering.limit(maxForce); + } + return steering; +} + +template < std::size_t S> +void Boids::flock(Boids (&otherBoids)[S], std::vector &shape, int alignmentRadius, int cohesionRadius, int separationRadius) +{ + Vector2f alignment = align(otherBoids, alignmentRadius); + Vector2f cohes = cohesion(otherBoids, cohesionRadius); + Vector2f sep = separation(otherBoids, separationRadius); + Vector2f col = collision(shape); + + acceleration = acceleration.add(alignment); + acceleration = acceleration.add(cohes); + acceleration = acceleration.add(sep); + acceleration = acceleration.add(col); +} + +void Boids::update() +{ + position = position.add(velocity); + velocity = velocity.add(acceleration); + velocity = velocity.limit(maxSpeed); + acceleration = acceleration.mult(0); + + float angle = atan2(velocity.y, velocity.x); + angle = angle * (180 / PI) - 90; + angle = (velocity.x < 0.0f || velocity.y < 0.0f) ? angle - 180 : angle + 180; + + sprite.setRotation(angle); + sprite.setPosition(position.ConverttoSF()); +} + +void Boids::draw(sf::RenderWindow &window) +{ + window.draw(sprite); +} + + + +bool operator==(const Boids &a, const Boids &b) +{ +return (a.position.x == b.position.x) && (a.position.y == b.position.y) && (a.velocity.x == b.velocity.x) && (a.velocity.y == b.velocity.y) && (a.acceleration.x == b.acceleration.x) && (a.acceleration.y == b.acceleration.y); +} + +bool operator!=(const Boids &a, const Boids &b) +{ +return !(a == b); +} + +template void Boids::flock(Boids (&otherBoids)[200], std::vector &shape, int alignmentRadius, int cohesionRadius, int separationRadius); diff --git a/Boids.h b/Boids.h new file mode 100644 index 0000000..70e8a2f --- /dev/null +++ b/Boids.h @@ -0,0 +1,39 @@ +#ifndef BOIDS_H +#define BOIDS_H +#include "Vector2.h" + +class Boids +{ + Vector2f position; + Vector2f velocity; + Vector2f acceleration; + float maxSpeed, maxForce; + sf::Texture texture; + sf::Sprite sprite; + +public: + Boids(); + void AvoidEdges(const int& HEIGHT, const int& WIDTH); + + template < std::size_t S> + Vector2f align(Boids (&otherBoids)[S], int alignmentRadius); + + template < std::size_t S> + Vector2f separation(Boids (&otherBoids)[S], int separationRadius); + + template < std::size_t S> + Vector2f cohesion(Boids (&otherBoids)[S], int cohesionRadius); + + Vector2f collision(std::vector& shape); + + template + void flock(Boids (&otherBoids)[S], std::vector &shape, int alignmentRadius, int aohesionRadius, int separationRadius); + + void update(); + void draw(sf::RenderWindow& window); + + friend bool operator==(const Boids &a, const Boids &b); + friend bool operator!=(const Boids &a, const Boids &b); +}; + +#endif //BOIDS_H diff --git a/Makefile b/Makefile index 4eaf59f..7bc6d54 100755 --- a/Makefile +++ b/Makefile @@ -1,14 +1,17 @@ all: sfml-app ./sfml-app -sfml-app: $(F2) Vector2.o - g++ -std=c++17 $(F2) Vector2.o -o sfml-app -ltgui -lsfml-graphics -lsfml-window -lsfml-audio -lsfml-system +sfml-app: $(F2) Vector2.o Boids.o + g++ -std=c++17 $(F2) Vector2.o Boids.o -o sfml-app -ltgui -lsfml-graphics -lsfml-window -lsfml-audio -lsfml-system Vector2.o : Vector2.cpp Vector2.h; g++ -std=c++17 -c Vector2.cpp -$(F2) : Vector2.h $(F1) - g++ -c $(F1) +Boids.o : Boids.cpp Boids.h + g++ -std=c++17 -c Boids.cpp + +$(F2) : Vector2.h $(F1) Boids.h + g++ -std=c++17 -c $(F1) clean: rm -rf *o sfml-app diff --git a/main.cpp b/main.cpp index 1fc1902..02a3c07 100644 --- a/main.cpp +++ b/main.cpp @@ -1,229 +1,11 @@ #include "SFML/Graphics.hpp" #include "TGUI/TGUI.hpp" -#include "Vector2.h" +#include "Boids.h" #include -#include -using namespace std; + #define WIDTH 900 #define HEIGHT 600 -#define PI 3.14159265 - -int ReturnIntRandom(int lower, int upper) -{ - return (rand() % (upper - lower + 1)) + lower; -} - -float ReturnFloatRandom(float lower, float upper) -{ - float r3 = lower + static_cast(rand()) / (static_cast(RAND_MAX / (upper - lower))); -} - -class Boid -{ - Vector2f position; - Vector2f velocity; - Vector2f acceleration; - float maxSpeed, maxForce; - sf::Texture texture; - sf::Sprite sprite; -public: - Boid() - { - texture.loadFromFile("arrow.png"); - sprite.setTexture(texture); - sprite.setOrigin(sf::Vector2f(290.0f, 365.0f)); - - sprite.setScale(0.02f, 0.02f); - position = Vector2f(ReturnIntRandom(0, WIDTH), ReturnIntRandom(0, HEIGHT)); - sprite.setPosition(position.ConverttoSF()); - auto pi = 4.0 * atan(1.0); - auto phi = rand() / (double)(RAND_MAX); - phi *= 2.0 * pi; - velocity = Vector2f(sin(phi), cos(phi)); - - velocity = velocity.setMag(ReturnIntRandom(2, 4)); - acceleration = Vector2f(0.0f, 0.0f); - maxForce = 1.5f; - maxSpeed = 5.0f; - } - - void AvoidEdges() - { - if (position.x > WIDTH) - { - position.x = 0; - } - else if (position.x < 0) - { - position.x = WIDTH; - } - if (position.y > HEIGHT) - { - position.y = 0; - } - else if (position.y < 0) - { - position.y = HEIGHT; - } - } - - template - Vector2f align(Boid (&boids)[S], int AlignmentRadius) - { - int perceptionRadius = AlignmentRadius; - Vector2f steering = Vector2f(0.f, 0.f); - int total = 0; - - for (int i = 0; i < sizeof(boids) / sizeof(boids[0]); i++) - { - auto distance = position.dist(boids[i].position); - if (*this != boids[i] && distance < perceptionRadius) - { - steering = steering.add(boids[i].velocity); - total++; - } - } - if (total > 0) - { - steering = steering.divide(total); - steering = steering.setMag(maxSpeed); - steering = steering.sub(velocity); - steering = steering.limit(maxForce); - } - return steering; - } - - template - Vector2f separation(Boid (&boids)[S], int SeparationRadius) - { - int perceptionRadius = SeparationRadius; - Vector2f steering = Vector2f(0.f, 0.f); - - int total = 0; - for (int i = 0; i < sizeof(boids) / sizeof(boids[0]); i++) - { - float distance = position.dist(boids[i].position); - if ((*this != boids[i]) && (distance < perceptionRadius) && (distance > 0.0f)) - { - - Vector2f diff = position.sub(boids[i].position); - if (distance < 1.0f) - diff = diff.mult(1 / (distance * distance)); - steering = steering.add(diff); - total++; - } - } - if (total > 0) - { - steering = steering.divide(total); - steering = steering.setMag(maxSpeed); - steering = steering.sub(velocity); - steering = steering.limit(maxForce); - } - return steering; - } - Vector2f collision(std::vector &shape) - { - int perceptionRadius = 50; - Vector2f steering = Vector2f(0.f, 0.f); - - int total = 0; - for (int i = 0; i < shape.size(); i++) - { - float distance = position.dist(Vector2f(shape[i].getPosition().x, shape[i].getPosition().y)); - if ((distance < perceptionRadius) && (distance > 0.0f)) - { - - Vector2f diff = position.sub(Vector2f(shape[i].getPosition().x, shape[i].getPosition().y)); - if (distance < 1.0f) - diff = diff.mult(1 / (distance * distance)); - steering = steering.add(diff); - total++; - } - } - if (total > 0) - { - steering = steering.divide(total); - steering = steering.setMag(maxSpeed); - steering = steering.sub(velocity); - steering = steering.limit(maxForce); - } - return steering; - } - - template - Vector2f cohesion(Boid (&boids)[S], int CohesionRadius) - { - int perceptionRadius = CohesionRadius; - Vector2f steering = Vector2f(0.f, 0.f); - int total = 0; - for (int i = 0; i < sizeof(boids) / sizeof(boids[0]); i++) - { - auto distance = position.dist(boids[i].position); - if (*this != boids[i] && distance < perceptionRadius) - { - steering = steering.add(boids[i].position); - total++; - } - } - if (total > 0) - { - steering = steering.divide(total); - steering = steering.sub(position); - steering = steering.setMag(maxSpeed); - steering = steering.sub(velocity); - steering = steering.limit(maxForce); - } - return steering; - } - - template - void flock(Boid (&boids)[S], std::vector &shape, int AlignmentRadius, int CohesionRadius, int SeparationRadius) - { - Vector2f alignment = align(boids, AlignmentRadius); - Vector2f cohes = cohesion(boids, CohesionRadius); - Vector2f sep = separation(boids, SeparationRadius); - Vector2f col = collision(shape); - - acceleration = acceleration.add(alignment); - acceleration = acceleration.add(cohes); - acceleration = acceleration.add(sep); - acceleration = acceleration.add(col); - } - - void update() - { - position = position.add(velocity); - velocity = velocity.add(acceleration); - velocity = velocity.limit(maxSpeed); - acceleration = acceleration.mult(0); - - float angle = atan2(velocity.y, velocity.x); - angle = angle * (180 / PI) - 90; - angle = (velocity.x < 0.0f || velocity.y < 0.0f) ? angle - 180 : angle + 180; - - sprite.setRotation(angle); - sprite.setPosition(position.ConverttoSF()); - } - void draw(sf::RenderWindow &window) - { - window.draw(sprite); - } - - friend bool operator==(const Boid &a, const Boid &b); - friend bool operator!=(const Boid &a, const Boid &b); -}; - -bool operator==(const Boid &a, const Boid &b) -{ - return (a.position.x == b.position.x) && (a.position.y == b.position.y) && (a.velocity.x == b.velocity.x) && (a.velocity.y == b.velocity.y) && (a.acceleration.x == b.acceleration.x) && (a.acceleration.y == b.acceleration.y); -} - -bool operator!=(const Boid &a, const Boid &b) -{ - return !(a == b); -} int main() { @@ -232,6 +14,7 @@ int main() window.setFramerateLimit(30); tgui::Gui gui{window}; + auto alignmentSlider = tgui::Slider::create(); alignmentSlider->setPosition(20, 560); alignmentSlider->setSize(200, 20); @@ -261,8 +44,9 @@ int main() alignmentText->setPosition(alignmentSlider->getPosition().x + alignmentSlider->getSize().x + 10, alignmentSlider->getPosition().y); alignmentText->setText(std::to_string((int)alignmentSlider->getValue())); alignmentText->setTextSize(20); - auto a = alignmentText->getSharedRenderer(); - a->setTextColor(tgui::Color(255, 255, 255)); + + auto textColor = alignmentText->getSharedRenderer(); + textColor->setTextColor(tgui::Color(255, 255, 255)); gui.add(alignmentText); auto cohesionText = tgui::Label::create(); @@ -270,7 +54,6 @@ int main() cohesionText->setPosition(cohesionSlider->getPosition().x + cohesionSlider->getSize().x + 10, cohesionSlider->getPosition().y); cohesionText->setText(std::to_string((int)cohesionSlider->getValue())); cohesionText->setTextSize(20); - gui.add(cohesionText); auto separationText = tgui::Label::create(); @@ -278,18 +61,18 @@ int main() separationText->setPosition(separationSlider->getPosition().x + separationSlider->getSize().x + 10, separationSlider->getPosition().y); separationText->setText(std::to_string((int)separationSlider->getValue())); separationText->setTextSize(20); - gui.add(separationText); auto resetButton = tgui::Button::create(); resetButton->setPosition(window.getSize().x - 80, window.getSize().y - 45); resetButton->setSize(55, 25); resetButton->setText("Reset"); + auto resetButtonRenderer = resetButton->getSharedRenderer(); resetButtonRenderer->setTextColor(tgui::Color(255, 255, 255)); resetButtonRenderer->setBackgroundColor(tgui::Color(0, 0, 0, 0)); gui.add(resetButton); - Boid boids[200]; + bool alignmentSliderMoved = false; bool cohesionSliderMoved = false; @@ -297,6 +80,8 @@ int main() bool buttonPressed = false; bool mouseDraw = false; + Boids boids[200]; + std::vector vec; while (window.isOpen()) { @@ -407,7 +192,7 @@ int main() for (auto &i : boids) { i.flock(boids, vec, alignmentSlider->getValue(), cohesionSlider->getValue(), separationSlider->getValue()); - i.AvoidEdges(); + i.AvoidEdges(HEIGHT, WIDTH); i.update(); i.draw(window); }