diff --git a/templates/_folder_Lectures/Lecture 15 - handout/main.cpp b/templates/_folder_Lectures/Lecture 15 - handout/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..adfbb4e37a18ceb251fc509c0a87a4ada6c18e62 --- /dev/null +++ b/templates/_folder_Lectures/Lecture 15 - handout/main.cpp @@ -0,0 +1,132 @@ +#include <vector> +#include <random> +#include "AnimationWindow.h" + +struct Point2D { + double x = 0; + double y = 0; +}; + +struct Direction2D { + double x = 0; + double y = 0; +}; + +constexpr double gravity = 0.1; +constexpr double explosionPower = 2.0; + +struct Rocket { + std::vector<Point2D> particleLocations; + std::vector<Direction2D> particleDirections; + bool hasExploded = false; + bool hasEnded = false; + int fadeTimeRemaining = 1000; + TDT4102::Color colour; + + Rocket() {} + Rocket(int particleCount, int fadeTime, Point2D start, Direction2D launchDirection, TDT4102::Color colour) : + fadeTimeRemaining(fadeTime), + colour(colour), + particleLocations(particleCount, start), + particleDirections(particleCount, launchDirection) {} + + void update() { + if(hasExploded && fadeTimeRemaining == 0) { + hasEnded = true; + } else if(hasExploded) { + fadeTimeRemaining--; + } else if(particleDirections.at(0).y > 0 && !hasExploded) { + hasExploded = true; + std::random_device device; + std::default_random_engine engine(device()); + std::uniform_real_distribution directionDist(0.0, M_PI * 2.0); + std::uniform_real_distribution powerDist(0.0, explosionPower * explosionPower); + + for(unsigned int i = 0; i < particleLocations.size(); i++) { + // Choose a random direction and velocity for each particle in the rocket + double angle = directionDist(engine); + double power = powerDist(engine); + // This results in a more even spread of particles + power = sqrt(power); + + // Using sine and cosine gives us a vector of length 1, + // which we multiply by the power + particleDirections.at(i).x = cos(angle) * power; + constexpr int bonusVerticalForce = 4; + particleDirections.at(i).y = sin(angle) * power - bonusVerticalForce; + } + } + + if(!hasEnded) { + for(unsigned int i = 0; i < particleDirections.size(); i++) { + particleDirections.at(i).y += gravity; + } + for(unsigned int i = 0; i < particleLocations.size(); i++) { + particleLocations.at(i).x += particleDirections.at(i).x; + particleLocations.at(i).y += particleDirections.at(i).y; + } + if(hasExploded) { + if(colour.redChannel > 1) { colour.redChannel-=2; } + if(colour.greenChannel > 1) { colour.greenChannel-=2; } + if(colour.blueChannel > 1) { colour.blueChannel-=2; } + if(colour.redChannel < 2 && colour.greenChannel < 2 && colour.blueChannel < 2) { + hasEnded = true; + } + } + } + } + + bool isComplete() { + return hasEnded; + } + + void draw(TDT4102::AnimationWindow &window) { + for(unsigned int i = 0; i < particleLocations.size(); i++) { + Point2D location = particleLocations.at(i); + constexpr int particleWidthPixels = 2; + constexpr int particleHeightPixels = 2; + window.draw_rectangle({int(location.x), int(location.y)}, particleWidthPixels, particleHeightPixels, colour); + } + } +}; + +int main() { + constexpr int rocketCount = 300; + constexpr int particleCount = 500; + constexpr int defaultFadeTime = 250; + constexpr double minVerticalSpeed = 7.0; + constexpr double maxVerticalSpeed = 12.0; + + TDT4102::AnimationWindow window; + std::vector<Rocket> rockets; + rockets.resize(rocketCount); + + std::random_device device; + std::default_random_engine engine(device()); + std::uniform_int_distribution xDist(0, window.width()); + std::uniform_real_distribution speedDist(-minVerticalSpeed, -maxVerticalSpeed); + std::uniform_int_distribution colourChannelDist(0, 255); + + for(unsigned int i = 0; i < rockets.size(); i++) { + TDT4102::Color randomColour(colourChannelDist(engine), colourChannelDist(engine), colourChannelDist(engine)); + rockets.at(i) = Rocket(particleCount, defaultFadeTime, {(double)xDist(engine), (double) window.height()}, {0.0, speedDist(engine)}, randomColour); + } + while(!window.should_close()) { + window.draw_rectangle({0, 0}, window.width(), window.height(), TDT4102::Color::black); + for(unsigned int i = 0; i < rockets.size(); i++) { + if(!rockets.at(i).isComplete()) { + rockets.at(i).update(); + rockets.at(i).draw(window); + } else { + TDT4102::Color randomColour(colourChannelDist(engine), colourChannelDist(engine), colourChannelDist(engine)); + std::uniform_int_distribution xDist(0, window.width()); + rockets.at(i) = Rocket(particleCount, defaultFadeTime, {(double)xDist(engine), (double) window.height()}, {0.0, speedDist(engine)}, randomColour); + } + } + constexpr int estimatedTextWidth = 1000; + constexpr int estimatedTextHeight = 200; + constexpr int fontSize = 96; + window.draw_text({window.width() / 2 - estimatedTextWidth / 2, window.height() / 2 - estimatedTextHeight / 2}, "Good luck on the exam!", TDT4102::Color::white, fontSize, TDT4102::Font::arial_bold); + window.next_frame(); + } +}