Fix issues with components and remove components when entities are destroyed
This commit is contained in:
parent
4e438d3ccc
commit
d8d490bff9
|
@ -200,7 +200,6 @@ void ProxyShapesComponents::addComponent(Entity entity, bool isSleeping, const P
|
||||||
linkProxyShapeWithEntity(entity, index);
|
linkProxyShapeWithEntity(entity, index);
|
||||||
|
|
||||||
assert(mSleepingStartIndex <= mNbComponents);
|
assert(mSleepingStartIndex <= mNbComponents);
|
||||||
|
|
||||||
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index || !hasNextProxyShape(index));
|
assert(mPreviousBodyProxyShapes[mNextBodyProxyShapes[index]] == index || !hasNextProxyShape(index));
|
||||||
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
|
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
|
||||||
}
|
}
|
||||||
|
@ -305,43 +304,6 @@ void ProxyShapesComponents::swapComponents(uint32 index1, uint32 index2) {
|
||||||
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] == index2 || !hasPreviousProxyShape(index2));
|
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index2]] == index2 || !hasPreviousProxyShape(index2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform garbage collection to remove unused components
|
|
||||||
void ProxyShapesComponents::garbageCollection(const EntityManager& entityManager) {
|
|
||||||
|
|
||||||
// TODO : Make sure we call this method each frame
|
|
||||||
|
|
||||||
// We use lazy garbage collection. The idea is to pick random components and destroy
|
|
||||||
// them if their corresponding entities have been destroyed. We do this until we hit
|
|
||||||
// GARBAGE_COLLECTION_MAX_VALID_ENTITIES in a row. Therefore, it cost almost nothing
|
|
||||||
// if there are no destroyed entities and it very quickly destroys components where there
|
|
||||||
// are a lot of destroyed entities.
|
|
||||||
|
|
||||||
uint32 nbHitValidEntitiesInARow = 0;
|
|
||||||
|
|
||||||
// For random number generation
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 eng(rd());
|
|
||||||
|
|
||||||
while (mNbComponents > 0 && nbHitValidEntitiesInARow < GARBAGE_COLLECTION_MAX_VALID_ENTITIES) {
|
|
||||||
|
|
||||||
// Select a random index in the components array
|
|
||||||
std::uniform_int_distribution<uint32> distr(0, mNbComponents - 1);
|
|
||||||
uint32 i = distr(eng);
|
|
||||||
|
|
||||||
// If the corresponding entity is valid
|
|
||||||
if (entityManager.isValid(mEntities[i])) {
|
|
||||||
nbHitValidEntitiesInARow++;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbHitValidEntitiesInARow = 0;
|
|
||||||
|
|
||||||
// Destroy the component
|
|
||||||
removeComponent(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a component at a given index
|
// Remove a component at a given index
|
||||||
void ProxyShapesComponents::removeComponent(uint32 index) {
|
void ProxyShapesComponents::removeComponent(uint32 index) {
|
||||||
|
|
||||||
|
@ -430,12 +392,13 @@ void ProxyShapesComponents::removeComponent(uint32 index) {
|
||||||
if (mSleepingStartIndex != mNbComponents) {
|
if (mSleepingStartIndex != mNbComponents) {
|
||||||
|
|
||||||
// We replace the last awake component by the last sleeping component
|
// We replace the last awake component by the last sleeping component
|
||||||
moveComponentToIndex(mNbComponents - 1, index);
|
moveComponentToIndex(mNbComponents - 1, mSleepingStartIndex - 1);
|
||||||
|
|
||||||
mSleepingStartIndex--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSleepingStartIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(mSleepingStartIndex <= mNbComponents);
|
||||||
mNbComponents--;
|
mNbComponents--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,6 +417,7 @@ bool ProxyShapesComponents::hasNextProxyShape(uint32 index) const {
|
||||||
// Destroy a component at a given index
|
// Destroy a component at a given index
|
||||||
void ProxyShapesComponents::destroyComponent(uint32 index) {
|
void ProxyShapesComponents::destroyComponent(uint32 index) {
|
||||||
|
|
||||||
|
assert(index < mNbComponents);
|
||||||
|
|
||||||
mEntities[index].~Entity();
|
mEntities[index].~Entity();
|
||||||
mLocalBounds[index].~AABB();
|
mLocalBounds[index].~AABB();
|
||||||
|
@ -500,3 +464,19 @@ void ProxyShapesComponents::setIsEntitySleeping(Entity entity, bool isSleeping)
|
||||||
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
|
assert(mNextBodyProxyShapes[mPreviousBodyProxyShapes[index]] == index || !hasPreviousProxyShape(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all the components of a given entity
|
||||||
|
void ProxyShapesComponents::removeComponents(Entity entity) {
|
||||||
|
|
||||||
|
auto it = mMapEntityToComponentIndex.find(entity);
|
||||||
|
|
||||||
|
// While there are components for this entity
|
||||||
|
while (it != mMapEntityToComponentIndex.end()) {
|
||||||
|
|
||||||
|
// Remove the component
|
||||||
|
removeComponent(it->second);
|
||||||
|
|
||||||
|
it = mMapEntityToComponentIndex.find(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!mMapEntityToComponentIndex.containsKey(entity));
|
||||||
|
}
|
||||||
|
|
|
@ -169,11 +169,11 @@ class ProxyShapesComponents {
|
||||||
/// Add a component
|
/// Add a component
|
||||||
void addComponent(Entity entity, bool isSleeping, const ProxyShapeComponent& component);
|
void addComponent(Entity entity, bool isSleeping, const ProxyShapeComponent& component);
|
||||||
|
|
||||||
|
/// Remove all the components of a given entity
|
||||||
|
void removeComponents(Entity entity);
|
||||||
|
|
||||||
/// Notify if a given entity is sleeping or not
|
/// Notify if a given entity is sleeping or not
|
||||||
void setIsEntitySleeping(Entity entity, bool isSleeping);
|
void setIsEntitySleeping(Entity entity, bool isSleeping);
|
||||||
|
|
||||||
/// Perform garbage collection to remove unused components
|
|
||||||
void garbageCollection(const EntityManager& entityManager);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,45 +140,6 @@ void TransformComponents::addComponent(Entity entity, bool isSleeping, const Tra
|
||||||
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
|
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform garbage collection to remove unused components
|
|
||||||
void TransformComponents::garbageCollection(const EntityManager& entityManager) {
|
|
||||||
|
|
||||||
// TODO : Make sure we call this method each frame
|
|
||||||
|
|
||||||
// We use lazy garbage collection. The idea is to pick random components and destroy
|
|
||||||
// them if their corresponding entities have been destroyed. We do this until we hit
|
|
||||||
// GARBAGE_COLLECTION_MAX_VALID_ENTITIES in a row. Therefore, it cost almost nothing
|
|
||||||
// if there are no destroyed entities and it very quickly destroys components where there
|
|
||||||
// are a lot of destroyed entities.
|
|
||||||
|
|
||||||
uint32 nbHitValidEntitiesInARow = 0;
|
|
||||||
|
|
||||||
// For random number generation
|
|
||||||
std::random_device rd;
|
|
||||||
std::mt19937 eng(rd());
|
|
||||||
|
|
||||||
while (mNbComponents > 0 && nbHitValidEntitiesInARow < GARBAGE_COLLECTION_MAX_VALID_ENTITIES) {
|
|
||||||
|
|
||||||
// Select a random index in the components array
|
|
||||||
std::uniform_int_distribution<uint32> distr(0, mNbComponents - 1);
|
|
||||||
uint32 i = distr(eng);
|
|
||||||
|
|
||||||
// If the corresponding entity is valid
|
|
||||||
if (entityManager.isValid(mEntities[i])) {
|
|
||||||
nbHitValidEntitiesInARow++;
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
nbHitValidEntitiesInARow = 0;
|
|
||||||
|
|
||||||
// Destroy the component
|
|
||||||
removeComponent(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove a component at a given index
|
// Remove a component at a given index
|
||||||
void TransformComponents::removeComponent(uint32 index) {
|
void TransformComponents::removeComponent(uint32 index) {
|
||||||
|
|
||||||
|
@ -214,14 +175,15 @@ void TransformComponents::removeComponent(uint32 index) {
|
||||||
if (mSleepingStartIndex != mNbComponents) {
|
if (mSleepingStartIndex != mNbComponents) {
|
||||||
|
|
||||||
// We replace the last awake component by the last sleeping component
|
// We replace the last awake component by the last sleeping component
|
||||||
moveComponentToIndex(mNbComponents - 1, index);
|
moveComponentToIndex(mNbComponents - 1, mSleepingStartIndex - 1);
|
||||||
|
|
||||||
mSleepingStartIndex--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mSleepingStartIndex--;
|
||||||
}
|
}
|
||||||
|
|
||||||
mNbComponents--;
|
mNbComponents--;
|
||||||
|
|
||||||
|
assert(mSleepingStartIndex <= mNbComponents);
|
||||||
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
|
assert(mNbComponents == static_cast<uint32>(mMapEntityToComponentIndex.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,8 +271,26 @@ void TransformComponents::swapComponents(uint32 index1, uint32 index2) {
|
||||||
// Destroy a component at a given index
|
// Destroy a component at a given index
|
||||||
void TransformComponents::destroyComponent(uint32 index) {
|
void TransformComponents::destroyComponent(uint32 index) {
|
||||||
|
|
||||||
|
assert(index < mNbComponents);
|
||||||
|
assert(mMapEntityToComponentIndex[mEntities[index]] == index);
|
||||||
|
|
||||||
mMapEntityToComponentIndex.remove(mEntities[index]);
|
mMapEntityToComponentIndex.remove(mEntities[index]);
|
||||||
|
|
||||||
mEntities[index].~Entity();
|
mEntities[index].~Entity();
|
||||||
mTransforms[index].~Transform();
|
mTransforms[index].~Transform();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove all the components of a given entity
|
||||||
|
void TransformComponents::removeComponents(Entity entity) {
|
||||||
|
|
||||||
|
auto it = mMapEntityToComponentIndex.find(entity);
|
||||||
|
|
||||||
|
// If there is a component for this entity
|
||||||
|
if (it != mMapEntityToComponentIndex.end()) {
|
||||||
|
|
||||||
|
// Remove the component
|
||||||
|
removeComponent(it->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(!mMapEntityToComponentIndex.containsKey(entity));
|
||||||
|
}
|
||||||
|
|
|
@ -105,8 +105,8 @@ class TransformComponents : public Components {
|
||||||
/// Add a component
|
/// Add a component
|
||||||
void addComponent(Entity entity, bool isSleeping, const TransformComponent& component);
|
void addComponent(Entity entity, bool isSleeping, const TransformComponent& component);
|
||||||
|
|
||||||
/// Perform garbage collection to remove unused components
|
/// Remove all the components of a given entity
|
||||||
void garbageCollection(const EntityManager& entityManager);
|
void removeComponents(Entity entity);
|
||||||
|
|
||||||
/// Return the transform of an entity
|
/// Return the transform of an entity
|
||||||
Transform& getTransform(Entity entity) const;
|
Transform& getTransform(Entity entity) const;
|
||||||
|
|
|
@ -197,8 +197,8 @@ void CollisionWorld::destroyCollisionBody(CollisionBody* collisionBody) {
|
||||||
// Reset the contact manifold list of the body
|
// Reset the contact manifold list of the body
|
||||||
collisionBody->resetContactManifoldsList();
|
collisionBody->resetContactManifoldsList();
|
||||||
|
|
||||||
// Destroy the corresponding entity
|
// Destroy the entity and its components
|
||||||
mEntityManager.destroyEntity(collisionBody->getEntity());
|
destroyEntity(collisionBody->getEntity());
|
||||||
|
|
||||||
// Call the destructor of the collision body
|
// Call the destructor of the collision body
|
||||||
collisionBody->~CollisionBody();
|
collisionBody->~CollisionBody();
|
||||||
|
@ -248,6 +248,19 @@ void CollisionWorld::notifyBodySleeping(Entity entity, bool isSleeping) {
|
||||||
mProxyShapesComponents.setIsEntitySleeping(entity, isSleeping);
|
mProxyShapesComponents.setIsEntitySleeping(entity, isSleeping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Destroy an entity and all the associated components
|
||||||
|
void CollisionWorld::destroyEntity(Entity entity) {
|
||||||
|
|
||||||
|
// Destroy the corresponding entity
|
||||||
|
mEntityManager.destroyEntity(entity);
|
||||||
|
|
||||||
|
// TODO : Make sure we notify all the components here ...
|
||||||
|
|
||||||
|
// Notify all the components
|
||||||
|
mTransformComponents.removeComponents(entity);
|
||||||
|
mProxyShapesComponents.removeComponents(entity);
|
||||||
|
}
|
||||||
|
|
||||||
// Test if the AABBs of two bodies overlap
|
// Test if the AABBs of two bodies overlap
|
||||||
/**
|
/**
|
||||||
* @param body1 Pointer to the first body to test
|
* @param body1 Pointer to the first body to test
|
||||||
|
|
|
@ -128,6 +128,9 @@ class CollisionWorld {
|
||||||
/// Notify the world if a body is sleeping or not
|
/// Notify the world if a body is sleeping or not
|
||||||
void notifyBodySleeping(Entity entity, bool isSleeping);
|
void notifyBodySleeping(Entity entity, bool isSleeping);
|
||||||
|
|
||||||
|
/// Destroy an entity and all the associated components
|
||||||
|
void destroyEntity(Entity entity);
|
||||||
|
|
||||||
public :
|
public :
|
||||||
|
|
||||||
// -------------------- Methods -------------------- //
|
// -------------------- Methods -------------------- //
|
||||||
|
|
|
@ -479,8 +479,8 @@ void DynamicsWorld::destroyRigidBody(RigidBody* rigidBody) {
|
||||||
// Reset the contact manifold list of the body
|
// Reset the contact manifold list of the body
|
||||||
rigidBody->resetContactManifoldsList();
|
rigidBody->resetContactManifoldsList();
|
||||||
|
|
||||||
// Destroy the corresponding entity
|
// Destroy the corresponding entity and its components
|
||||||
mEntityManager.destroyEntity(rigidBody->getEntity());
|
destroyEntity(rigidBody->getEntity());
|
||||||
|
|
||||||
// Call the destructor of the rigid body
|
// Call the destructor of the rigid body
|
||||||
rigidBody->~RigidBody();
|
rigidBody->~RigidBody();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user