diff --git a/game/game_window.hpp b/game/game_window.hpp index b83d582..475dd4c 100644 --- a/game/game_window.hpp +++ b/game/game_window.hpp @@ -11,9 +11,13 @@ #include "state/player.hpp" #include "state/planet.hpp" #include "state/ship.hpp" +#include "state/explosion.hpp" class GameWindow : public endofthejedi::GLWindow { private: + Game m_game; + endofthejedi::Renderer m_renderer; + protected: void init() override { glClearColor(0.5f, 0.6f, 0.7f, 1.0f); @@ -37,7 +41,7 @@ class GameWindow : public endofthejedi::GLWindow { } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - + /* for (const game::Planet *planet : m_game.state()->planets) { drawPlanet(planet->position, planet->radius); } @@ -46,6 +50,10 @@ class GameWindow : public endofthejedi::GLWindow { drawTrace(trace); } + for (const game::Explosion *explosion : m_game.state()->explosions) { + drawExplosion(explosion); + } + for (const game::Ship *ship : m_game.state()->ships) { drawShip(ship->position); } @@ -55,6 +63,8 @@ class GameWindow : public endofthejedi::GLWindow { drawMissile(missile->position); } } + */ + m_renderer.render(m_game.state()); } void resize() override { glViewport(0, 0, getwidth(), getheight()); } @@ -77,9 +87,7 @@ class GameWindow : public endofthejedi::GLWindow { 32); } - void drawMissile(const glm::vec2 &pos) - - { + 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.01, color.x, color.y, color.z, 6); } @@ -93,11 +101,18 @@ class GameWindow : public endofthejedi::GLWindow { } } + void drawExplosion(const game::Explosion *explosion) { + // TODO: transparent + // TODO: with glow in the middle + float r = explosion->maxRadius * (explosion->age / explosion->maxAge); + + // TODO: transparency? + glm::vec3 color = glm::vec3(1.0, 0.9, 0.1); + m_renderer.drawCircle(explosion->position.x, explosion->position.y, r, + color.x, color.y, color.z, 64); + } + public: GameWindow(unsigned int width, unsigned int height) : endofthejedi::GLWindow(width, height) {} - - private: - Game m_game; - endofthejedi::Renderer m_renderer; }; diff --git a/game/glclasses.cpp b/game/glclasses.cpp index 4776970..0733c47 100644 --- a/game/glclasses.cpp +++ b/game/glclasses.cpp @@ -42,12 +42,12 @@ bool endofthejedi::Shader::checkShader(GLuint shader) { GLint len = 0; GLint result = 0; - glGetProgramiv(m_program, GL_LINK_STATUS, &result); - glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &len); + glGetShaderiv(shader, GL_COMPILE_STATUS, &result); + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len); if (len > 1) { - char *error = (char *)malloc(len); + char *error = (char *)malloc(len+1); glGetShaderInfoLog(shader, 0, &len, error); - std::string str(error); + std::string str(error, error + len); std::cout << str << "\n"; } std::cout << "checked shader" @@ -71,3 +71,7 @@ void endofthejedi::Shader::load(std::string path, GLenum shadertype) { check(); glDeleteShader(cheddar); } + +GLuint endofthejedi::Shader::location(std::string name) { + return glGetUniformLocation(m_program, name.c_str()); +} diff --git a/game/glclasses.hpp b/game/glclasses.hpp index 46cbf77..7280425 100644 --- a/game/glclasses.hpp +++ b/game/glclasses.hpp @@ -43,8 +43,9 @@ class VAO { class Shader { private: GLuint m_program; - bool check(); - bool checkShader(GLuint shader); + bool check(); + bool checkShader(GLuint shader); + protected: public: Shader(); @@ -52,6 +53,7 @@ class Shader { void bind(); void unbind(); void load(std::string data, GLenum shadertype); + GLuint location(std::string name); }; } diff --git a/game/renderer.cpp b/game/renderer.cpp index 43198b7..c11a04d 100644 --- a/game/renderer.cpp +++ b/game/renderer.cpp @@ -7,18 +7,51 @@ static const char *fss = #include "main.fs" ; +#include +#include "glm/glm.hpp" +#include "glm/vec2.hpp" +#include "glm/vec3.hpp" +#include "glm/gtc/type_ptr.hpp" + endofthejedi::Renderer::Renderer() { m_shader.load(vss, GL_VERTEX_SHADER); m_shader.load(fss, GL_FRAGMENT_SHADER); - - } endofthejedi::Renderer::~Renderer() {} -void endofthejedi::Renderer::render() { +void endofthejedi::Renderer::render(const game::State *state) { m_shader.bind(); + std::vector positions; + std::vector colors; + std::vector radii; + std::vector reflections; + + for (const game::Planet *planet : state->planets) { + positions.push_back(glm::vec3(planet->position, -10.0f)); + radii.push_back(planet->radius); + colors.push_back(glm::vec4(1.0f, 0.0f, 0.0f, 0.5f)); + } + + glUniform1f(m_shader.location("aspectratio"), 16.0f/9.0f); + glUniform1i(m_shader.location("reflections"), 1); + glUniform3f(m_shader.location("l_position"), 0.6f, 0.1f, 0.0f); + glUniform1f(m_shader.location("l_radius"), 1.0f); + glUniform3fv(m_shader.location("s_positions"), positions.size(), + glm::value_ptr(positions[0])); + glUniform4fv(m_shader.location("s_colors"), colors.size(), + glm::value_ptr(colors[0])); + glUniform1fv(m_shader.location("s_radii"), radii.size(), &radii[0]); + glUniform1i(m_shader.location("s_length"), positions.size()); + + // render fullscreen quad with legacy opengl (too lazy, sorry) + glBegin(GL_QUADS); + glVertex2f(-1.0f, -1.0f); + glVertex2f(1.0f, -1.0f); + glVertex2f(1.0f, 1.0f); + glVertex2f(-1.0f, 1.0f); + glEnd(); } void endofthejedi::Renderer::drawCircle(float x, float y, float radius, float r, diff --git a/game/renderer.hpp b/game/renderer.hpp index 65b736f..572547a 100644 --- a/game/renderer.hpp +++ b/game/renderer.hpp @@ -6,20 +6,20 @@ #include #include "glclasses.hpp" +#include "game.hpp" +#include "state/planet.hpp" namespace endofthejedi { class Renderer { private: - VBO m_vbo; - VAO m_vao; Shader m_shader; protected: public: Renderer(); ~Renderer(); - void render(); + void render(const game::State* state); void drawCircle(float x, float y, float radius, float r, float g, float b, int numSides = 12); }; diff --git a/game/state/explosion.hpp b/game/state/explosion.hpp index 66c234f..32169eb 100644 --- a/game/state/explosion.hpp +++ b/game/state/explosion.hpp @@ -2,31 +2,32 @@ #include +#include "util.hpp" + +#include "missile_hit_type.hpp" + namespace game { /** * Explosion: just an effect which looks good. */ class Explosion { public: - enum class Kind { - MissileExplodesInSpace, // missile explode in free space - MissileAgainstPlanet, // explosion of missile when it hits a planet - MissileAgainstShip // bigger explosion: missile hits a ship which explodes with it - }; - - Explosion(const glm::vec2 &pos, Kind kind, float maxAge=1.0) - : position(pos), kind(kind), age(0.0), maxAge(maxAge) + Explosion(const glm::vec2 &pos, Hit hit, float maxAge=1.0) + : hit(hit) + , position(pos) + , age(0.0) + , maxAge(maxAge * (1.0 + 0.1*util::randf_0_1())) + , maxRadius(0.05) { } - const Kind kind; // kind of the explosion + const Hit hit; // kind of the explosion depends on the hit type const glm::vec2 position; // position where it starts float age; // age (in seconsd) of the explosion // age (in seconds) when the explosion is not visible // anymore and will disappear afterwards const float maxAge; + const float maxRadius; // current radius depends on time. }; } - -#endif diff --git a/game/state/missile.cpp b/game/state/missile.cpp index b789b5f..08a04b7 100644 --- a/game/state/missile.cpp +++ b/game/state/missile.cpp @@ -49,7 +49,7 @@ namespace game { 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); + return Missile::Event(position, Hit::Planet); } dist *= 20.0; @@ -77,7 +77,7 @@ namespace game { // 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, Hit::BorderOfUniverse); } return Missile::Event(position); diff --git a/game/state/missile.hpp b/game/state/missile.hpp index c68706d..2763fe7 100644 --- a/game/state/missile.hpp +++ b/game/state/missile.hpp @@ -3,6 +3,8 @@ #include #include +#include "missile_hit_type.hpp" + namespace game { class State; class Ship; @@ -15,36 +17,29 @@ namespace game { // 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) : Event(pos, Hit::Nothing) { } - Event(const glm::vec2 &pos, HitObject hit) - : hit(hit), pos(pos) + Event(const glm::vec2 &pos, Hit hit) + : hit(hit), position(pos) { } Event(const glm::vec2 &pos, int playerIdKiller, int playerIdVictim) - : Event(pos, HitObject::HitPlayer) + : Event(pos, Hit::Ship) { this->playerIdKiller = playerIdKiller; this->playerIdVictim = playerIdVictim; } - HitObject hit; - glm::vec2 pos; + Hit hit; + glm::vec2 position; int playerIdKiller; int playerIdVictim; diff --git a/game/state/missile_hit_type.hpp b/game/state/missile_hit_type.hpp new file mode 100644 index 0000000..04f1af3 --- /dev/null +++ b/game/state/missile_hit_type.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace game { + /* + * A missile can hit different objects the type says which one. + * Used in various places so extra file for this. + */ + enum class Hit { + Nothing, + Ship, + Planet, + + // TODO could be needed for really fancy explosions because + // this is cool and should noh happen very often + // AgainstMissile, + + BorderOfUniverse + }; +} diff --git a/game/state/state.cpp b/game/state/state.cpp index bc39594..acce65c 100644 --- a/game/state/state.cpp +++ b/game/state/state.cpp @@ -6,6 +6,7 @@ #include #include +#include "missile_hit_type.hpp" #include "object.hpp" #include "missile.hpp" #include "player.hpp" @@ -13,6 +14,7 @@ #include "ship.hpp" #include "commands.hpp" #include "trace.hpp" +#include "explosion.hpp" #include "util.hpp" @@ -43,7 +45,9 @@ namespace game { } } while(glm::length(pos) < 0.2 && tries++ < 1000); - planets.push_back(new Planet(pos, 0.03 + 0.07*util::randf_0_1())); + pos.x *= 10; + pos.y *= 10; + planets.push_back(new Planet(pos, (0.03 + 0.07*util::randf_0_1()) * 10)); } } @@ -162,26 +166,25 @@ namespace game { //std::cout<<"missile: " << (long unsigned int) missile << std::endl; const Missile::Event evt = missile->advance(this, dt); - missile->trace->addPointFromMissile(); + const bool isHit = (evt.hit != Hit::Nothing); - // TODO: - // spawn just if the path differs + missile->trace->addPointFromMissile(isHit); // force point if missile gets destroyed a - if (evt.hit == Missile::HitObject::Nothing) { + if (!isHit) { i++; } else { switch(evt.hit) { - case Missile::HitObject::HitPlanet: + case Hit::Planet: //std::cout<<"hit Planet" << std::endl; break; - case Missile::HitObject::HitPlayer: + case Hit::Ship: //std::cout<<"hit Player" << std::endl; playerKillsPlayer(playerForId(evt.playerIdKiller), playerForId(evt.playerIdVictim)); break; - case Missile::HitObject::LeftUniverse: + case Hit::BorderOfUniverse: //std::cout<<"missile left the universe." << std::endl; break; @@ -189,6 +192,8 @@ namespace game { break; } + addExplosionFromHit(&evt); + player->missiles.erase(player->missiles.begin() + i); delete(missile); //std::cout<age += dt; + if (explosion->age >= explosion->maxAge) { + delete(explosion); + explosions.erase(explosions.begin()+i); + continue; + } + + i++; + } + } + void State::advance(float dt) { - //std::cout<<"advance ship spawns" << std::endl; advancePlayerShipSpawns(dt); - //std::cout<<"advance commands" << std::endl; + advanceExplosions(dt); + advancePlayerCommands(dt); - //std::cout<<"advance missiles" << std::endl; advancePlayerMissiles(dt); + } Player *State::playerForId(int playerId) @@ -270,4 +291,13 @@ namespace game { { traces.push_back(trace); } + + void State::addExplosionFromHit(const Missile::Event *evt) + { + if (evt->hit == Hit::Nothing || evt->hit == Hit::BorderOfUniverse) { + return; + } + + explosions.push_back(new Explosion(evt->position, evt->hit)); + } } diff --git a/game/state/state.hpp b/game/state/state.hpp index 0df4313..3fa7781 100644 --- a/game/state/state.hpp +++ b/game/state/state.hpp @@ -7,14 +7,16 @@ #include +#include "missile.hpp" + namespace game { // forward declarations class Command; - class Missile; class Player; class Planet; class Ship; class Trace; + class Explosion; class State { public: @@ -61,10 +63,11 @@ namespace game { // Game items which should be rendered are here: // (access missiles by iterating over player's missiles attribute) - std::vector planets; - std::vector ships; - std::vector players; - std::vector traces; + std::vector planets; + std::vector ships; + std::vector players; + std::vector traces; + std::vector explosions; private: /*************************************************************************/ @@ -73,6 +76,9 @@ namespace game { void playerKillsPlayer(Player *killer, Player *victim); + void addExplosionFromHit(const Missile::Event *evt); + + void advanceExplosions(float dt); void advancePlayerShipSpawns(float dt); void advancePlayerCommands(float dt); void advancePlayerMissiles(float dt);