diff --git a/compGraph/flying_object/Makefile b/compGraph/flying_object/Makefile new file mode 100644 index 0000000..2b1be85 --- /dev/null +++ b/compGraph/flying_object/Makefile @@ -0,0 +1,14 @@ +CC = g++ +SDL_ROOT = lib/i686-w64-mingw32 + +build/phys.exe: build/main.o + $(CC) -o $@ $^ -L$(SDL_ROOT)/lib -lmingw32 -lSDL2main -lSDL2 -lSDL2_ttf -mwindows +build/main.o: main.cpp + $(CC) -c -o $@ $^ -I$(SDL_ROOT)/include/SDL2 + +run: build/phys.exe + cd ./build && ./$(notdir $<); cd .. + +clear: + -rm ./build/*.o + -rm ./build/*.exe diff --git a/compGraph/flying_object/build/FreeSans.ttf b/compGraph/flying_object/build/FreeSans.ttf new file mode 100644 index 0000000..4c2f69b Binary files /dev/null and b/compGraph/flying_object/build/FreeSans.ttf differ diff --git a/compGraph/flying_object/build/SDL2.dll b/compGraph/flying_object/build/SDL2.dll new file mode 100644 index 0000000..af9f0bb Binary files /dev/null and b/compGraph/flying_object/build/SDL2.dll differ diff --git a/compGraph/flying_object/build/SDL2_ttf.dll b/compGraph/flying_object/build/SDL2_ttf.dll new file mode 100644 index 0000000..8bf6239 Binary files /dev/null and b/compGraph/flying_object/build/SDL2_ttf.dll differ diff --git a/compGraph/flying_object/build/libfreetype-6.dll b/compGraph/flying_object/build/libfreetype-6.dll new file mode 100644 index 0000000..41ac163 Binary files /dev/null and b/compGraph/flying_object/build/libfreetype-6.dll differ diff --git a/compGraph/flying_object/main.cpp b/compGraph/flying_object/main.cpp new file mode 100644 index 0000000..4c2ec60 --- /dev/null +++ b/compGraph/flying_object/main.cpp @@ -0,0 +1,317 @@ +/* +Copyright 2020 KoroLion (github.com/KoroLion) +*/ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "SDL.h" +#include "SDL_TTF.h" + +const int WIN_WIDTH = 1280; +const int WIN_HEIGHT = 800; + +const char* WIN_TITLE = "Fall Simulator"; +const int FPS = 60; + +#define PI 3.1415 + +// configurate here +#define HEIGHT 200 +#define SPEED 100 +#define ANGLE -90 +// endconf + +template +float sqr(T a) { + return a * a; +} + +std::string floatToStr(float v, int p) { + std::stringstream stream; + stream << std::fixed << std::setprecision(p) << v; + std::string s = stream.str(); + return s; +} + +void renderText(SDL_Renderer *renderer, const char *s, + float x, float y, float size) { + SDL_Texture *texture; + TTF_Font *font = TTF_OpenFont("FreeSans.ttf", size); + SDL_Surface *surface; + SDL_Color textColor = {128, 128, 128, 0}; + + surface = TTF_RenderText_Solid(font, s, textColor); + texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_Rect rect{(int)round(x), (int)round(y), surface->w, surface->h}; + SDL_RenderCopy(renderer, texture, NULL, &rect); + SDL_FreeSurface(surface); +} + + +class Object { + protected: + float x, y; + int width, height; + public: + Object(float x, float y, int width, int height): x(x), y(y), width(width), height(height) {}; + + float getX() const { return x; } + float getY() const { return y; } + void setX(float x) { this->x = x; } + void setY(float y) { this->y = y; } + + virtual void update(int fps) {}; + virtual void render(SDL_Renderer *renderer) { + SDL_SetRenderDrawColor(renderer, 64, 80, 64, 0); + + SDL_Rect r{(int)x, (int)y, width, height}; + SDL_RenderFillRect(renderer, &r); + }; +}; + + +class PhysObject: public Object { + protected: + float speedX, speedY, aX, aY; + float m = 1; + public: + PhysObject(): Object(0, 0, 1, 1), speedX(0), speedY(0), aX(0), aY(0) {} + PhysObject(float x, float y, float speed, float angle): Object(x, y, 15, 15) { + speedX = speed * cos(angle * PI / 180); + speedY = speed * sin(angle * PI / 180); + aX = 0; + aY = 9.8; + } + + float getSpeedX() const { return speedX; } + float getSpeedY() const { return speedY; } + float getWidth() const { return width; } + float getHeight() const { return height; } + + float getSpeed() { + return sqrt(sqr(speedX) + sqr(speedY)); + } + float getEKin() { + return sqr(getSpeed()) * m / 2.0; + } + float getEPot(float height) { + return m * aY * height; + } + + void setSpeedX(float speedX) { this->speedX = speedX; } + void setSpeedY(float speedY) { this->speedY = speedY; } + + void update(int fps) { + x += speedX / fps; + y -= speedY / fps; + speedX += aX / fps; + speedY -= aY / fps; // y axes is reversed + } + + void render(SDL_Renderer *renderer) { + SDL_SetRenderDrawColor(renderer, 32, 200, 32, 0); + + SDL_Rect r{(int)x, (int)y, width, height}; + SDL_RenderFillRect(renderer, &r); + } +}; + +class Simulation { + private: + int width, height, floorHeight = 10; + float t = 0; + PhysObject *physObject; + std::vector objects; + + void renderFloor(SDL_Renderer *renderer) { + SDL_SetRenderDrawColor(renderer, 128, 128, 128, 0); + + SDL_Rect r{0, height - floorHeight, width, floorHeight}; + SDL_RenderFillRect(renderer, &r); + } + + float yToHeight(float y, int objHeight) { + return height - y - floorHeight - objHeight; + } + + void renderInfo(SDL_Renderer *renderer) { + float h = yToHeight(physObject->getY(), physObject->getHeight()); + + std::string st = floatToStr(t, 2); + std::string sh = floatToStr(h, 2); + std::string sv = floatToStr(physObject->getSpeed(), 2); + + renderText(renderer, ("t = " + st + " s").c_str(), 10, 10, 16); + renderText(renderer, ("h = " + sh + " m").c_str(), 10, 30, 16); + renderText(renderer, ("V = " + sv + " m/s").c_str(), 10, 50, 16); + } + + void renderEInfoAndGraphs(SDL_Renderer *renderer, int x, int y) { + float h = yToHeight(physObject->getY(), physObject->getHeight()); + float ep = physObject->getEPot(h); + float ek = physObject->getEKin(); + float e = ep + ek; + + std::string sek = floatToStr(ek, 2); + std::string sep = floatToStr(ep, 2); + std::string se = floatToStr(e, 2); + + const int maxWidth = 300; + SDL_Rect r{x, 200, maxWidth, 30}; + + renderText(renderer, ("Ep = " + sek + " J").c_str(), x, y, 16); + SDL_SetRenderDrawColor(renderer, 64, 64, 64, 0); + r.y = y + 20; + r.w = maxWidth; + SDL_RenderFillRect(renderer, &r); + r.w = maxWidth * (ep / e); + SDL_SetRenderDrawColor(renderer, 32, 128, 32, 0); + SDL_RenderFillRect(renderer, &r); + + renderText(renderer, ("Ek = " + sek + " J").c_str(), x, y + 70, 16); + SDL_SetRenderDrawColor(renderer, 64, 64, 64, 0); + r.y = y + 90; + r.w = maxWidth; + SDL_RenderFillRect(renderer, &r); + r.w = maxWidth * (ek / e); + SDL_SetRenderDrawColor(renderer, 32, 128, 128, 0); + SDL_RenderFillRect(renderer, &r); + + renderText(renderer, ("E = " + se + " J").c_str(), x, y + 140, 16); + } + public: + Simulation(int width, int height): width(width), height(height) { + float h = HEIGHT; + physObject = new PhysObject(50, 0, SPEED, ANGLE); + physObject->setY(height - h - floorHeight - physObject->getWidth()); + objects.push_back(physObject); + } + + ~Simulation() { + std::for_each( + objects.begin(), + objects.end(), + [](Object *obj) { + delete obj; + } + ); + } + + void update(int fps) { + t += 1.0 / fps; + + std::for_each( + objects.begin(), + objects.end(), + [fps](Object* obj) { + obj->update(60); + } + ); + + if (physObject->getSpeed() > 0.1) { + float x = physObject->getX() + physObject->getWidth() / 2; + float y = physObject->getY() + physObject->getHeight() / 2; + objects.push_back(new Object(x, y, 5, 5)); + } + + float collisionY = height - floorHeight - physObject->getHeight(); + if (physObject->getY() > collisionY) { + physObject->setY(collisionY); + physObject->setSpeedY(floor(abs(physObject->getSpeedY() / 2))); + } + } + + void render(SDL_Renderer *renderer) { + std::for_each( + objects.rbegin(), + objects.rend(), + [renderer](Object* obj) { + obj->render(renderer); + } + ); + + renderFloor(renderer); + renderEInfoAndGraphs(renderer, 150, 10); + renderInfo(renderer); + } +}; + +class App { + private: + int width, height, fps; + bool isRunning; + + SDL_Window *window; + SDL_Renderer *renderer; + + Simulation *matPlot; + + void handleEvents() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + bool esc_or_quit = event.type == SDL_QUIT || + event.key.keysym.sym == SDLK_ESCAPE; + bool win_close = event.type == SDL_WINDOWEVENT && + event.window.event == SDL_WINDOWEVENT_CLOSE; + if (esc_or_quit || win_close) { + isRunning = false; + } + } + } + + void handleKeyboard() { + const Uint8 *keys = SDL_GetKeyboardState(0); + } + + public: + App(const char* title, int width, int height, int initX, int initY, + int fps): + width(width), height(height), fps(fps), isRunning(true) { + SDL_Init(SDL_INIT_VIDEO); + TTF_Init(); + + window = SDL_CreateWindow(title, initX, initY, width, height, + SDL_WINDOW_OPENGL); + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | + SDL_RENDERER_PRESENTVSYNC); + matPlot = new Simulation(width, height); + } + ~App() { + delete matPlot; + TTF_Quit(); + SDL_Quit(); + } + + void start() { + while (isRunning) { + handleEvents(); + handleKeyboard(); + + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0); + SDL_RenderClear(renderer); + + matPlot->update(fps); + matPlot->render(renderer); + + SDL_RenderPresent(renderer); + + SDL_Delay(1000 / fps); + } + } +}; + +int main(int argc, char **argv) { + std::stringstream ss; + ss << WIN_TITLE << " (H = " << HEIGHT << " m, V = " << SPEED << " m/s, angle = " << ANGLE << " deg)"; + App app(ss.str().c_str(), WIN_WIDTH, WIN_HEIGHT, 100, 100, FPS); + app.start(); + + return 0; +}