study_public/compGraph/flying_object/main.cpp

318 lines
8.6 KiB
C++
Raw Normal View History

2020-12-24 23:23:16 +03:00
/*
Copyright 2020 KoroLion (github.com/KoroLion)
*/
#include <iostream>
#include <sstream>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <vector>
#include <string>
#include <sstream>
#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 <typename T>
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<Object*> 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;
}