From 0d9855574065f6ad4a392d22a1a7936f11896aa0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 24 Nov 2014 22:29:24 -0800 Subject: [PATCH] add EntitySimulation and SimpleEntitySimulation --- libraries/entities/src/EntitySimulation.h | 37 +++ .../entities/src/SimpleEntitySimulation.cpp | 213 ++++++++++++++++++ .../entities/src/SimpleEntitySimulation.h | 46 ++++ 3 files changed, 296 insertions(+) create mode 100644 libraries/entities/src/EntitySimulation.h create mode 100644 libraries/entities/src/SimpleEntitySimulation.cpp create mode 100644 libraries/entities/src/SimpleEntitySimulation.h diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h new file mode 100644 index 0000000000..230e744a16 --- /dev/null +++ b/libraries/entities/src/EntitySimulation.h @@ -0,0 +1,37 @@ +// +// EntitySimulation.h +// 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 +// + +#ifndef hifi_EntitySimulation_h +#define hifi_EntitySimulation_h + +#include + +#include "EntityItemID.h" +#include "EntityTree.h" + +class EntitySimulation { +public: + EntitySimulation(EntityTree* tree) : _myTree(tree) { assert(tree); } + virtual ~EntitySimulation() { _myTree = NULL; } + + /// \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& entitiesToDelete) = 0; + + virtual void addEntity(EntityItem* entity) = 0; + virtual void removeEntity(EntityItem* entity) = 0; + virtual void updateEntity(EntityItem* entity) = 0; + +protected: + EntityTree* _myTree; +}; + +#endif // hifi_EntitySimulation_h diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp new file mode 100644 index 0000000000..d8edfb8ba7 --- /dev/null +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -0,0 +1,213 @@ +// +// SimpleEntitySimulation.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 +#include + +#include "EntityItem.h" +#include "MovingEntitiesOperator.h" +#include "SimpleEntitySimulation.h" + +void SimpleEntitySimulation::update(QSet& entitiesToDelete) { + quint64 now = usecTimestampNow(); + updateChangedEntities(now, entitiesToDelete); + updateMovingEntities(now, entitiesToDelete); + updateMortalEntities(now, entitiesToDelete); +} + +void SimpleEntitySimulation::addEntity(EntityItem* entity) { + assert(entity && entity->getSimulationState() == EntityItem::Static); + EntityItem::SimulationState state = entity->computeSimulationState(); + switch(state) { + case EntityItem::Moving: + _movingEntities.push_back(entity); + entity->setSimulationState(state); + break; + case EntityItem::Mortal: + _mortalEntities.push_back(entity); + entity->setSimulationState(state); + break; + case EntityItem::Static: + default: + break; + } +} + +void SimpleEntitySimulation::removeEntity(EntityItem* entity) { + assert(entity); + // make sure to remove it from any of our simulation lists + EntityItem::SimulationState state = entity->getSimulationState(); + switch (state) { + case EntityItem::Moving: + _movingEntities.removeAll(entity); + break; + case EntityItem::Mortal: + _mortalEntities.removeAll(entity); + break; + + default: + break; + } + _changedEntities.remove(entity); +} + +void SimpleEntitySimulation::updateEntity(EntityItem* entity) { + assert(entity); + // we'll deal with thsi change later + _changedEntities.insert(entity); +} + +void SimpleEntitySimulation::updateChangedEntities(quint64 now, QSet& 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(); + clearEntityState(entity); + } else { + updateEntityState(entity); + } + entity->clearUpdateFlags(); + } + _changedEntities.clear(); +} + +void SimpleEntitySimulation::updateMovingEntities(quint64 now, QSet& entitiesToDelete) { + if (_movingEntities.size() > 0) { + PerformanceTimer perfTimer("_movingEntities"); + MovingEntitiesOperator moveOperator(_myTree); + QList::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 (moveOperator.hasMovingEntities()) { + PerformanceTimer perfTimer("recurseTreeWithOperator"); + _myTree->recurseTreeWithOperator(&moveOperator); + } + } +} + +void SimpleEntitySimulation::updateMortalEntities(quint64 now, QSet& entitiesToDelete) { + QList::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; + } + } + } +} + +void SimpleEntitySimulation::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 SimpleEntitySimulation::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); +} + + diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h new file mode 100644 index 0000000000..bc79bf9958 --- /dev/null +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -0,0 +1,46 @@ +// +// SimpleEntitySimulation.h +// 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 +// + +#ifndef hifi_SimpleEntitySimulation_h +#define hifi_SimpleEntitySimulation_h + +#include "EntitySimulation.h" + +/// provides simple velocity + gravity extrapolation of EntityItem's + +class SimpleEntitySimulation : public EntitySimulation { +public: + SimpleEntitySimulation(EntityTree* tree) : EntitySimulation(tree) { } + virtual ~SimpleEntitySimulation() { } + + virtual void update(QSet& entitiesToDelete); + + virtual void addEntity(EntityItem* entity); + virtual void removeEntity(EntityItem* entity); + virtual void updateEntity(EntityItem* entity); + +private: + void updateEntityState(EntityItem* entity); + void clearEntityState(EntityItem* entity); + + QList& getMovingEntities() { return _movingEntities; } + + void updateChangedEntities(quint64 now, QSet& entitiesToDelete); + void updateMovingEntities(quint64 now, QSet& entitiesToDelete); + void updateMortalEntities(quint64 now, QSet& entitiesToDelete); + +private: + QList _movingEntities; // entities that need to be updated + QList _mortalEntities; // non-moving entities that need to be checked for expiry + QSet _changedEntities; // entities that have changed in the last frame +}; + +#endif // hifi_SimpleEntitySimulation_h