EntitySimulation takes EntityItem* rather than ID

This commit is contained in:
Andrew Meadows 2014-11-26 12:12:43 -08:00
parent 0d98555740
commit dd3a7b9b9d
10 changed files with 162 additions and 292 deletions

View file

@ -48,9 +48,6 @@ void DeleteEntityOperator::addEntityIDToDeleteList(const EntityItemID& searchEnt
details.cube = details.containingElement->getAACube();
_entitiesToDelete << details;
_lookingCount++;
_tree->trackDeletedEntity(searchEntityID);
// before deleting any entity make sure to remove it from our Mortal, Changing, and Moving lists
_tree->removeEntityFromSimulationLists(searchEntityID);
}
}
}
@ -78,13 +75,9 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) {
EntityTreeElement* entityTreeElement = static_cast<EntityTreeElement*>(element);
// In Pre-recursion, we're generally deciding whether or not we want to recurse this
// path of the tree. For this operation, we want to recurse the branch of the tree if
// and of the following are true:
// * We have not yet found the old entity, and this branch contains our old entity
// * We have not yet found the new entity, and this branch contains our new entity
//
// Note: it's often the case that the branch in question contains both the old entity
// and the new entity.
// path of the tree. For this operation, we want to recurse the branch of the tree if:
// * We have not yet found the all entities, and
// * this branch contains our some of the entities we're looking for.
bool keepSearching = false; // assume we don't need to search any more
@ -100,6 +93,8 @@ bool DeleteEntityOperator::preRecursion(OctreeElement* element) {
if (entityTreeElement == details.containingElement) {
EntityItemID entityItemID = details.entity->getEntityItemID();
EntityItem* theEntity = entityTreeElement->getEntityWithEntityItemID(entityItemID); // find the actual entity
assert(theEntity);
_tree->trackDeletedEntity(theEntity);
entityTreeElement->removeEntityItem(theEntity); // remove it from the element
_tree->setContainingElement(entityItemID, NULL); // update or id to element lookup
delete theEntity; // now actually delete the entity!

View file

@ -0,0 +1,20 @@
//
// EntitySimulation.cpp
// libraries/entities/src
//
// Created by Andrew Meadows on 2014.11.24
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "EntitySimulation.h"
void EntitySimulation::setEntityTree(EntityTree* tree) {
if (_entityTree && _entityTree != tree) {
clearEntities();
}
_entityTree = tree;
}

View file

@ -14,24 +14,36 @@
#include <QSet>
#include "EntityItemID.h"
#include "EntityTree.h"
class EntitySimulation {
public:
EntitySimulation(EntityTree* tree) : _myTree(tree) { assert(tree); }
virtual ~EntitySimulation() { _myTree = NULL; }
EntitySimulation() : _entityTree(NULL) { }
virtual ~EntitySimulation() {}
/// \sideeffect For each EntityItem* that EntitySimulation puts on entitiesToDelete it will automatically
/// removeEntity() on any internal lists -- no need to call removeEntity() for that one later.
virtual void update(QSet<EntityItemID>& entitiesToDelete) = 0;
/// \param tree pointer to EntityTree which is stored internally
virtual void setEntityTree(EntityTree* tree);
/// \param[out] entitiesToDelete list of entities removed from simulation and should be deleted.
virtual void update(QSet<EntityItem*>& entitiesToDelete) = 0;
/// \param entity pointer to EntityItem to add to the simulation
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate membership to internal list
virtual void addEntity(EntityItem* entity) = 0;
/// \param entity pointer to EntityItem to removed from the simulation
/// \sideeffect the EntityItem::_simulationState member may be updated to indicate non-membership to internal list
virtual void removeEntity(EntityItem* entity) = 0;
virtual void updateEntity(EntityItem* entity) = 0;
/// \param entity pointer to EntityItem to that may have changed in a way that would affect its simulation
virtual void entityChanged(EntityItem* entity) = 0;
virtual void clearEntities() = 0;
EntityTree* getEntityTree() { return _entityTree; }
protected:
EntityTree* _myTree;
EntityTree* _entityTree;
};
#endif // hifi_EntitySimulation_h

View file

@ -12,13 +12,14 @@
#include <PerfStat.h>
#include "EntityTree.h"
#include "EntitySimulation.h"
#include "AddEntityOperator.h"
#include "DeleteEntityOperator.h"
#include "MovingEntitiesOperator.h"
#include "UpdateEntityOperator.h"
EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage) {
EntityTree::EntityTree(bool shouldReaverage) : Octree(shouldReaverage), _simulation(NULL) {
_rootElement = createNewElement();
}
@ -34,14 +35,14 @@ EntityTreeElement* EntityTree::createNewElement(unsigned char * octalCode) {
void EntityTree::eraseAllOctreeElements(bool createNewRoot) {
// this would be a good place to clean up our entities...
if (_simulation) {
_simulation->clearEntities();
}
foreach (EntityTreeElement* element, _entityToElementMap) {
element->cleanupEntities();
}
_entityToElementMap.clear();
Octree::eraseAllOctreeElements(createNewRoot);
_movingEntities.clear();
_mortalEntities.clear();
_changedEntities.clear();
}
bool EntityTree::handlesEditPacketType(PacketType packetType) const {
@ -89,13 +90,14 @@ void EntityTree::addEntityItem(EntityItem* entityItem) {
recurseTreeWithOperator(&theOperator);
// check to see if we need to simulate this entity..
updateEntityState(entityItem);
if (_simulation) {
_simulation->addEntity(entityItem);
}
_isDirty = true;
}
bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties) {
// You should not call this on existing entities that are already part of the tree! Call updateEntity()
EntityTreeElement* containingElement = getContainingElement(entityID);
if (!containingElement) {
qDebug() << "UNEXPECTED!!!! EntityTree::updateEntity() entityID doesn't exist!!! entityID=" << entityID;
@ -119,6 +121,9 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
UpdateEntityOperator theOperator(this, containingElement, existingEntity, tempProperties);
recurseTreeWithOperator(&theOperator);
_isDirty = true;
if (_simulation && existingEntity->getUpdateFlags() != 0) {
_simulation->entityChanged(existingEntity);
}
}
}
} else {
@ -129,13 +134,14 @@ bool EntityTree::updateEntity(const EntityItemID& entityID, const EntityItemProp
recurseTreeWithOperator(&theOperator);
_isDirty = true;
updateEntityState(existingEntity);
if (_simulation && existingEntity->getUpdateFlags() != 0) {
_simulation->entityChanged(existingEntity);
}
QString entityScriptAfter = existingEntity->getScript();
if (entityScriptBefore != entityScriptAfter) {
emitEntityScriptChanging(entityID); // the entity script has changed
}
}
containingElement = getContainingElement(entityID);
@ -179,13 +185,16 @@ EntityItem* EntityTree::addEntity(const EntityItemID& entityID, const EntityItem
}
void EntityTree::trackDeletedEntity(const EntityItemID& entityID) {
void EntityTree::trackDeletedEntity(EntityItem* entity) {
if (_simulation) {
_simulation->removeEntity(entity);
}
// this is only needed on the server to send delete messages for recently deleted entities to the viewers
if (getIsServer()) {
// set up the deleted entities ID
quint64 deletedAt = usecTimestampNow();
_recentlyDeletedEntitiesLock.lockForWrite();
_recentlyDeletedEntityItemIDs.insert(deletedAt, entityID.id);
_recentlyDeletedEntityItemIDs.insert(deletedAt, entity->getEntityItemID().id);
_recentlyDeletedEntitiesLock.unlock();
}
}
@ -198,6 +207,19 @@ void EntityTree::emitEntityScriptChanging(const EntityItemID& entityItemID) {
emit entityScriptChanging(entityItemID);
}
void EntityTree::setSimulation(EntitySimulation* simulation) {
if (simulation) {
// assert that the simulation's backpointer has already been properly connected
assert(simulation->getEntityTree() == this);
}
if (_simulation && _simulation != simulation) {
// It's important to clearEntities() on the simulation since taht will update each
// EntityItem::_simulationState correctly so as to not confuse the next _simulation.
_simulation->clearEntities();
}
_simulation = simulation;
}
void EntityTree::deleteEntity(const EntityItemID& entityID) {
emit deletingEntity(entityID);
@ -220,29 +242,6 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs) {
_isDirty = true;
}
void EntityTree::removeEntityFromSimulationLists(const EntityItemID& entityID) {
EntityItem* theEntity = findEntityByEntityItemID(entityID);
if (theEntity) {
// make sure to remove it from any of our simulation lists
EntityItem::SimulationState theState = theEntity->getSimulationState();
switch (theState) {
case EntityItem::Moving:
_movingEntities.removeAll(theEntity);
break;
case EntityItem::Mortal:
_mortalEntities.removeAll(theEntity);
break;
default:
break;
}
_changedEntities.remove(theEntity);
}
}
/// This method is used to find and fix entity IDs that are shifting from creator token based to known ID based entity IDs.
/// This should only be used on a client side (viewing) tree. The typical usage is that a local editor has been creating
/// entities in the local tree, those entities have creatorToken based entity IDs. But those entity edits are also sent up to
@ -575,183 +574,29 @@ void EntityTree::releaseSceneEncodeData(OctreeElementExtraEncodeData* extraEncod
extraEncodeData->clear();
}
void EntityTree::updateEntityState(EntityItem* entity) {
EntityItem::SimulationState oldState = entity->getSimulationState();
EntityItem::SimulationState newState = entity->computeSimulationState();
if (newState != oldState) {
switch (oldState) {
case EntityItem::Moving:
_movingEntities.removeAll(entity);
break;
case EntityItem::Mortal:
_mortalEntities.removeAll(entity);
break;
default:
break;
}
switch (newState) {
case EntityItem::Moving:
_movingEntities.push_back(entity);
break;
case EntityItem::Mortal:
_mortalEntities.push_back(entity);
break;
default:
break;
}
entity->setSimulationState(newState);
}
}
void EntityTree::clearEntityState(EntityItem* entity) {
EntityItem::SimulationState oldState = entity->getSimulationState();
switch (oldState) {
case EntityItem::Moving:
_movingEntities.removeAll(entity);
break;
case EntityItem::Mortal:
_mortalEntities.removeAll(entity);
break;
default:
break;
}
entity->setSimulationState(EntityItem::Static);
}
void EntityTree::entityChanged(EntityItem* entity) {
_changedEntities.insert(entity);
if (_simulation) {
_simulation->entityChanged(entity);
}
}
void EntityTree::update() {
// our new strategy should be to segregate entities into three classes:
// 1) stationary things that are not changing - most models
// 2) mortal things - these are stationary but have a lifetime - then need to be checked,
// can be touched linearly, and won't change the tree
// 2) changing things - like things animating they can be touched linearly and they don't change the tree
// 3) moving things - these need to scan the tree and update accordingly
// finally - all things that need to be deleted, can be handled on a single delete pass.
//
// TODO: theoretically we could combine the move and delete tree passes...
lockForWrite();
quint64 now = usecTimestampNow();
QSet<EntityItemID> entitiesToDelete;
updateChangedEntities(now, entitiesToDelete);
updateMovingEntities(now, entitiesToDelete);
updateMortalEntities(now, entitiesToDelete);
if (entitiesToDelete.size() > 0) {
deleteEntities(entitiesToDelete);
}
unlock();
}
void EntityTree::updateChangedEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
foreach (EntityItem* thisEntity, _changedEntities) {
// check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
entitiesToDelete << thisEntity->getEntityItemID();
clearEntityState(thisEntity);
} else {
updateEntityState(thisEntity);
}
thisEntity->clearUpdateFlags();
}
_changedEntities.clear();
}
void EntityTree::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
PerformanceTimer perfTimer("updateMovingEntities");
if (_movingEntities.size() > 0) {
MovingEntitiesOperator moveOperator(this);
{
PerformanceTimer perfTimer("_movingEntities");
QList<EntityItem*>::iterator item_itr = _movingEntities.begin();
while (item_itr != _movingEntities.end()) {
EntityItem* thisEntity = *item_itr;
// always check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
} else {
AACube oldCube = thisEntity->getMaximumAACube();
thisEntity->update(now);
AACube newCube = thisEntity->getMaximumAACube();
// check to see if this movement has sent the entity outside of the domain.
AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f);
if (!domainBounds.touches(newCube)) {
qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds.";
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
} else {
moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube);
EntityItem::SimulationState newState = thisEntity->computeSimulationState();
if (newState != EntityItem::Moving) {
if (newState == EntityItem::Mortal) {
_mortalEntities.push_back(thisEntity);
}
// remove thisEntity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(newState);
} else {
++item_itr;
}
}
}
if (_simulation) {
lockForWrite();
QSet<EntityItem*> entitiesToDelete;
_simulation->update(entitiesToDelete);
if (entitiesToDelete.size() > 0) {
// translate into list of ID's
QSet<EntityItemID> idsToDelete;
foreach (EntityItem* entity, entitiesToDelete) {
idsToDelete.insert(entity->getEntityItemID());
}
deleteEntities(idsToDelete);
}
if (moveOperator.hasMovingEntities()) {
PerformanceTimer perfTimer("recurseTreeWithOperator");
recurseTreeWithOperator(&moveOperator);
}
unlock();
}
}
void EntityTree::updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
QList<EntityItem*>::iterator item_itr = _mortalEntities.begin();
while (item_itr != _mortalEntities.end()) {
EntityItem* thisEntity = *item_itr;
thisEntity->update(now);
// always check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
item_itr = _mortalEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
} else {
// check to see if this entity is no longer moving
EntityItem::SimulationState newState = thisEntity->computeSimulationState();
if (newState != EntityItem::Mortal) {
if (newState == EntityItem::Moving) {
_movingEntities.push_back(thisEntity);
}
// remove thisEntity from the list
item_itr = _mortalEntities.erase(item_itr);
thisEntity->setSimulationState(newState);
} else {
++item_itr;
}
}
}
}
bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) {
// we can probably leverage the ordered nature of QMultiMap to do this quickly...
bool hasSomethingNewer = false;
@ -966,19 +811,16 @@ int EntityTree::processEraseMessageDetails(const QByteArray& dataByteArray, cons
EntityTreeElement* EntityTree::getContainingElement(const EntityItemID& entityItemID) /*const*/ {
// TODO: do we need to make this thread safe? Or is it acceptable as is
if (_entityToElementMap.contains(entityItemID)) {
return _entityToElementMap.value(entityItemID);
} else if (entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){
EntityTreeElement* element = _entityToElementMap.value(entityItemID);
if (!element && entityItemID.creatorTokenID != UNKNOWN_ENTITY_TOKEN){
// check the creator token version too...
EntityItemID creatorTokenOnly;
creatorTokenOnly.id = UNKNOWN_ENTITY_ID;
creatorTokenOnly.creatorTokenID = entityItemID.creatorTokenID;
creatorTokenOnly.isKnownID = false;
if (_entityToElementMap.contains(creatorTokenOnly)) {
return _entityToElementMap.value(creatorTokenOnly);
}
element = _entityToElementMap.value(creatorTokenOnly);
}
return NULL;
return element;
}
// TODO: do we need to make this thread safe? Or is it acceptable as is

View file

@ -19,6 +19,7 @@
class Model;
class EntitySimulation;
class NewlyCreatedEntityHook {
public:
@ -84,7 +85,7 @@ public:
bool updateEntity(const EntityItemID& entityID, const EntityItemProperties& properties);
void deleteEntity(const EntityItemID& entityID);
void deleteEntities(QSet<EntityItemID> entityIDs);
void removeEntityFromSimulationLists(const EntityItemID& entityID);
void removeEntityFromSimulation(EntityItem* entity);
const EntityItem* findClosestEntity(glm::vec3 position, float targetRadius);
EntityItem* findEntityByID(const QUuid& id);
@ -137,18 +138,15 @@ public:
void sendEntities(EntityEditPacketSender* packetSender, EntityTree* localTree, float x, float y, float z);
void updateEntityState(EntityItem* entity);
void clearEntityState(EntityItem* entity);
void entityChanged(EntityItem* entity);
void trackDeletedEntity(const EntityItemID& entityID);
void trackDeletedEntity(EntityItem* entity);
void emitAddingEntity(const EntityItemID& entityItemID);
void emitEntityScriptChanging(const EntityItemID& entityItemID);
QList<EntityItem*>& getMovingEntities() { return _movingEntities; }
void setSimulation(EntitySimulation* simulation);
signals:
void deletingEntity(const EntityItemID& entityID);
void addingEntity(const EntityItemID& entityID);
@ -157,10 +155,6 @@ signals:
private:
void updateChangedEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
void updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
void updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
static bool findNearPointOperation(OctreeElement* element, void* extraData);
static bool findInSphereOperation(OctreeElement* element, void* extraData);
static bool findInCubeOperation(OctreeElement* element, void* extraData);
@ -176,11 +170,7 @@ private:
EntityItemFBXService* _fbxService;
QHash<EntityItemID, EntityTreeElement*> _entityToElementMap;
QList<EntityItem*> _movingEntities; // entities that need to be updated
QList<EntityItem*> _mortalEntities; // entities that need to be checked for expiry
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
EntitySimulation* _simulation;
};
#endif // hifi_EntityTree_h

View file

@ -768,7 +768,6 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int
addEntityItem(entityItem); // add this new entity to this elements entities
entityItemID = entityItem->getEntityItemID();
_myTree->setContainingElement(entityItemID, this);
_myTree->updateEntityState(entityItem);
_myTree->emitAddingEntity(entityItemID); // we just added an entity
}
}

View file

@ -16,7 +16,7 @@
#include "MovingEntitiesOperator.h"
#include "SimpleEntitySimulation.h"
void SimpleEntitySimulation::update(QSet<EntityItemID>& entitiesToDelete) {
void SimpleEntitySimulation::update(QSet<EntityItem*>& entitiesToDelete) {
quint64 now = usecTimestampNow();
updateChangedEntities(now, entitiesToDelete);
updateMovingEntities(now, entitiesToDelete);
@ -56,21 +56,32 @@ void SimpleEntitySimulation::removeEntity(EntityItem* entity) {
default:
break;
}
entity->setSimulationState(EntityItem::Static);
_changedEntities.remove(entity);
}
void SimpleEntitySimulation::updateEntity(EntityItem* entity) {
void SimpleEntitySimulation::entityChanged(EntityItem* entity) {
assert(entity);
// we'll deal with thsi change later
// we batch all changes and deal with them in updateChangedEntities()
_changedEntities.insert(entity);
}
void SimpleEntitySimulation::clearEntities() {
foreach (EntityItem* entity, _changedEntities) {
entity->clearUpdateFlags();
entity->setSimulationState(EntityItem::Static);
}
_changedEntities.clear();
_movingEntities.clear();
_mortalEntities.clear();
}
void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete) {
foreach (EntityItem* entity, _changedEntities) {
// check to see if the lifetime has expired, for immortal entities this is always false
if (entity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID();
entitiesToDelete << entity->getEntityItemID();
entitiesToDelete.insert(entity);
clearEntityState(entity);
} else {
updateEntityState(entity);
@ -80,44 +91,44 @@ void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet<EntityItemI
_changedEntities.clear();
}
void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
if (_movingEntities.size() > 0) {
void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete) {
if (_entityTree && _movingEntities.size() > 0) {
PerformanceTimer perfTimer("_movingEntities");
MovingEntitiesOperator moveOperator(_myTree);
MovingEntitiesOperator moveOperator(_entityTree);
QList<EntityItem*>::iterator item_itr = _movingEntities.begin();
while (item_itr != _movingEntities.end()) {
EntityItem* thisEntity = *item_itr;
EntityItem* entity = *item_itr;
// always check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
if (entity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID();
entitiesToDelete.insert(entity);
// remove entity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
entity->setSimulationState(EntityItem::Static);
} else {
AACube oldCube = thisEntity->getMaximumAACube();
thisEntity->update(now);
AACube newCube = thisEntity->getMaximumAACube();
AACube oldCube = entity->getMaximumAACube();
entity->update(now);
AACube newCube = entity->getMaximumAACube();
// check to see if this movement has sent the entity outside of the domain.
AACube domainBounds(glm::vec3(0.0f,0.0f,0.0f), 1.0f);
if (!domainBounds.touches(newCube)) {
qDebug() << "Entity " << thisEntity->getEntityItemID() << " moved out of domain bounds.";
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
qDebug() << "Entity " << entity->getEntityItemID() << " moved out of domain bounds.";
entitiesToDelete.insert(entity);
// remove entity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
entity->setSimulationState(EntityItem::Static);
} else {
moveOperator.addEntityToMoveList(thisEntity, oldCube, newCube);
EntityItem::SimulationState newState = thisEntity->computeSimulationState();
moveOperator.addEntityToMoveList(entity, oldCube, newCube);
EntityItem::SimulationState newState = entity->computeSimulationState();
if (newState != EntityItem::Moving) {
if (newState == EntityItem::Mortal) {
_mortalEntities.push_back(thisEntity);
_mortalEntities.push_back(entity);
}
// remove thisEntity from the list
// remove entity from the list
item_itr = _movingEntities.erase(item_itr);
thisEntity->setSimulationState(newState);
entity->setSimulationState(newState);
} else {
++item_itr;
}
@ -126,33 +137,33 @@ void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet<EntityItemID
}
if (moveOperator.hasMovingEntities()) {
PerformanceTimer perfTimer("recurseTreeWithOperator");
_myTree->recurseTreeWithOperator(&moveOperator);
_entityTree->recurseTreeWithOperator(&moveOperator);
}
}
}
void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete) {
void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete) {
QList<EntityItem*>::iterator item_itr = _mortalEntities.begin();
while (item_itr != _mortalEntities.end()) {
EntityItem* thisEntity = *item_itr;
thisEntity->update(now);
EntityItem* entity = *item_itr;
// always check to see if the lifetime has expired, for immortal entities this is always false
if (thisEntity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << thisEntity->getEntityItemID();
entitiesToDelete << thisEntity->getEntityItemID();
// remove thisEntity from the list
if (entity->lifetimeHasExpired()) {
qDebug() << "Lifetime has expired for entity:" << entity->getEntityItemID();
entitiesToDelete.insert(entity);
// remove entity from the list
item_itr = _mortalEntities.erase(item_itr);
thisEntity->setSimulationState(EntityItem::Static);
entity->setSimulationState(EntityItem::Static);
} else {
// check to see if this entity is no longer moving
EntityItem::SimulationState newState = thisEntity->computeSimulationState();
EntityItem::SimulationState newState = entity->computeSimulationState();
if (newState != EntityItem::Mortal) {
if (newState == EntityItem::Moving) {
_movingEntities.push_back(thisEntity);
entity->update(now);
_movingEntities.push_back(entity);
}
// remove thisEntity from the list
// remove entity from the list
item_itr = _mortalEntities.erase(item_itr);
thisEntity->setSimulationState(newState);
entity->setSimulationState(newState);
} else {
++item_itr;
}

View file

@ -18,29 +18,30 @@
class SimpleEntitySimulation : public EntitySimulation {
public:
SimpleEntitySimulation(EntityTree* tree) : EntitySimulation(tree) { }
virtual ~SimpleEntitySimulation() { }
SimpleEntitySimulation() : EntitySimulation() { }
virtual ~SimpleEntitySimulation() { setEntityTree(NULL); }
virtual void update(QSet<EntityItemID>& entitiesToDelete);
virtual void update(QSet<EntityItem*>& entitiesToDelete);
virtual void addEntity(EntityItem* entity);
virtual void removeEntity(EntityItem* entity);
virtual void updateEntity(EntityItem* entity);
virtual void entityChanged(EntityItem* entity);
private:
virtual void clearEntities();
protected:
void updateEntityState(EntityItem* entity);
void clearEntityState(EntityItem* entity);
QList<EntityItem*>& getMovingEntities() { return _movingEntities; }
void updateChangedEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
void updateMovingEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
void updateMortalEntities(quint64 now, QSet<EntityItemID>& entitiesToDelete);
void updateChangedEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
void updateMovingEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
void updateMortalEntities(quint64 now, QSet<EntityItem*>& entitiesToDelete);
private:
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
QList<EntityItem*> _movingEntities; // entities that need to be updated
QList<EntityItem*> _mortalEntities; // non-moving entities that need to be checked for expiry
QSet<EntityItem*> _changedEntities; // entities that have changed in the last frame
};
#endif // hifi_SimpleEntitySimulation_h