summaryrefslogtreecommitdiffstats
path: root/src/Game.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Game.cpp')
-rw-r--r--src/Game.cpp95
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);
}
}