diff --git a/src/Game.cpp b/src/Game.cpp index 5879c07..662ade7 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -849,6 +849,7 @@ namespace ZL for (auto const& [id, remotePlayer] : remotePlayerStates) { + if (deadRemotePlayers.count(id)) continue; //<<<<<<< HEAD const ClientState& st = remotePlayer; diff --git a/src/network/LocalClient.cpp b/src/network/LocalClient.cpp index 5869c6a..c0a219e 100644 --- a/src/network/LocalClient.cpp +++ b/src/network/LocalClient.cpp @@ -17,7 +17,7 @@ namespace ZL { void LocalClient::generateBoxes() { serverBoxes.clear(); - + std::random_device rd; std::mt19937 gen(rd()); @@ -69,7 +69,7 @@ namespace ZL { std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distribution<> distrib(-500.0, 500.0); - + return Eigen::Vector3f( (float)distrib(gen), (float)distrib(gen), @@ -94,6 +94,7 @@ namespace ZL { npc.targetPosition = generateRandomPosition(); npc.lastStateUpdateMs = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); + npc.destroyed = false; npc.stateHistory.add_state(npc.currentState); npcs.push_back(npc); @@ -105,6 +106,8 @@ namespace ZL { std::chrono::system_clock::now().time_since_epoch()).count(); for (auto& npc : npcs) { + if (npc.destroyed) continue; + uint64_t deltaMs = now_ms - npc.lastStateUpdateMs; if (deltaMs == 0) { npc.lastStateUpdateMs = now_ms; @@ -191,12 +194,12 @@ namespace ZL { void LocalClient::updatePhysics() { auto now_ms = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()).count(); - + if (lastUpdateMs == 0) { lastUpdateMs = now_ms; return; } - + uint64_t deltaMs = now_ms - lastUpdateMs; float dt = deltaMs / 1000.0f; lastUpdateMs = now_ms; @@ -229,6 +232,7 @@ namespace ZL { const float projectileHitRadius = 1.5f; const float boxCollisionRadius = 2.0f; const float shipCollisionRadius = 15.0f; + const float npcCollisionRadius = 5.0f; std::vector> boxProjectileCollisions; @@ -266,7 +270,48 @@ namespace ZL { std::cout << "LocalClient: Box " << boxIdx << " destroyed by projectile from player " << projectiles[projIdx].shooterId << std::endl; - if (std::find(projIndicesToRemove.begin(), projIndicesToRemove.end(), (int)projIdx) + if (std::find(projIndicesToRemove.begin(), projIndicesToRemove.end(), (int)projIdx) + == projIndicesToRemove.end()) { + projIndicesToRemove.push_back(static_cast(projIdx)); + } + } + } + + std::vector> npcProjectileCollisions; + + for (size_t ni = 0; ni < npcs.size(); ++ni) { + if (npcs[ni].destroyed) continue; + + for (size_t pi = 0; pi < projectiles.size(); ++pi) { + const auto& pr = projectiles[pi]; + Eigen::Vector3f diff = pr.pos - npcs[ni].currentState.position; + float thresh = npcCollisionRadius + projectileHitRadius; + + if (diff.squaredNorm() <= thresh * thresh) { + npcProjectileCollisions.push_back({ ni, pi }); + } + } + } + + for (const auto& [npcIdx, projIdx] : npcProjectileCollisions) { + if (!npcs[npcIdx].destroyed) { + npcs[npcIdx].destroyed = true; + + DeathInfo death; + death.targetId = npcs[npcIdx].id; + death.serverTime = now_ms; + death.position = npcs[npcIdx].currentState.position; + death.killerId = projectiles[projIdx].shooterId; + + pendingDeaths.push_back(death); + + std::cout << "LocalClient: NPC " << npcs[npcIdx].id << " destroyed by projectile from player " + << projectiles[projIdx].shooterId << " at position (" + << npcs[npcIdx].currentState.position.x() << ", " + << npcs[npcIdx].currentState.position.y() << ", " + << npcs[npcIdx].currentState.position.z() << ")" << std::endl; + + if (std::find(projIndicesToRemove.begin(), projIndicesToRemove.end(), (int)projIdx) == projIndicesToRemove.end()) { projIndicesToRemove.push_back(static_cast(projIdx)); } @@ -317,7 +362,7 @@ namespace ZL { tokens.push_back(token); } return tokens; - }(message, ':'); + }(message, ':'); if (parts.empty()) return; @@ -371,8 +416,8 @@ namespace ZL { pinfo.velocity = velocity; pendingProjectiles.push_back(pinfo); - std::cout << "LocalClient: Created projectile at pos (" << shotPos.x() << ", " - << shotPos.y() << ", " << shotPos.z() << ") vel (" << pr.vel.x() << ", " + std::cout << "LocalClient: Created projectile at pos (" << shotPos.x() << ", " + << shotPos.y() << ", " << shotPos.z() << ") vel (" << pr.vel.x() << ", " << pr.vel.y() << ", " << pr.vel.z() << ")" << std::endl; } } @@ -384,10 +429,18 @@ namespace ZL { return result; } + std::vector LocalClient::getPendingDeaths() { + auto result = pendingDeaths; + pendingDeaths.clear(); + return result; + } + std::unordered_map LocalClient::getRemotePlayers() { std::unordered_map result; for (const auto& npc : npcs) { - result[npc.id] = npc.stateHistory; + if (!npc.destroyed) { + result[npc.id] = npc.stateHistory; + } } return result; } @@ -400,16 +453,9 @@ namespace ZL { return result; } - std::vector LocalClient::getPendingDeaths() { - auto result = pendingDeaths; - pendingDeaths.clear(); - return result; - } - std::vector LocalClient::getPendingBoxDestructions() { auto result = pendingBoxDestructions; pendingBoxDestructions.clear(); return result; } - } \ No newline at end of file diff --git a/src/network/LocalClient.h b/src/network/LocalClient.h index 32fe19a..c8707a4 100644 --- a/src/network/LocalClient.h +++ b/src/network/LocalClient.h @@ -9,78 +9,79 @@ namespace ZL { - struct LocalServerBox { - Eigen::Vector3f position; - Eigen::Matrix3f rotation; - float collisionRadius = 2.0f; - bool destroyed = false; - }; + struct LocalServerBox { + Eigen::Vector3f position; + Eigen::Matrix3f rotation; + float collisionRadius = 2.0f; + bool destroyed = false; + }; - struct LocalProjectile { - int shooterId = -1; - uint64_t spawnMs = 0; - Eigen::Vector3f pos; - Eigen::Vector3f vel; - float lifeMs = 5000.0f; - }; + struct LocalProjectile { + int shooterId = -1; + uint64_t spawnMs = 0; + Eigen::Vector3f pos; + Eigen::Vector3f vel; + float lifeMs = 5000.0f; + }; - struct LocalNPC { - int id = -1; - ClientState currentState; - ClientStateInterval stateHistory; - Eigen::Vector3f targetPosition; - uint64_t lastStateUpdateMs = 0; - }; + struct LocalNPC { + int id = -1; + ClientState currentState; + ClientStateInterval stateHistory; + Eigen::Vector3f targetPosition; + uint64_t lastStateUpdateMs = 0; + bool destroyed = false; + }; - class LocalClient : public INetworkClient { - private: - std::queue messageQueue; - std::vector serverBoxes; - std::vector projectiles; - std::vector pendingProjectiles; - std::vector pendingDeaths; - std::vector pendingBoxDestructions; - std::vector pendingRespawns; - - uint64_t lastUpdateMs = 0; - ClientState localPlayerState; - bool hasLocalPlayerState = false; - - std::vector npcs; - - void updatePhysics(); - void checkCollisions(); - void generateBoxes(); - void initializeNPCs(); - void updateNPCs(); - Eigen::Vector3f generateRandomPosition(); - - public: - void Connect(const std::string& host, uint16_t port) override; + class LocalClient : public INetworkClient { + private: + std::queue messageQueue; + std::vector serverBoxes; + std::vector projectiles; + std::vector pendingProjectiles; + std::vector pendingDeaths; + std::vector pendingBoxDestructions; + std::vector pendingRespawns; - void Poll() override; + uint64_t lastUpdateMs = 0; + ClientState localPlayerState; + bool hasLocalPlayerState = false; - void Send(const std::string& message) override; + std::vector npcs; - bool IsConnected() const override { return true; } - int GetClientId() const override { return 1; } - std::vector getPendingProjectiles() override; + void updatePhysics(); + void checkCollisions(); + void generateBoxes(); + void initializeNPCs(); + void updateNPCs(); + Eigen::Vector3f generateRandomPosition(); - std::unordered_map getRemotePlayers() override; + public: + void Connect(const std::string& host, uint16_t port) override; - std::vector> getServerBoxes() override; + void Poll() override; - std::vector getPendingDeaths() override; + void Send(const std::string& message) override; - std::vector getPendingRespawns() override { - return {}; - } + bool IsConnected() const override { return true; } + int GetClientId() const override { return 1; } + std::vector getPendingProjectiles() override; - std::vector getPendingBoxDestructions() override; + std::unordered_map getRemotePlayers() override; - void setLocalPlayerState(const ClientState& state) { - localPlayerState = state; - hasLocalPlayerState = true; - } - }; + std::vector> getServerBoxes() override; + + std::vector getPendingDeaths() override; + + std::vector getPendingRespawns() override { + return {}; + } + + std::vector getPendingBoxDestructions() override; + + void setLocalPlayerState(const ClientState& state) { + localPlayerState = state; + hasLocalPlayerState = true; + } + }; } \ No newline at end of file