#include "../H/engine.h" #include "../H/transformation.h" #include #include #include #include Engine::Engine() : m_p1(Vector3f(VIEW_DISTANCE,20,VIEW_DISTANCE)), m_textureAtlas(BTYPE_LAST), m_chunks(Array2d(VIEW_DISTANCE * 2 / CHUNK_SIZE_X, VIEW_DISTANCE * 2 / CHUNK_SIZE_Z)), m_currentBlock(Vector4f(0,0,0,0)), m_currentMob(Vector3f(0,0,0),0,0) { } Engine::~Engine() { SaveGame(); } void Engine::LoadGame(std::ifstream SaveFile){ std::cout << "LOADING THE GAME" << std::endl; if (SaveFile.is_open()) { std::string Block; while (std::getline(SaveFile, Block)) { int notdigit = 0; std::string x,y,z,t; for (int i = 0; i < Block.length(); i++) { if (isdigit(Block[i])) { if (notdigit < 2) x += Block[i]; else if (notdigit < 3) y += Block[i]; else if (notdigit < 4) z += Block[i]; else if (notdigit < 5) t += Block[i]; } else notdigit++; } Vector4f Bloc(stoi(x), stoi(y), stoi(z), stoi(t)); m_ModifiedBlocks.push_front(Bloc); SetBlockAt(stoi(x), stoi(y), stoi(z), stoi(t)); } std::cout << "GAME LOADED" << std::endl; SaveFile.close(); } else std::cout << "Problem opening the save file :(" << std::endl; } void Engine::SaveGame(){ std::cout << "SAVING THE GAME" << std::endl; std::ofstream SaveFile("SaveFile"); if(SaveFile.is_open()){ for (size_t i = 0; i < m_ModifiedBlocks.size() + 1; i++) { if (m_ModifiedBlocks.front().x >= 0 && m_ModifiedBlocks.front().y >= 0 && m_ModifiedBlocks.front().z >= 0){ SaveFile << "{" << m_ModifiedBlocks.front().x << ";" << m_ModifiedBlocks.front().y << ";" << m_ModifiedBlocks.front().z << ";" << m_ModifiedBlocks.front().t << "}" << std::endl; } m_ModifiedBlocks.pop_front(); } SaveFile.close(); std::cout << "GAME SAVED" << std::endl; } else std::cout << "Problem writing to the save file :(" << std::endl; } void Engine::Init() { //glEnable(GL_CULL_FACE); // Initialize GLEW GLenum glewErr = glewInit(); if ( glewErr != GLEW_OK ) { std :: cerr << " ERREUR GLEW : " << glewGetErrorString(glewErr) << std :: endl ; abort(); } glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glEnable(GL_TEXTURE_2D); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0f, (float)Width() / (float)Height(), 0.0001f, 1000.0f); glEnable(GL_DEPTH_TEST); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); glEnable(GL_LINE_SMOOTH); // Light GLfloat light0Pos[4] = { 0.0f, CHUNK_SIZE_Y, 0.0f, 1.0f }; GLfloat light0Amb[4] = { 0.9f, 0.9f, 0.9f, 1.0f }; GLfloat light0Diff[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat light0Spec[4] = { 0.2f, 0.2f, 0.2f, 1.0f }; glEnable(GL_LIGHT0); glLightfv(GL_LIGHT0, GL_POSITION, light0Pos); glLightfv(GL_LIGHT0, GL_AMBIENT, light0Amb); glLightfv(GL_LIGHT0, GL_DIFFUSE, light0Diff); glLightfv(GL_LIGHT0, GL_SPECULAR, light0Spec); CenterMouse(); HideCursor(); } void Engine::DeInit() { } void Engine::LoadResource() { LoadTexture(m_textureCrosshair, TEXTURE_PATH "cross.bmp"); LoadTexture(m_textureFont, TEXTURE_PATH "font.bmp"); LoadTexture(m_textureMob, TEXTURE_PATH "mob.png"); TextureAtlas::TextureIndex texDarkIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "dark.png"); TextureAtlas::TextureIndex texDarkerIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "darker.png"); TextureAtlas::TextureIndex texLightIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "light.png"); TextureAtlas::TextureIndex texLighterIndex = m_textureAtlas.AddTexture(TEXTURE_PATH "lighter.png"); float u,v,w,h; m_textureAtlas.TextureIndexToCoord(texDarkerIndex, u,v,w,h); m_bi[BTYPE_DARKER].SetUVWH(u, v, w, h); m_textureAtlas.TextureIndexToCoord(texDarkIndex, u,v,w,h); m_bi[BTYPE_DARK].SetUVWH(u, v, w, h); m_textureAtlas.TextureIndexToCoord(texLighterIndex, u,v,w,h); m_bi[BTYPE_LIGHTER].SetUVWH(u, v, w, h); m_textureAtlas.TextureIndexToCoord(texLightIndex, u,v,w,h); m_bi[BTYPE_LIGHT].SetUVWH(u, v, w, h); if(!m_textureAtlas.Generate(1024, false)) { std::cout << "Unable to generate texture atlas ..." << std::endl; abort(); } std::cout << "Loading and compiling shaders ..." << std::endl; if (!m_shader01.Load(SHADER_PATH "shader01.vert", SHADER_PATH "shader01.frag", true)) { std::cout << " Failed to load shader " << std::endl; exit(1); } for (int x = 0; x < (VIEW_DISTANCE * 2 / CHUNK_SIZE_X); x++) { for (int z = 0; z < (VIEW_DISTANCE * 2 / CHUNK_SIZE_Z); z++) { m_chunks.Set(x, z, new Chunk(x * CHUNK_SIZE_X, z * CHUNK_SIZE_Z)); } } m_chunks.Set(15, 15, new Chunk(15 * CHUNK_SIZE_X, 15 * CHUNK_SIZE_Z)); LoadGame(std::ifstream("SaveFile")); } void Engine::UnloadResource() { } void Engine::Render(float elapsedTime) { static float gameTime = elapsedTime; gameTime += elapsedTime; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Transformations initiales glMatrixMode(GL_MODELVIEW); glLoadIdentity(); Transformation player_move; bool OnGround = false; Vector3f pos = m_p1.Position(); Vector3f delta = m_p1.SimulateMove(m_keyW, m_keyS, m_keyA, m_keyD, m_shift, elapsedTime); delta.y = -0.1; float jumpvalue = 0; BlockType bt1, bt2, bt3; bt1 = BlockAt(pos.x, pos.y - 1.7f, pos.z, BTYPE_DARK); if (bt1 != BTYPE_AIR) OnGround = true; bt2 = BlockAt(pos.x, pos.y + delta.y, pos.z, BTYPE_DARK); if (bt2 != BTYPE_AIR) m_jumpsize = 1.6; m_jumpsize += m_p1.SimulateJump(m_space, m_InJump, jumpvalue, OnGround, m_jumpsize); //Collisions for x: bt1 = BlockAt(pos.x + delta.x, pos.y, pos.z, BTYPE_AIR); bt2 = BlockAt(pos.x + delta.x, pos.y - 0.9f, pos.z, BTYPE_AIR); bt3 = BlockAt(pos.x + delta.x, pos.y - 1.6f, pos.z, BTYPE_AIR); if(bt1 != BTYPE_AIR || bt2 != BTYPE_AIR || bt3 != BTYPE_AIR) delta.x = 0; // Collisions for y bt1 = BlockAt(pos.x, pos.y - 1.7f, pos.z, BTYPE_DARK); if(bt1 != BTYPE_AIR){ delta.y = 0; } //Colisions for z bt1 = BlockAt(pos.x, pos.y, pos.z + delta.z, BTYPE_AIR); bt2 = BlockAt(pos.x, pos.y - 0.9f, pos.z + delta.z, BTYPE_AIR); bt3 = BlockAt(pos.x, pos.y - 1.6f, pos.z + delta.z, BTYPE_AIR); if(bt1 != BTYPE_AIR || bt2 != BTYPE_AIR || bt3 != BTYPE_AIR) delta.z = 0; pos.y += jumpvalue; pos += delta; m_p1.SetPosition(pos); m_p1.ApplyTransformation(player_move); player_move.Use(); m_textureAtlas.Bind(); //translation player_move.ApplyTranslation(0.5f,0.5f,0.5f); //use the above player_move.Use(); m_shader01.Use(); for (int x = 0; x < (VIEW_DISTANCE * 2 / CHUNK_SIZE_X); x++) { for (int z = 0; z < (VIEW_DISTANCE * 2 / CHUNK_SIZE_Z); z++) { if (m_chunks.Get(x,z)->IsDirty()) m_chunks.Get(x,z)->Update(m_bi); m_chunks.Get(x,z)->Render(); } } Shader::Disable(); m_textureMob.Bind(); for (int i = 0; i < m_mobs.size(); i++) { if (m_mobs[i].Health() <= 0) m_mobs.erase(m_mobs.begin() + i); Vector3f posMob = m_mobs[i].Position(); if ((posMob.x <= pos.x + 0.1 && posMob.x >= pos.x - 0.1) && (posMob.y <= pos.y + 0.1 && posMob.y >= pos.y - 0.1) && (posMob.z <= pos.z + 0.1 && posMob.z >= pos.z - 0.1)) { m_mobs[i].Damage(m_p1); m_mobs[i].SetPosition(Vector3f(posMob.x - 5, posMob.y + 5, posMob.z - 5)); } m_mobs[i].Move(m_p1); m_mobs[i].RenderMob(); } m_points = m_mobs.size() * 100; if(m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); DrawHud(elapsedTime); if(m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (m_p1.Health() <= 0) { SaveGame(); Stop(); } } void Engine::KeyPressEvent(unsigned char key) { switch(key) { case 36: // ESC SaveGame(); Stop(); break; case 94: // F10 SetFullscreen(!IsFullscreen()); break; case 38: // Shift m_shift = true; m_run = true; break; case 22: // W m_keyW = true; m_walk = true; break; case 0: // A m_keyA = true; m_walk = true; break; case 18: // S m_keyS = true; m_walk = true; break; case 3: // D m_keyD = true; m_walk = true; break; case 57: // spacebar m_space = true; break; case 60: //tab if (m_selectedbloc <= BTYPE_LIGHTER) m_selectedbloc++; else m_selectedbloc = BTYPE_DARK; break; default: std::cout << "Unhandled key: " << (int)key << std::endl; } } void Engine::KeyReleaseEvent(unsigned char key) { switch(key) { case 38: // Shift m_shift = false; m_run = false; break; case 22: // W m_keyW = false; if (!m_keyW && !m_keyS && !m_keyD && !m_keyA) m_walk = false; break; case 0: // A m_keyA = false; if (!m_keyW && !m_keyS && !m_keyD && !m_keyA) m_walk = false; break; case 18: // S m_keyS = false; if (!m_keyW && !m_keyS && !m_keyD && !m_keyA) m_walk = false; break; case 3: // D m_keyD = false; if (!m_keyW && !m_keyS && !m_keyD && !m_keyA) m_walk = false; break; case 57: // spacebar m_space = false; break; case 24: // Y m_wireframe = !m_wireframe; if(m_wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); else glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); break; } } void Engine::MouseMoveEvent(int x, int y) { // Centrer la souris seulement si elle n'est pas d�j� centr�e // Il est n�cessaire de faire la v�rification pour �viter de tomber // dans une boucle infinie o� l'appel � CenterMouse g�n�re un // MouseMoveEvent, qui rapelle CenterMouse qui rapelle un autre // MouseMoveEvent, etc if(x == (Width() / 2) && y == (Height() / 2)) return; MakeRelativeToCenter(x, y); //m_p1.TurnLeftRight(y); //m_p1.TurnTopBottom(x); m_p1.TurnCamera(x, y); CenterMouse(); } void Engine::MousePressEvent(const MOUSE_BUTTON& button, int x, int y) { switch (button) { case 1: if(!m_currentMob.isNull()) HitMob(); else DestroyBlocGenerateMob(); break; case 4: CreateBloc(); break; default: std::cout << "Unhandled mouse action" << std::endl; break; } } void Engine::MouseReleaseEvent(const MOUSE_BUTTON& button, int x, int y) { } bool Engine::LoadTexture(Texture& texture, const std::string& filename, bool stopOnError) { texture.Load(filename); if(!texture.IsValid()) { std::cerr << "Unable to load texture (" << filename << ")" << std::endl; if(stopOnError) Stop(); return false; } return true; } int Engine::GetFps(float elapsedTime){ return 1 / elapsedTime; } void Engine::DrawHud(float elapsedTime) { // Set the blend func, all that is black will be transparent glDisable(GL_LIGHTING); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glBlendFunc(GL_SRC_ALPHA , GL_ONE); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, Width (), 0, Height (), -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); // Font m_textureFont.Bind(); std::ostringstream ss; for (int i = 0; i < m_mobs.size(); i++) { ss << "Mob#" << i << " health: " << m_mobs[i].Health(); PrintText(10, Height () - 40 - (i * 10), ss.str()); ss.str(""); } ss << "Score:" << m_points; PrintText(Width() / 2, Height () - 25, ss.str()); ss.str(""); ss << "Health:" << m_p1.Health(); PrintText(Width() / 2, Height () - 35, ss.str()); ss.str(""); ss << "Fps: " << GetFps(elapsedTime); PrintText(10, Height () - 25, ss.str()); ss.str(""); ss << "Selected bloc type: " << m_selectedbloc; PrintText(10, 20, ss.str()); ss.str(""); ss << "Position: " << m_p1.Position(); PrintText (10, 10, ss.str()); // Crosshair m_textureCrosshair.Bind(); static const int crossSize = 32; glLoadIdentity(); glTranslated(Width () / 2 - crossSize / 2, Height () / 2 - crossSize / 2, 0); glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2i(0, 0); glTexCoord2f(1, 0); glVertex2i(crossSize, 0); glTexCoord2f(1, 1); glVertex2i(crossSize, crossSize); glTexCoord2f(0, 1); glVertex2i(0, crossSize); glEnd(); glEnable(GL_LIGHTING); glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } void Engine::PrintText(unsigned int x, unsigned int y, const std::string& t) { glLoadIdentity(); glTranslated(x, y, 0); for(unsigned int i = 0; i VIEW_DISTANCE * 2 / CHUNK_SIZE_X || cz > VIEW_DISTANCE * 2 / CHUNK_SIZE_Z || cx < 0 || cz < 0) { std::cout << "WRONG CHUNK POSITION" << std::endl; return nullptr; } return m_chunks.Get(cx, cz); } Chunk* Engine::ChunkAt(const Vector3& pos) const { return ChunkAt(pos.x, pos.y, pos.z); } BlockType Engine::BlockAt(float x, float y, float z, BlockType defaultBlockType) const { Chunk* c = ChunkAt(x, y, z); if(!c) return defaultBlockType; int bx = (int)x % CHUNK_SIZE_X; int by = (int)y % CHUNK_SIZE_Y; int bz = (int)z % CHUNK_SIZE_Z; return c->GetBlock(bx, by, bz); } void Engine::SetBlockAt(float x, float y, float z, BlockType BlockToSet) const{ Chunk* c = ChunkAt(x, y, z); int bx = (int)x % CHUNK_SIZE_X; int by = (int)y % CHUNK_SIZE_Y; int bz = (int)z % CHUNK_SIZE_Z; c->SetBlock(bx, by, bz, BlockToSet); } bool Engine::IsWalking(){ if (m_keyA || m_keyD || m_keyS || m_keyW) return true; else return false; } static bool EqualWithEpsilon(const float& v1, const float& v2, float epsilon = float(0.0001)) { return (fabs(v2 - v1) < epsilon); } static bool InRangeWithEpsilon(const float& v, const float& vinf, const float& vsup, float epsilon = float(0.0001)) { return (v >= vinf - epsilon && v <= vsup + epsilon); } void Engine::GetBlocAtCursor() { int x = Width() / 2; int y = Height() / 2; GLint viewport[4]; GLdouble modelview[16]; GLdouble projection[16]; GLfloat winX, winY, winZ; GLdouble posX, posY, posZ; glGetDoublev(GL_MODELVIEW_MATRIX, modelview); glGetDoublev(GL_PROJECTION_MATRIX, projection); glGetIntegerv(GL_VIEWPORT, viewport); winX = (float)x; winY = (float)viewport[3] - (float)y; glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ); gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ); posX += .5f; posY += .5f; posZ += .5f; // Le cast vers int marche juste pour les valeurs entiere, utiliser une fonction de la libc si besoin // de valeurs negatives int px = (int)(posX); int py = (int)(posY); int pz = (int)(posZ); bool found = false; if((m_p1.Position() - Vector3f((float)posX, (float)posY, (float)posZ)).Length() < MAX_SELECTION_DISTANCE) { // Apres avoir determine la position du bloc en utilisant la partie entiere du hit // point retourne par opengl, on doit verifier de chaque cote du bloc trouve pour trouver // le vrai bloc. Le vrai bloc peut etre different a cause d'erreurs de precision de nos // nombres flottants (si z = 14.999 par exemple, et qu'il n'y a pas de blocs a la position // 14 (apres arrondi vers l'entier) on doit trouver et retourner le bloc en position 15 s'il existe // A cause des erreurs de precisions, ils arrive que le cote d'un bloc qui doit pourtant etre a la // position 15 par exemple nous retourne plutot la position 15.0001 for(int x = px - 1; !found && x <= px + 1; ++x) { for(int y = py - 1; !found && x >= 0 && y <= py + 1; ++y) { for(int z = pz - 1; !found && y >= 0 && z <= pz + 1; ++z) { if(z >= 0) { Mob mob = MobAt((float)x,(float)y, (float)z); if (!mob.isNull()) m_currentMob = mob; BlockType bt = BlockAt((float)x,(float)y, (float)z, BTYPE_AIR); if(bt == BTYPE_AIR) continue; // Skip water blocs //if(bloc->Type == BT_WATER) // continue; m_currentBlock.x = x; m_currentBlock.y = y; m_currentBlock.z = z; m_currentBlock.t = bt; if(InRangeWithEpsilon((float)posX, (float)x, (float)x + 1.f, 0.05f) && InRangeWithEpsilon((float)posY, (float)y, (float)y + 1.f, 0.05f) && InRangeWithEpsilon((float)posZ, (float)z, (float)z + 1.f, 0.05f)) { found = true; } } } } } } if(!found) { m_currentBlock.x = -1; } else { // Find on which face of the bloc we got an hit m_currentFaceNormal.Zero(); const float epsilon = 0.09f; // Front et back: if(EqualWithEpsilon((float)posZ, (float)m_currentBlock.z, epsilon)) m_currentFaceNormal.z = -1; else if(EqualWithEpsilon((float)posZ, (float)m_currentBlock.z + 1.f, epsilon)) m_currentFaceNormal.z = 1; else if(EqualWithEpsilon((float)posX, (float)m_currentBlock.x, epsilon)) m_currentFaceNormal.x = -1; else if(EqualWithEpsilon((float)posX, (float)m_currentBlock.x + 1.f, epsilon)) m_currentFaceNormal.x = 1; else if(EqualWithEpsilon((float)posY, (float)m_currentBlock.y, epsilon)) m_currentFaceNormal.y = -1; else if(EqualWithEpsilon((float)posY, (float)m_currentBlock.y + 1.f, epsilon)) m_currentFaceNormal.y = 1; } } void Engine::CreateBloc(){ GetBlocAtCursor(); Vector4f Bloc(m_currentBlock.x + m_currentFaceNormal.x, m_currentBlock.y + m_currentFaceNormal.y, m_currentBlock.z + m_currentFaceNormal.z, m_selectedbloc); m_ModifiedBlocks.push_front(Bloc); SetBlockAt(m_currentBlock.x + m_currentFaceNormal.x, m_currentBlock.y + m_currentFaceNormal.y, m_currentBlock.z + m_currentFaceNormal.z, m_selectedbloc); } void Engine::DestroyBloc(){ GetBlocAtCursor(); Vector4f Bloc(m_currentBlock.x, m_currentBlock.y, m_currentBlock.z, BTYPE_AIR); m_ModifiedBlocks.push_front(Bloc); SetBlockAt(m_currentBlock.x, m_currentBlock.y, m_currentBlock.z, BTYPE_AIR); } void Engine::DestroyBlocGenerateMob(){ GetBlocAtCursor(); Vector4f Bloc(m_currentBlock.x, m_currentBlock.y, m_currentBlock.z, BTYPE_AIR); m_ModifiedBlocks.push_front(Bloc); SetBlockAt(m_currentBlock.x, m_currentBlock.y, m_currentBlock.z, BTYPE_AIR); Vector3f v(m_currentBlock.x, m_currentBlock.y, m_currentBlock.z); int dmg; if(m_currentBlock.t == BTYPE_AIR) dmg = 1000; else dmg = m_currentBlock.t; Mob NewMob(v, dmg, dmg); m_mobs.push_back(NewMob); } void Engine::HitMob(){ GetBlocAtCursor(); for (int i = 0; i < m_mobs.size(); i++) { if(m_mobs[i].isEqual(m_currentMob)) { m_p1.Damage(m_mobs[i]); } } } Mob Engine::MobAt(int x, int y, int z){ for (int i = 0; i < m_mobs.size(); i++) { Vector3f posMob = m_mobs[i].Position(); if((posMob.x <= x + 0.5f && posMob.x >= x - 0.5f) && (posMob.y <= y + 0.5f && posMob.y >= y - 0.5f) && (posMob.z <= z + 0.5f && posMob.z >= z - 0.5f)) { return m_mobs[i]; } } return Mob(Vector3f(0,0,0), 0, 0); }