queue object destruction
This commit is contained in:
@@ -56,6 +56,7 @@ namespace Game {
|
|||||||
static T* getEntityByName(const std::string& name);
|
static T* getEntityByName(const std::string& name);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static void destroyEntity(T* entity);
|
static void destroyEntity(T* entity);
|
||||||
|
static void processPendingEntityRemovals();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mTargetUpdatesPerSecond = TARGET_UPDATE_RATE;
|
int mTargetUpdatesPerSecond = TARGET_UPDATE_RATE;
|
||||||
@@ -140,7 +141,8 @@ namespace Game {
|
|||||||
void GameManager::destroyEntity(T* entity) {
|
void GameManager::destroyEntity(T* entity) {
|
||||||
static_assert(std::is_base_of_v<Object::Entity, T>, "T must derive from Object::Entity");
|
static_assert(std::is_base_of_v<Object::Entity, T>, "T must derive from Object::Entity");
|
||||||
if (entity) {
|
if (entity) {
|
||||||
State::GameState::getInstance().removeEntity(entity->getName());
|
entity->setActive(false);
|
||||||
|
State::GameState::getInstance().queueEntityRemoval(entity->getName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <object/entity.hpp>
|
#include <object/entity.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Game::State {
|
namespace Game::State {
|
||||||
class GameState {
|
class GameState {
|
||||||
@@ -23,6 +24,8 @@ namespace Game::State {
|
|||||||
void wipe();
|
void wipe();
|
||||||
Object::Entity* getEntityByName(const std::string& name); // Get an entity by name, returns nullptr if no entity with the name exists
|
Object::Entity* getEntityByName(const std::string& name); // Get an entity by name, returns nullptr if no entity with the name exists
|
||||||
std::vector<Object::Entity*> getEntitiesSnapshot(bool sortByZIndex = false); // Get a stable snapshot of entity pointers for iteration outside the lock
|
std::vector<Object::Entity*> getEntitiesSnapshot(bool sortByZIndex = false); // Get a stable snapshot of entity pointers for iteration outside the lock
|
||||||
|
void queueEntityRemoval(const std::string& name);
|
||||||
|
void processPendingRemovals();
|
||||||
|
|
||||||
// Add an entity to the gamestate; returns a pointer to the stored entity.
|
// Add an entity to the gamestate; returns a pointer to the stored entity.
|
||||||
Object::Entity* addEntity(std::unique_ptr<Object::Entity> entity);
|
Object::Entity* addEntity(std::unique_ptr<Object::Entity> entity);
|
||||||
@@ -31,5 +34,6 @@ namespace Game::State {
|
|||||||
private:
|
private:
|
||||||
mutable std::mutex mMutex; // Shared mutex for thread safety
|
mutable std::mutex mMutex; // Shared mutex for thread safety
|
||||||
std::unordered_map<std::string, std::unique_ptr<Object::Entity>> mEntityMap; // Own entities while allowing O(1) lookup by name
|
std::unordered_map<std::string, std::unique_ptr<Object::Entity>> mEntityMap; // Own entities while allowing O(1) lookup by name
|
||||||
|
std::vector<std::string> mPendingRemovals;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -15,5 +15,8 @@ namespace Game::AGame {
|
|||||||
void Enemy::onCollisionEnter(Object::Entity* other) {
|
void Enemy::onCollisionEnter(Object::Entity* other) {
|
||||||
LOG("Enemy '" << getName() << "' collided with '" << other->getName() << "' (onCollisionEnter); Killing myself now!");
|
LOG("Enemy '" << getName() << "' collided with '" << other->getName() << "' (onCollisionEnter); Killing myself now!");
|
||||||
GameManager::setSharedData("enemyActiveCount", GameManager::getSharedData<int>("enemyActiveCount") - 1);
|
GameManager::setSharedData("enemyActiveCount", GameManager::getSharedData<int>("enemyActiveCount") - 1);
|
||||||
|
|
||||||
|
// Find in state
|
||||||
|
GameManager::destroyEntity(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,6 +35,9 @@ namespace Game {
|
|||||||
|
|
||||||
// Update components first
|
// Update components first
|
||||||
entity->updateComponents(seconds);
|
entity->updateComponents(seconds);
|
||||||
|
if (!entity->isActive()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
entity->update(seconds);
|
entity->update(seconds);
|
||||||
}
|
}
|
||||||
@@ -42,6 +45,8 @@ namespace Game {
|
|||||||
ERROR("Exception in GameManager thread: " << e.what());
|
ERROR("Exception in GameManager thread: " << e.what());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameManager::processPendingEntityRemovals();
|
||||||
|
|
||||||
mLastDelta = seconds;
|
mLastDelta = seconds;
|
||||||
mLastUpdate = now;
|
mLastUpdate = now;
|
||||||
|
|
||||||
@@ -75,4 +80,8 @@ namespace Game {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameManager::processPendingEntityRemovals() {
|
||||||
|
State::GameState::getInstance().processPendingRemovals();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -82,9 +82,15 @@ namespace Game::Object::Components {
|
|||||||
// Collision detected
|
// Collision detected
|
||||||
if (!mCollidingWith.contains(other)) {
|
if (!mCollidingWith.contains(other)) {
|
||||||
thisEntity->onCollisionEnter(other);
|
thisEntity->onCollisionEnter(other);
|
||||||
|
if (!thisEntity->isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
//other->onCollisionEnter(thisEntity);
|
//other->onCollisionEnter(thisEntity);
|
||||||
} else {
|
} else {
|
||||||
thisEntity->onCollisionStay(other);
|
thisEntity->onCollisionStay(other);
|
||||||
|
if (!thisEntity->isActive()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
//other->onCollisionStay(thisEntity);
|
//other->onCollisionStay(thisEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,25 @@ namespace Game::State {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameState::queueEntityRemoval(const std::string& name) {
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
if (std::find(mPendingRemovals.begin(), mPendingRemovals.end(), name) == mPendingRemovals.end()) {
|
||||||
|
mPendingRemovals.push_back(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameState::processPendingRemovals() {
|
||||||
|
std::vector<std::string> pendingRemovals;
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
|
pendingRemovals = std::move(mPendingRemovals);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& name : pendingRemovals) {
|
||||||
|
removeEntity(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GameState::wipe() {
|
void GameState::wipe() {
|
||||||
std::lock_guard<std::mutex> lock(mMutex);
|
std::lock_guard<std::mutex> lock(mMutex);
|
||||||
for (const auto& pair : mEntityMap) {
|
for (const auto& pair : mEntityMap) {
|
||||||
@@ -39,6 +58,7 @@ namespace Game::State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mEntityMap.clear();
|
mEntityMap.clear();
|
||||||
|
mPendingRemovals.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object::Entity* GameState::getEntityByName(const std::string& name) {
|
Object::Entity* GameState::getEntityByName(const std::string& name) {
|
||||||
|
|||||||
Reference in New Issue
Block a user