diff --git a/game/CMakeLists.txt b/game/CMakeLists.txt index 64fc26a..05fc7d1 100644 --- a/game/CMakeLists.txt +++ b/game/CMakeLists.txt @@ -8,10 +8,20 @@ set(GAME_SRC main.cpp opengl.cpp glclasses.cpp - config.cpp - simulation.cpp renderer.cpp - ) + game_window.cpp + triangle_window.cpp + + util.cpp + game.cpp + state/object.cpp + state/state.cpp + state/player.cpp + state/planet.cpp + state/missile.cpp + state/commands.cpp + state/state.cpp +) set(GAME_HEADERS opengl.h @@ -20,7 +30,7 @@ set(GAME_HEADERS config.h simulation.h renderer.h - ) +) include_directories(${CMAKE_CURRENT_BINARY_DIR}) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/game/game.cpp b/game/game.cpp new file mode 100644 index 0000000..36ffc64 --- /dev/null +++ b/game/game.cpp @@ -0,0 +1,67 @@ +#include "game.hpp" + +#include "state/commands.hpp" + +#include "util.hpp" + +#include + +Game::Game() +{ + // advance simulation with 100 Hz + m_time_step = 1.0 / 100.0; + m_time_for_next_step = 0.0; + + m_state = new game::State(); + m_state->init(); + + m_state->addPlayer(0); + m_state->addPlayer(1); + m_state->addPlayer(2); + m_state->addPlayer(3); + //m_state->addPlayer(2); +} + +bool Game::cycle(float dt) +{ + static float acc = 0.0; + acc += dt; + + float spawnInterval = 0.1; + while(acc > spawnInterval) { + acc -= spawnInterval; + + float a = 2.0 * M_PI * util::randf_0_1(); + float speed = 0.002; + m_state->players[0]->addCommand(new game::ShootCommand(a, speed)); + } + +#if 1 + if (dt >= 10.0) { + //std::cout<<"time to big: " << dt << std::endl; + dt = m_time_step; + } + + //std::cout<<"adding dt: " << dt << std::endl; + m_time_for_next_step += dt; + + int steps = 0; + while(m_time_for_next_step >= m_time_step) { + //std::cout<<"time now: " << m_time_for_next_step << std::endl; + m_time_for_next_step -= m_time_step; + + m_state->advance(m_time_step); + steps++; + } + + //std::cout << m_time_for_next_step << " s remaining time, " << steps << " steps taken." << std::endl; + + return true; +#else + (void) dt; + + m_state->advance(dt); + + return true; +#endif +} diff --git a/game/game.hpp b/game/game.hpp new file mode 100644 index 0000000..9c9512a --- /dev/null +++ b/game/game.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "state/state.hpp" + +class Game { +public: + Game(); + + // main method of the game. run this regulary + // return false if want to exit. + bool cycle(float dt); + + // for rendering + const game::State *state() const { return m_state; } + +private: + game::State *m_state; + + float m_time_for_next_step; + float m_time_step; +}; diff --git a/game/game_window.cpp b/game/game_window.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/game_window.h b/game/game_window.h new file mode 100644 index 0000000..a5659a5 --- /dev/null +++ b/game/game_window.h @@ -0,0 +1,89 @@ +#pragma once + +#include "opengl.h" +#include "renderer.h" + +#include "game.hpp" + +#include "state/object.hpp" +#include "state/missile.hpp" +#include "state/player.hpp" +#include "state/planet.hpp" +#include "state/ship.hpp" + +class GameWindow : public endofthejedi::GLWindow { +private: +protected: + void init() override { + glClearColor(0.5f, 0.6f, 0.7f, 1.0f); + resize(); + + glEnable(GL_DEPTH_TEST); + } + + void render(double time) override { + //static bool once = false; + //if (!once) { + // once = true; + // for (int i=0; i<1000; i++) { + // m_game.cycle(time); + // } + //} + + if (!m_game.cycle(static_cast(time/1000000000.0))) { + std::cout<<"stopping the game..." << std::endl; + stop(); + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + for (const game::Planet *planet : m_game.state()->planets) { + drawPlanet(planet->position, planet->radius); + } + + for (const game::Ship *ship : m_game.state()->ships) { + drawShip(ship->position); + } + + for (const game::Player *player : m_game.state()->players) { + for (const game::Missile *missile : player->missiles) { + drawMissile(missile->position); + } + } + } + + void resize() override { glViewport(0, 0, getwidth(), getheight()); } + + void drawShip(const glm::vec2 &pos) + { + //std::cout<<"draw ship @ " << pos.x << ", " << pos.y << std::endl; + glm::vec3 color = glm::vec3(0.2, 1.0, 0.3); + + float radius = m_game.state()->shipRadius(); + + m_renderer.drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 12); + } + + void drawPlanet(const glm::vec2 &pos, float radius) + { + glm::vec3 color = glm::vec3(0.7, 0.1, 0.2); + + //std::cout<<"draw planet @ " << pos.x << ", " << pos.y << std::endl; + m_renderer.drawCircle(pos.x, pos.y, radius, color.x, color.y, color.z, 32); + } + + void drawMissile(const glm::vec2 &pos) + { + glm::vec3 color = glm::vec3(1.0, 1.0, 0.3); + m_renderer.drawCircle(pos.x, pos.y, 0.005, color.x, color.y, color.z, 5); + } + +public: + GameWindow(unsigned int width, unsigned int height) + : endofthejedi::GLWindow(width, height) {} + +private: + Game m_game; + endofthejedi::Renderer m_renderer; +}; + diff --git a/game/main.cpp b/game/main.cpp index 5a7aead..a63380e 100644 --- a/game/main.cpp +++ b/game/main.cpp @@ -1,36 +1,11 @@ #include "opengl.h" #include -class MainWindow : public endofthejedi::GLWindow { -private: -protected: - void init() override { - glClearColor(0.5f, 0.6f, 0.7f, 1.0f); - resize(); - - glEnable(GL_DEPTH_TEST); - } - void render(double time) override { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glBegin(GL_TRIANGLES); - glColor3f(1.0f, 0.0f, 0.0f); - glVertex3f(0.0f, -1.0f, 0.0f); - glColor3f(0.0f, 1.0f, 0.0f); - glVertex3f(-1.0f, 1.0f, 0.0f); - glColor3f(0.0f, 0.0f, 1.0f); - glVertex3f(1.0f, 1.0f, 0.0f); - glEnd(); - } - void resize() override { glViewport(0, 0, getwidth(), getheight()); } - -public: - MainWindow(unsigned int width, unsigned int height) - : endofthejedi::GLWindow(width, height) {} -}; +//#include "triangle_window.h" +#include "game_window.h" int main(int argc, const char *argv[]) { - MainWindow window(500, 500); + GameWindow window(500, 500); window.set_maxfps(60.0); window.loop(); window.stop(); diff --git a/game/renderer.cpp b/game/renderer.cpp index bed3c3d..93b4dc0 100644 --- a/game/renderer.cpp +++ b/game/renderer.cpp @@ -7,12 +7,12 @@ endofthejedi::Renderer::Renderer() { endofthejedi::Renderer::~Renderer() {} void endofthejedi::Renderer::drawCircle(float x, float y, float radius, float r, - float g, float b) { + float g, float b, int numSides) { glBegin(GL_TRIANGLE_FAN); glVertex2f(x, y); // center of circle - for (int i = 0; i <= 64; i++) { + for (int i = 0; i <= numSides; i++) { glColor3f(r,g,b); - glVertex2f(x + (radius * cos(i * 2 * M_PI / 64)), y + (radius * sin(i * 2 * M_PI / 64))); + glVertex2f(x + (radius * cos(i * 2 * M_PI / numSides)), y + (radius * sin(i * 2 * M_PI / numSides))); } glEnd(); } diff --git a/game/renderer.h b/game/renderer.h index d5b4f63..53a4058 100644 --- a/game/renderer.h +++ b/game/renderer.h @@ -19,7 +19,7 @@ class Renderer { Renderer(); ~Renderer(); void drawCircle(float x, float y, float radius, float r, - float g, float b); + float g, float b, int numSides=12); }; } diff --git a/game/state/commands.cpp b/game/state/commands.cpp new file mode 100644 index 0000000..f656dc6 --- /dev/null +++ b/game/state/commands.cpp @@ -0,0 +1,22 @@ +#include "commands.hpp" + +namespace game { + void ShootCommand::apply(Player *player, State *state) const + { + (void) state; + // TODO spawn missile if alive and enough energy + //std::cout<<"apply command " << name() << std::endl; + + player->energy -= m_speed; + player->missiles.push_back(new Missile(player->id, player->ship->position, m_angle, m_speed)); + } + + bool ShootCommand::allowed(const Player *player, const State *state) const + { + (void) state; + + // TODO + return player->alive && player->energy >= m_speed; + //return player->alive; + } +} diff --git a/game/state/commands.hpp b/game/state/commands.hpp new file mode 100644 index 0000000..5c8ff97 --- /dev/null +++ b/game/state/commands.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include "state.hpp" +#include "player.hpp" +#include "ship.hpp" +#include "planet.hpp" +#include "missile.hpp" + +#include + +namespace game { + class Command { + public: + Command() + { + } + + virtual ~Command() + { + } + + virtual bool allowed(const Player *player, const State *state) const + { + (void) player; + (void) state; + + return true; + } + + virtual void apply(Player *player, State *state) const + { + (void) state; + (void) player; + + std::cout<<"Command '" << name() << "' not yet implemented!" << std::endl; + } + + virtual std::string name() const { return ""; } + }; + + class ShootCommand : public Command { + public: + ShootCommand(float angle, float speed) : m_angle(angle), m_speed(speed) + { + } + + std::string name() const { return ""; } + + void apply( Player *player, State *state) const; + bool allowed(const Player *player, const State *state) const; + + private: + float m_angle; + float m_speed; + }; +} diff --git a/game/state/explosion.cpp b/game/state/explosion.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/state/explosion.hpp b/game/state/explosion.hpp new file mode 100644 index 0000000..2cf92ef --- /dev/null +++ b/game/state/explosion.hpp @@ -0,0 +1,17 @@ +#pragma once + +#if 0 +class Explosion { +public: + enum class Kind { + Normal, + MissileWithShip + }; + + glm::vec2 position; + + Explosion(Kind kind); + +public: +}; +#endif diff --git a/game/state/missile.cpp b/game/state/missile.cpp new file mode 100644 index 0000000..b060ca3 --- /dev/null +++ b/game/state/missile.cpp @@ -0,0 +1,82 @@ +#include "missile.hpp" + +#include + +#include "state.hpp" +#include "player.hpp" + +#include + +namespace game { + Missile::Missile(int playerId, const glm::vec2 &pos, float angle, float speed) + : playerId(playerId) + , position(pos) + { + velocity = speed * glm::vec2(std::sin(angle), std::cos(angle)); + + //std::cout << "spawned missile for player " << playerId << " @ (" + // << pos.x << ", " << pos.y << ") speed = " << speed << std::endl; + } + + Missile::~Missile() + { + //std::cout<<"destroyed missile" << std::endl; + } + + Missile::Event Missile::advance(const game::State *state, float dt) + { + glm::vec2 gravityForce = glm::vec2(0.0, 0.0); + + for (const Player *other : state->players) { + if (other->ship != nullptr && other->id != playerId) { + glm::vec2 diff = other->ship->position - position; + float dist = glm::length(diff); + if (dist <= other->ship->radius) { + // TODO: collect all hits and return the first one only + // TODO: find exact hit position! + return Missile::Event(position, playerId, other->id); + } + } + } + + // get forces + for (const Planet *planet : state->planets) { + glm::vec2 diff = planet->position - position; + float dist = glm::length(diff); + if (dist <= planet->radius) { + // TODO: collect all hits and return the first one only + // TODO: find exact hit position! + return Missile::Event(position, Missile::HitObject::HitPlanet); + } + + dist *= 20.0; + if (dist > 0.001) { + float G = 0.1; + gravityForce += G * diff / (1.0f + dist*dist); + } + } + + // simple (and bad) euler integration. + position += 0.5f * gravityForce*dt*dt + velocity*dt; + velocity += gravityForce * dt; + + //const float thr = 0.01; + //float s = glm::length(velocity); + //if (s > thr) { + // velocity = glm::normalize(velocity) * thr; + //} + + glm::vec2 nextPos = position + velocity; + + // TODO: collision checks + position = nextPos; + + // check if distance to center of the universe is getting too big + float distToCenter = glm::length(position); + if (distToCenter > state->maxMissileDistance()) { + return Missile::Event(position, Missile::HitObject::LeftUniverse); + } + + return Missile::Event(position); + } +} diff --git a/game/state/missile.hpp b/game/state/missile.hpp new file mode 100644 index 0000000..b1f0f96 --- /dev/null +++ b/game/state/missile.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include +#include + +#include "state.hpp" + +#include "ship.hpp" +#include "planet.hpp" + +namespace game { + class State; + + // missile belongs to a player and optionally fills a trace behind it. + // trace then belongs to the player. + class Missile { + public: + enum class HitObject { + Nothing, + HitPlayer, + HitPlanet, + // HitMissile, + LeftUniverse + }; + + // missile advances to pos. if hit != Nothing, it hits something and + // stops existing afterwards. + class Event { + public: + Event(const glm::vec2 &pos) : Event(pos, HitObject::Nothing) + { + } + + Event(const glm::vec2 &pos, HitObject hit) + : hit(hit), pos(pos) + { + } + + Event(const glm::vec2 &pos, int playerIdKiller, int playerIdVictim) + : Event(pos, HitObject::HitPlayer) + { + this->playerIdKiller = playerIdKiller; + this->playerIdVictim = playerIdVictim; + } + + HitObject hit; + glm::vec2 pos; + + int playerIdKiller; + int playerIdVictim; + }; + + // XXX + int playerId; // owner won't be hit by own missiles + glm::vec2 position; + glm::vec2 velocity; + //Trace *trace; + + Missile(int playerId, const glm::vec2 &pos, float angle, float speed); + + ~Missile(); + + // try to advance. if something will be hit, return the first hit in + // time. + Missile::Event advance(const game::State *state, float dt); + }; +} + diff --git a/game/state/object.cpp b/game/state/object.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/state/object.hpp b/game/state/object.hpp new file mode 100644 index 0000000..2909acc --- /dev/null +++ b/game/state/object.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +class Object { +public: + Object(const glm::vec2 &pos, float r) : position(pos), radius(r) + { + } + + const glm::vec2 position; + const float radius; +}; + diff --git a/game/state/planet.cpp b/game/state/planet.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/state/planet.hpp b/game/state/planet.hpp new file mode 100644 index 0000000..0407683 --- /dev/null +++ b/game/state/planet.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "object.hpp" + +namespace game { + class Planet : public Object { + public: + Planet(const glm::vec2 &pos, float r) : Object(pos, r) + { + } + }; +} diff --git a/game/state/player.cpp b/game/state/player.cpp new file mode 100644 index 0000000..255c844 --- /dev/null +++ b/game/state/player.cpp @@ -0,0 +1,33 @@ +#include "player.hpp" + +#include + +#include "commands.hpp" + +#include "ship.hpp" + +namespace game { + void Player::popCommand() + { + //std::cout<<"popCommand()" << std::endl; + + Command *cmd = commands.front(); + commands.erase(commands.begin()); + delete(cmd); + } + + Command *Player::peekCommand() + { + return commands.front(); + } + + bool Player::hasCommandInQueue() + { + return !commands.empty(); + } + + void Player::addCommand(Command *cmd) + { + commands.push_back(cmd); + } +} diff --git a/game/state/player.hpp b/game/state/player.hpp new file mode 100644 index 0000000..199a411 --- /dev/null +++ b/game/state/player.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include +#include + +#include +#include + +namespace game { + class Ship; + class Command; + class Missile; + + class Player { + public: + int id; + bool alive; + float energy; + float deadTimeCounter; + Ship *ship; + std::vector missiles; + + Player(int id) : id(id), alive(true), energy(0.0), ship(nullptr) + { + } + + void addCommand(Command *cmd); + bool hasCommandInQueue(); + + Command *peekCommand(); + void popCommand(); + + private: + std::deque commands; + }; +} diff --git a/game/state/ship.cpp b/game/state/ship.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/state/ship.hpp b/game/state/ship.hpp new file mode 100644 index 0000000..bffb754 --- /dev/null +++ b/game/state/ship.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include "object.hpp" + +namespace game { + class Ship : public Object { + public: + Ship(const glm::vec2 &pos, float r) : Object(pos, r) + { + } + }; +} diff --git a/game/state/state.cpp b/game/state/state.cpp new file mode 100644 index 0000000..462f62a --- /dev/null +++ b/game/state/state.cpp @@ -0,0 +1,262 @@ +#include "state.hpp" + +#include + +#include +#include +#include + +#include "object.hpp" +#include "missile.hpp" +#include "player.hpp" +#include "planet.hpp" +#include "ship.hpp" +#include "commands.hpp" + +#include "util.hpp" + +namespace game { + void State::init() + { + m_shipRadius = 0.05; + m_maxMissileDistance = 2.0; + m_playerRespawnTime = 2.0; + m_defaultEnergy = 10.0; + + bool planetsOnCircle = false; + + int numPlanets = 10; + for (int i=0; i(numPlanets); + t *= 2.0*M_PI; + + // distribute but not in the center + int tries = 0; + glm::vec2 pos; + do { + float cr = 0.7; + if (planetsOnCircle) { + pos = cr * glm::vec2(std::sin(t), std::cos(t)); + } else { + pos = cr * util::randv2_m1_1(); + } + } while(glm::length(pos) < 0.2 && tries++ < 1000); + + planets.push_back(new Planet(pos, 0.03 + 0.07*util::randf_0_1())); + } + } + + bool State::spawnShipForPlayer(Player *player) + { + glm::vec2 spawnPos; + if (!findFreePositionWithRadius(5.0 * m_shipRadius, spawnPos)) { + return false; + } + + player->ship = new Ship(spawnPos, m_shipRadius); + ships.push_back(player->ship); + + player->energy = m_defaultEnergy; + + return true; + } + + void State::addPlayer(int playerId) + { + Player *player = new Player(playerId); + players.push_back(player); + } + + void State::playerLeft(int playerId) + { + (void) playerId; + } + + void State::advancePlayerShipSpawns(float dt) + { + (void) dt; + + for (Player *player : players) { + if (!player->alive) { + player->deadTimeCounter += dt; + if (player->deadTimeCounter >= m_playerRespawnTime) { + player->deadTimeCounter = 0; + player->alive = true; + std::cout<<"respawning player " << player->id << " now!" << std::endl; + } + } + + if (player->alive && player->ship == NULL) { + if (!spawnShipForPlayer(player)) { + std::cout<<"could not spawn ship for player!" << std::endl; + } + } + } + } + + void State::advancePlayerCommands(float dt) + { + (void) dt; + for (Player *player : players) { + if (player->alive) { + player->energy += dt; + } + + // try to execute as much queued commands as possible. + while (player->hasCommandInQueue()) { + Command *command = player->peekCommand(); + if (!command->allowed(player, this)) { + break; + } + + command->apply(player, this); + player->popCommand(); + } + } + } + + void State::playerKillsPlayer(Player *killer, Player *victim) + { + if (killer == nullptr || victim == nullptr) { + std::cerr <<"error: killer / victim is NULL!" << std::endl; + exit(-1); + return; + } + + std::cout<<"player " << killer->id << " killed " << victim->id << std::endl; + + // destroy ship + size_t i; + for (i=0; iship) { + ships.erase(ships.begin() + i); + break; + } + } + + delete(victim->ship); + victim->ship = nullptr; + + victim->alive = false; + victim->deadTimeCounter = 0.0; + + // TODO + // add points + // + // TODO + // message + // + // TODO + // respawn timer + } + + void State::advancePlayerMissiles(float dt) + { + // advance missiles + for (Player *player : players) { + size_t i = 0; + while (imissiles.size()) { + Missile *missile = player->missiles[i]; + + //std::cout<<"missile: " << (long unsigned int) missile << std::endl; + const Missile::Event evt = missile->advance(this, dt); + + if (evt.hit == Missile::HitObject::Nothing) { + i++; + + } else { + switch(evt.hit) { + case Missile::HitObject::HitPlanet: + //std::cout<<"hit Planet" << std::endl; + break; + + case Missile::HitObject::HitPlayer: + //std::cout<<"hit Player" << std::endl; + playerKillsPlayer(playerForId(evt.playerIdKiller), playerForId(evt.playerIdVictim)); + break; + + case Missile::HitObject::LeftUniverse: + //std::cout<<"missile left the universe." << std::endl; + break; + + default: + break; + } + + player->missiles.erase(player->missiles.begin() + i); + delete(missile); + //std::cout<id == playerId) { + return p; + } + } + + return nullptr; + } + + bool State::findFreePositionWithRadius(float radius, glm::vec2 &pos) + { + bool first = ships.size() == 0; + + int tries = 0; + while(true) { + bool noCollision = true; + + //pos = glm::linearRand2(-1.0, 1.0); + if (first) { + first = false; + pos = glm::vec2(0.0, 0.0); + } else { + pos = glm::vec2(util::randf_0_1(), util::randf_m1_1()); + //glm::linearRand(-1.0, 1.0), glm::linearRand(-1.0, 1.0)); + } + + for (Planet *p : planets) { + if (glm::distance(p->position, pos) <= radius) { + noCollision = false; + break; + } + } + + if (noCollision) { + return true; + } + + if (tries++ >= 1000) { + pos = glm::vec2(0.0, 0.0); + return false; + } + } + } + + void State::commandForPlayer(int playerId, game::Command *cmd) + { + Player *player = playerForId(playerId); + if (player != nullptr) { + player->addCommand(cmd); + } + } +} diff --git a/game/state/state.hpp b/game/state/state.hpp new file mode 100644 index 0000000..1182147 --- /dev/null +++ b/game/state/state.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include +#include + +#include + +#include + +namespace game { + class Command; + class Missile; + class Player; + class Planet; + class Ship; + + // trace of a missile. exists without a missile at player. + //class Trace { + //public: + // std::vector points; + //}; + + class State { + public: + void init(); + void advance(float dt); + + // the (network) layer calling these three functions should keep id's + // unique and give one (network) input an id. + void addPlayer(int playerId); + void playerLeft(int playerId); + void commandForPlayer(int playerId, Command *cmd); + + // lookup. return nullptr on invalid playerId + Player *playerForId(int playerId); + + float maxMissileDistance() const { return m_maxMissileDistance; } + float shipRadius() const { return m_shipRadius; } + + std::vector planets; + std::vector ships; + std::vector players; + + private: + void playerKillsPlayer(Player *killer, Player *victim); + + void advancePlayerShipSpawns(float dt); + void advancePlayerCommands(float dt); + void advancePlayerMissiles(float dt); + + // try to spawn a ship for this player. + // return true on success, false on failure to find a spot. + bool spawnShipForPlayer(Player *player); + + // find some place where nothing is placed nearby (ships/planets). + // usefule for spanwing things + bool findFreePositionWithRadius(float r, glm::vec2 &pos); + + float m_maxMissileDistance; + float m_playerRespawnTime; + float m_shipRadius; + float m_defaultEnergy; + }; +}; diff --git a/game/triangle_window.cpp b/game/triangle_window.cpp new file mode 100644 index 0000000..e69de29 diff --git a/game/triangle_window.h b/game/triangle_window.h new file mode 100644 index 0000000..84a0636 --- /dev/null +++ b/game/triangle_window.h @@ -0,0 +1,36 @@ +#pragma once + +#include "opengl.h" + +class TriangleWindow : public endofthejedi::GLWindow { +private: +protected: + void init() override { + glClearColor(0.5f, 0.6f, 0.7f, 1.0f); + resize(); + + glEnable(GL_DEPTH_TEST); + } + void render(double time) override { + (void) time; + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glBegin(GL_TRIANGLES); + glColor3f(1.0f, 0.0f, 0.0f); + glVertex3f(0.0f, -1.0f, 0.0f); + glColor3f(0.0f, 1.0f, 0.0f); + glVertex3f(-1.0f, 1.0f, 0.0f); + glColor3f(0.0f, 0.0f, 1.0f); + glVertex3f(1.0f, 1.0f, 0.0f); + glEnd(); + } + void resize() override { glViewport(0, 0, getwidth(), getheight()); } + +public: + TriangleWindow(unsigned int width, unsigned int height) + : endofthejedi::GLWindow(width, height) + { + } +}; + diff --git a/game/util.cpp b/game/util.cpp new file mode 100644 index 0000000..99970d0 --- /dev/null +++ b/game/util.cpp @@ -0,0 +1,25 @@ +#include "util.hpp" + +#include + +namespace util { + float randf_m1_1() + { + return 2.0f*randf_0_1() - 1.0f; + } + + float randf_0_1() + { + return static_cast(static_cast(rand()) / (double) RAND_MAX); + } + + glm::vec2 randv2_m1_1() + { + return glm::vec2(randf_m1_1(), randf_m1_1()); + } + + glm::vec2 randv2_0_1() + { + return glm::vec2(randf_0_1(), randf_0_1()); + } +} diff --git a/game/util.hpp b/game/util.hpp new file mode 100644 index 0000000..041968b --- /dev/null +++ b/game/util.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace util { + + float randf_0_1(); + float randf_m1_1(); + + glm::vec2 randv2_m1_1(); + glm::vec2 randv2_0_1(); +}