From cda1c0de2013998bfd74070654d3a0297b19844a Mon Sep 17 00:00:00 2001 From: Vlad Date: Tue, 13 Jan 2026 19:09:06 +0600 Subject: [PATCH] added collision box/planet --- resources/config/explosion_config.json | 15 +++++ resources/config/game_over.json | 55 ++++++++++++++++ resources/gameover.png | 3 + src/Game.cpp | 91 ++++++++++++++++++++++++-- src/Game.h | 9 ++- src/SparkEmitter.cpp | 42 ++++++++---- src/SparkEmitter.h | 2 + 7 files changed, 200 insertions(+), 17 deletions(-) create mode 100644 resources/config/explosion_config.json create mode 100644 resources/config/game_over.json create mode 100644 resources/gameover.png diff --git a/resources/config/explosion_config.json b/resources/config/explosion_config.json new file mode 100644 index 0000000..2e461e8 --- /dev/null +++ b/resources/config/explosion_config.json @@ -0,0 +1,15 @@ +{ + "emissionPoints": [ + { "position": [0.0, 0.0, 0.0] } + ], + "texture": "resources/spark_white.png", + "speedRange": [10.0, 30.0], + "zSpeedRange": [-1.0, 1.0], + "scaleRange": [0.5, 1.0], + "lifeTimeRange": [200.0, 800.0], + "emissionRate": 50.0, + "maxParticles": 5, + "particleSize": 0.5, + "biasX": 0.1, + "shaderProgramName": "default" + } \ No newline at end of file diff --git a/resources/config/game_over.json b/resources/config/game_over.json new file mode 100644 index 0000000..fe448c6 --- /dev/null +++ b/resources/config/game_over.json @@ -0,0 +1,55 @@ +{ + "root": { + "type": "LinearLayout", + "orientation": "vertical", + "align": "center", + "x": 0, + "y": 0, + "width": 1920, + "height": 1080, + "background": { + "color": [0, 0, 0, 0.7] + }, + "children": [ + { + "type": "Button", + "name": "gameOverText", + "x": 350, + "y": 400, + "width": 600, + "height": 150, + "textures": { + "normal": "resources/gameover.png", + "hover": "resources/gameover.png", + "pressed": "resources/gameover.png" + } + }, + { + "type": "Button", + "name": "restartButton", + "x": 350, + "y": 300, + "width": 300, + "height": 80, + "textures": { + "normal": "resources/shoot_normal.png", + "hover": "resources/shoot_normal.png", + "pressed": "resources/shoot_normal.png" + } + }, + { + "type": "Button", + "name": "gameOverExitButton", + "x": 650, + "y": 300, + "width": 300, + "height": 80, + "textures": { + "normal": "resources/sand2.png", + "hover": "resources/sand2.png", + "pressed": "resources/sand2.png" + } + } + ] + } +} \ No newline at end of file diff --git a/resources/gameover.png b/resources/gameover.png new file mode 100644 index 0000000..fa508ac --- /dev/null +++ b/resources/gameover.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8298e2d01c6e7a78a2b4983ad5cab42c6ca145979e5dc516f38fb5b72c5be84 +size 9165 diff --git a/src/Game.cpp b/src/Game.cpp index c6b5575..56bd7d2 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -204,6 +204,8 @@ namespace ZL bool cfgLoaded = sparkEmitter.loadFromJsonFile("resources/config/spark_config.json", renderer, CONST_ZIP_FILE); bool projCfgLoaded = projectileEmitter.loadFromJsonFile("resources/config/spark_projectile_config.json", renderer, CONST_ZIP_FILE); + bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE); + explosionEmitter.setEmissionPoints(std::vector()); projectileEmitter.setEmissionPoints(std::vector()); uiManager.loadFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE); @@ -342,6 +344,7 @@ namespace ZL boxRenderArr[i].RefreshVBO(); } + boxAlive.resize(boxCoordsArr.size(), true); std::cout << "Init step 4 " << std::endl; @@ -454,19 +457,28 @@ namespace ZL renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.TranslateMatrix({ 0, -Environment::zoom * 0.03f, 0 }); - glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); - renderer.DrawVertexRenderStruct(spaceship); + if (shipAlive) { + glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); + renderer.DrawVertexRenderStruct(spaceship); + } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + for (const auto& p : projectiles) { if (p && p->isActive()) { p->draw(renderer); } } + if (shipAlive) { + sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); + projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); + } + + if (showExplosion) { + explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); + } - sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); - projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); glDisable(GL_BLEND); renderer.PopMatrix(); renderer.PopProjectionMatrix(); @@ -496,6 +508,7 @@ namespace ZL for (int i = 0; i < boxCoordsArr.size(); i++) { + if (!boxAlive[i]) continue; renderer.PushMatrix(); renderer.LoadIdentity(); @@ -670,6 +683,76 @@ namespace ZL sparkEmitter.update(static_cast(delta)); projectileEmitter.update(static_cast(delta)); + explosionEmitter.update(static_cast(delta)); + if (shipAlive) { + float distToSurface = planetObject.distanceToPlanetSurface(Environment::shipPosition); + if (distToSurface <= 0.0f) { + Vector3f localForward = { 0,0,-1 }; + Vector3f worldForward = (Environment::shipMatrix * localForward).normalized(); + const float backDistance = 400.0f; + Environment::shipPosition = Environment::shipPosition - worldForward * backDistance; + + shipAlive = false; + gameOver = true; + Environment::shipVelocity = 0.0f; + showExplosion = true; + + explosionEmitter.setUseWorldSpace(false); + explosionEmitter.setEmissionPoints(std::vector{ Vector3f{ 0.0f,0.0f,0.0f } }); + explosionEmitter.emit(); + + std::cerr << "GAME OVER: collision with planet (moved back and exploded)\n"; + + if (!uiGameOverShown) { + if (uiManager.pushMenuFromFile("resources/config/game_over.json", this->renderer, CONST_ZIP_FILE)) { + uiManager.setButtonCallback("restartButton", [this](const std::string& name) { + this->shipAlive = true; + this->gameOver = false; + this->uiGameOverShown = false; + this->showExplosion = false; + this->explosionEmitter.setEmissionPoints(std::vector()); + Environment::shipPosition = Vector3f{ 0, 0, 45000.f }; + Environment::shipVelocity = 0.0f; + uiManager.popMenu(); + std::cerr << "Game restarted\n"; + }); + + uiManager.setButtonCallback("gameOverExitButton", [this](const std::string& name) { + Environment::exitGameLoop = true; + }); + + uiGameOverShown = true; + } + else { + std::cerr << "Failed to load game_over.json\n"; + } + } + } + } + + for (int i = 0; i < boxCoordsArr.size(); ++i) { + if (!boxAlive[i]) continue; + Vector3f boxWorld = boxCoordsArr[i].pos + Vector3f{ 0.0f, 0.0f, 45000.0f }; + Vector3f diff = Environment::shipPosition - boxWorld; + float thresh = shipCollisionRadius + boxCollisionRadius; + if (diff.squaredNorm() <= thresh * thresh) { + boxAlive[i] = false; + + boxRenderArr[i].data.PositionData.clear(); + boxRenderArr[i].vao.reset(); + boxRenderArr[i].positionVBO.reset(); + boxRenderArr[i].texCoordVBO.reset(); + showExplosion = true; + + Vector3f rel = boxWorld - Environment::shipPosition; + Vector3f camPos = Environment::inverseShipMatrix * rel; + explosionEmitter.setUseWorldSpace(true); + explosionEmitter.setEmissionPoints(std::vector{ boxWorld }); + explosionEmitter.emit(); + + std::cerr << "Box destroyed at index " << i << std::endl; + } + } uiManager.update(static_cast(delta)); //#endif lastTickCount = newTickCount; diff --git a/src/Game.h b/src/Game.h index 3b4bf8e..715d605 100644 --- a/src/Game.h +++ b/src/Game.h @@ -100,6 +100,7 @@ namespace ZL { SparkEmitter sparkEmitter; SparkEmitter projectileEmitter; + SparkEmitter explosionEmitter; PlanetObject planetObject; UiManager uiManager; @@ -112,7 +113,13 @@ namespace ZL { TaskManager taskManager; - + bool shipAlive = true; + bool gameOver = false; + std::vector boxAlive; + float shipCollisionRadius = 3.5f; + float boxCollisionRadius = 2.0f; + bool uiGameOverShown = false; + bool showExplosion = false; }; diff --git a/src/SparkEmitter.cpp b/src/SparkEmitter.cpp index b2655f3..40bc676 100644 --- a/src/SparkEmitter.cpp +++ b/src/SparkEmitter.cpp @@ -13,10 +13,10 @@ namespace ZL { using json = nlohmann::json; - SparkEmitter::SparkEmitter() : emissionRate(100.0f), isActive(true), drawDataDirty(true), maxParticles(200), - shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false) { + shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false), + useWorldSpace(false) { particles.resize(maxParticles); drawPositions.reserve(maxParticles * 6); drawTexCoords.reserve(maxParticles * 6); @@ -28,7 +28,8 @@ namespace ZL { SparkEmitter::SparkEmitter(const std::vector& positions, float rate) : emissionPoints(positions), emissionRate(rate), isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100), - shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false) { + shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false), + useWorldSpace(false) { particles.resize(maxParticles); drawPositions.reserve(maxParticles * 6); drawTexCoords.reserve(maxParticles * 6); @@ -42,7 +43,8 @@ namespace ZL { float rate) : emissionPoints(positions), texture(tex), emissionRate(rate), isActive(true), drawDataDirty(true), maxParticles(positions.size() * 100), - shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false) { + shaderProgramName("default"), particleSize(0.04f), biasX(0.3f), configured(false), + useWorldSpace(false) { particles.resize(maxParticles); drawPositions.reserve(maxParticles * 6); drawTexCoords.reserve(maxParticles * 6); @@ -71,7 +73,15 @@ namespace ZL { for (const auto& particle : particles) { if (particle.active) { - sortedParticles.push_back({ &particle, particle.position(2) }); + Vector3f posCam; + if (useWorldSpace) { + Vector3f rel = particle.position - Environment::shipPosition; + posCam = Environment::inverseShipMatrix * rel; + } + else { + posCam = particle.position; + } + sortedParticles.push_back({ &particle, posCam(2) }); } } @@ -82,25 +92,33 @@ namespace ZL { for (const auto& [particlePtr, depth] : sortedParticles) { const auto& particle = *particlePtr; - Vector3f pos = particle.position; + Vector3f posCam; + if (useWorldSpace) { + Vector3f rel = particle.position - Environment::shipPosition; + posCam = Environment::inverseShipMatrix * rel; + } + else { + posCam = particle.position; + } + float size = particleSize * particle.scale; - drawPositions.push_back({ pos(0) - size, pos(1) - size, pos(2) }); + drawPositions.push_back({ posCam(0) - size, posCam(1) - size, posCam(2) }); drawTexCoords.push_back({ 0.0f, 0.0f }); - drawPositions.push_back({ pos(0) - size, pos(1) + size, pos(2) }); + drawPositions.push_back({ posCam(0) - size, posCam(1) + size, posCam(2) }); drawTexCoords.push_back({ 0.0f, 1.0f }); - drawPositions.push_back({ pos(0) + size, pos(1) + size, pos(2) }); + drawPositions.push_back({ posCam(0) + size, posCam(1) + size, posCam(2) }); drawTexCoords.push_back({ 1.0f, 1.0f }); - drawPositions.push_back({ pos(0) - size, pos(1) - size, pos(2) }); + drawPositions.push_back({ posCam(0) - size, posCam(1) - size, posCam(2) }); drawTexCoords.push_back({ 0.0f, 0.0f }); - drawPositions.push_back({ pos(0) + size, pos(1) + size, pos(2) }); + drawPositions.push_back({ posCam(0) + size, posCam(1) + size, posCam(2) }); drawTexCoords.push_back({ 1.0f, 1.0f }); - drawPositions.push_back({ pos(0) + size, pos(1) - size, pos(2) }); + drawPositions.push_back({ posCam(0) + size, posCam(1) - size, posCam(2) }); drawTexCoords.push_back({ 1.0f, 0.0f }); } diff --git a/src/SparkEmitter.h b/src/SparkEmitter.h index 81de9f9..3eed0aa 100644 --- a/src/SparkEmitter.h +++ b/src/SparkEmitter.h @@ -51,6 +51,7 @@ namespace ZL { bool configured; void prepareDrawData(); + bool useWorldSpace; public: SparkEmitter(); @@ -67,6 +68,7 @@ namespace ZL { void setParticleSize(float size) { particleSize = size; } void setBiasX(float bias) { biasX = bias; } + void setUseWorldSpace(bool use) { useWorldSpace = use; } bool loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile = ""); void update(float deltaTimeMs);