added npc destroy

This commit is contained in:
Vlad 2026-02-13 15:40:40 +06:00
parent 9793c5bf06
commit a8700af1d0
3 changed files with 126 additions and 78 deletions

View File

@ -849,6 +849,7 @@ namespace ZL
for (auto const& [id, remotePlayer] : remotePlayerStates)
{
if (deadRemotePlayers.count(id)) continue;
//<<<<<<< HEAD
const ClientState& st = remotePlayer;

View File

@ -94,6 +94,7 @@ namespace ZL {
npc.targetPosition = generateRandomPosition();
npc.lastStateUpdateMs = std::chrono::duration_cast<std::chrono::milliseconds>(
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;
@ -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<std::pair<size_t, size_t>> boxProjectileCollisions;
@ -273,6 +277,47 @@ namespace ZL {
}
}
std::vector<std::pair<size_t, size_t>> 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<int>(projIdx));
}
}
}
if (!projIndicesToRemove.empty()) {
std::sort(projIndicesToRemove.rbegin(), projIndicesToRemove.rend());
for (int idx : projIndicesToRemove) {
@ -317,7 +362,7 @@ namespace ZL {
tokens.push_back(token);
}
return tokens;
}(message, ':');
}(message, ':');
if (parts.empty()) return;
@ -384,10 +429,18 @@ namespace ZL {
return result;
}
std::vector<DeathInfo> LocalClient::getPendingDeaths() {
auto result = pendingDeaths;
pendingDeaths.clear();
return result;
}
std::unordered_map<int, ClientStateInterval> LocalClient::getRemotePlayers() {
std::unordered_map<int, ClientStateInterval> 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<DeathInfo> LocalClient::getPendingDeaths() {
auto result = pendingDeaths;
pendingDeaths.clear();
return result;
}
std::vector<BoxDestroyedInfo> LocalClient::getPendingBoxDestructions() {
auto result = pendingBoxDestructions;
pendingBoxDestructions.clear();
return result;
}
}

View File

@ -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<std::string> messageQueue;
std::vector<LocalServerBox> serverBoxes;
std::vector<LocalProjectile> projectiles;
std::vector<ProjectileInfo> pendingProjectiles;
std::vector<DeathInfo> pendingDeaths;
std::vector<BoxDestroyedInfo> pendingBoxDestructions;
std::vector<int> pendingRespawns;
class LocalClient : public INetworkClient {
private:
std::queue<std::string> messageQueue;
std::vector<LocalServerBox> serverBoxes;
std::vector<LocalProjectile> projectiles;
std::vector<ProjectileInfo> pendingProjectiles;
std::vector<DeathInfo> pendingDeaths;
std::vector<BoxDestroyedInfo> pendingBoxDestructions;
std::vector<int> pendingRespawns;
uint64_t lastUpdateMs = 0;
ClientState localPlayerState;
bool hasLocalPlayerState = false;
uint64_t lastUpdateMs = 0;
ClientState localPlayerState;
bool hasLocalPlayerState = false;
std::vector<LocalNPC> npcs;
std::vector<LocalNPC> npcs;
void updatePhysics();
void checkCollisions();
void generateBoxes();
void initializeNPCs();
void updateNPCs();
Eigen::Vector3f generateRandomPosition();
void updatePhysics();
void checkCollisions();
void generateBoxes();
void initializeNPCs();
void updateNPCs();
Eigen::Vector3f generateRandomPosition();
public:
void Connect(const std::string& host, uint16_t port) override;
public:
void Connect(const std::string& host, uint16_t port) override;
void Poll() override;
void Poll() override;
void Send(const std::string& message) override;
void Send(const std::string& message) override;
bool IsConnected() const override { return true; }
int GetClientId() const override { return 1; }
std::vector<ProjectileInfo> getPendingProjectiles() override;
bool IsConnected() const override { return true; }
int GetClientId() const override { return 1; }
std::vector<ProjectileInfo> getPendingProjectiles() override;
std::unordered_map<int, ClientStateInterval> getRemotePlayers() override;
std::unordered_map<int, ClientStateInterval> getRemotePlayers() override;
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override;
std::vector<std::pair<Eigen::Vector3f, Eigen::Matrix3f>> getServerBoxes() override;
std::vector<DeathInfo> getPendingDeaths() override;
std::vector<DeathInfo> getPendingDeaths() override;
std::vector<int> getPendingRespawns() override {
return {};
}
std::vector<int> getPendingRespawns() override {
return {};
}
std::vector<BoxDestroyedInfo> getPendingBoxDestructions() override;
std::vector<BoxDestroyedInfo> getPendingBoxDestructions() override;
void setLocalPlayerState(const ClientState& state) {
localPlayerState = state;
hasLocalPlayerState = true;
}
};
void setLocalPlayerState(const ClientState& state) {
localPlayerState = state;
hasLocalPlayerState = true;
}
};
}