diff options
Diffstat (limited to 'src/Game.cpp')
-rw-r--r-- | src/Game.cpp | 95 |
1 files changed, 91 insertions, 4 deletions
diff --git a/src/Game.cpp b/src/Game.cpp index 604eb64..5b61da7 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -18,18 +18,21 @@ */ #include "Game.h" - -#include "gl.h" -#include "BSPTree.h" +#include "Collision.h" #include "Level.h" #include "Shader.h" #include "ShadowVolume.h" #include "Triangle.h" +#include "gl.h" + #include <algorithm> namespace Zoom { +const float Game::PLAYER_SPEED = 10; +const float Game::PLAYER_RADIUS = 0.3; + Game::Game() : playerPos(vmml::vec3f::ZERO), playerRotY(vmml::mat4f::IDENTITY), playerRotX(0), input(0), lightPos(0) { glEnable(GL_DEPTH_TEST); @@ -92,6 +95,15 @@ void Game::turn(float x, float y) { playerRotX = -M_PI_2; } +bool Game::doesCollide(const vmml::vec3f &playerMove) const { + for(std::vector<TriangleRecord>::const_iterator t = triangles.begin(); t != triangles.end(); ++t) { + if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS-MathUtil::EPSILON, playerMove)) + return true; + } + + return false; +} + void Game::run(int delta) { lightPos += delta*0.5; lightPos = std::fmod(lightPos, 26000); @@ -111,8 +123,59 @@ void Game::run(int delta) { playerMove += playerRotY*vmml::vec3f::UNIT_X; } + if(playerMove == vmml::vec3f::ZERO) + return; + playerMove.normalize(); - playerPos += playerMove*0.01*delta; + playerMove *= PLAYER_SPEED*delta/1000; + + vmml::vec3f origMove = playerMove; + + bool ok = false; + + while(!ok) { + ok = true; + + MathUtil::Plane nearestPlane; + + for(std::vector<TriangleRecord>::iterator t = triangles.begin(); t != triangles.end(); ++t) { + if(Collision::test(t->getTriangle(), playerPos, PLAYER_RADIUS, playerMove)) { + vmml::vec3f normal = t->getTriangle().computeNormal(); + MathUtil::Plane p(normal, vmml::dot(normal, t->getTriangle().getVertex(0)+PLAYER_RADIUS*normal)); + if(p.isInFront(playerPos) || p.contains(playerPos)) { + if(ok || p.distance(playerPos) < nearestPlane.distance(playerPos)) { + ok = false; + + nearestPlane = p; + } + } + } + } + + if(!ok) { + vmml::vec3f move; + + if(playerMove.dot(nearestPlane.getNormal()) == 0) + move = playerMove; + else + move = nearestPlane.intersection(MathUtil::Ray(playerPos, playerMove)) - playerPos; + + if(move.dot(origMove) <= 0 && move.squared_length() > MathUtil::EPSILON) { + return; + } + + if(doesCollide(move)) + return; + + playerPos += move; + + vmml::vec3f restMove = playerMove - move; + playerMove = restMove - nearestPlane.getNormal() * (nearestPlane.getNormal().dot(restMove)); + } + } + + if(!doesCollide(playerMove)) + playerPos += playerMove; } void Game::render() { @@ -153,6 +216,30 @@ void Game::render() { glLoadMatrixf(inverse.array); renderer.render(triangles, light); + + Shader::disable(); + glDepthFunc(GL_LEQUAL); + glStencilFunc(GL_ALWAYS, 0, std::numeric_limits<GLuint>::max()); + glBlendFunc(GL_ONE, GL_ZERO); + + glDisable(GL_TEXTURE_2D); + glColor3f(1, 1, 1); + + vmml::vec3f lightVec = playerPos-light; + + vmml::vec3f axis1 = lightVec.cross(vmml::vec3f(0, 1, 0)), axis2 = lightVec.cross(axis1); + axis1.normalize(); + axis2.normalize(); + + glBegin(GL_POLYGON); + for(int i = 0; i < 32; ++i) { + vmml::vec3f pos = light + axis1*std::cos(M_PI*i/16.0)*0.05 + axis2*std::sin(M_PI*i/16.0)*0.05; + + glVertex3fv(pos.array); + } + glEnd(); + + glEnable(GL_TEXTURE_2D); } } |