Browse Source

Removed old Object Component code (Entity Component System is its replacement)

combatComponentRefactor
Macoy Madson 7 years ago
parent
commit
5348a494f8
  1. 38
      README.md
  2. 9
      src/ai/htn/HTNTasks.hpp
  3. BIN
      src/experiments/flatbuffers/testFlatbuffers_write
  4. 95
      src/objectComponent/Component.cpp
  5. 89
      src/objectComponent/Component.hpp
  6. 54
      src/objectComponent/ComponentManager.cpp
  7. 46
      src/objectComponent/ComponentManager.hpp
  8. 10
      src/objectComponent/ComponentTypes.hpp
  9. 169
      src/objectComponent/Object.cpp
  10. 113
      src/objectComponent/Object.hpp
  11. 381
      src/objectComponent/ObjectComponentManager.cpp
  12. 120
      src/objectComponent/ObjectComponentManager.hpp
  13. 16
      src/objectComponent/ObjectID.cpp
  14. 15
      src/objectComponent/ObjectID.hpp
  15. 5
      src/objectComponent/ObjectType.cpp
  16. 25
      src/objectComponent/ObjectType.hpp
  17. 4
      src/objectComponent/README.txt
  18. 2
      src/unitTesting/Jamfile
  19. 167
      src/unitTesting/ObjectComponent_test.cpp

38
README.md

@ -7,26 +7,36 @@ With my current design, agents are based on Maslow's hierarchy of needs. This ma
Galavant is basically [Horizon](http://github.com/makuto/horizon) v2. I coded myself into a bit of a quagmire in Horizon, so I decided I would be more productive if I started over.
Interested?
------------
Message me on Github or email me at macoymadson@gmail.com for any questions. I'd love some help!
## Building
There is a lot to the design of Galavant that does not fit in this readme. If you email me, I can fill you in on my goals with Galavant and what the game will actually be like.
Galavant uses Flatbuffers. Before trying to build, make sure to initialize it:
`git submodule update --init --recursive`
Then run cmake in `thirdParty/flatbuffers`:
`cmake .`
Then
`make`
License
--------
The code is MIT licensed. I intend on keeping all data (images, sprites, gameplay/design data) private, following the Doom/Quake model, but for now, consider those to be MIT Licensed.
Jam is used as the build system for Galavant. I used to use makefiles in the Horizon iteration of this project, and I hated them. Jam is much easier to use and takes much less work to get a project set up. If people actually become interested in this project, I can invest some time in cmake-ifying it for more standard building. If you're willing to try building using Jam, you may have to edit Jamrules to set your preferred compiler (the default is g++).
Technical
----------
I am writing Galavant in C++ (C++11, to be specific). I rely on SFML2 for sound, graphics, input, and networking. SFML is wrapped in my personal game library, [Base2.0](https://github.com/makuto/base2.0) (also MIT licensed), which also has other useful game-agnostic code.
To build with jam, first install jam:
`sudo apt-get install jam`
Then run jam (in galavant/ is fine):
`jam`
Jam is used as the build system for Galavant. I used to use makefiles in the Horizon iteration of this project, and I hated them. Jam is much easier to use and takes much less work to get a project set up. If people actually become interested in this project, I can invest some time in cmake-ifying it for more standard building. If you're willing to try building using jam, you may have to edit Jamrules to set your preferred compiler.
## Dependencies
Dependencies
--------------
Galavant uses features of C++11.
The following libraries are required by Galavant and included in /thirdParty:
- [OpenSimplexNoise](https://gist.github.com/tombsar/716134ec71d1b8c1b530), created by Arthur Tombs (public domain)
- [Flatbuffers](https://github.com/google/flatbuffers), created by Google/Fun Propulsion Labs (Apache License, v2.0)
- [Flatbuffers](https://github.com/google/flatbuffers), created by Google/Fun Propulsion Labs (Apache License, v2.0)
## License
The code is MIT licensed. I intend on keeping all data (images, sprites, gameplay/design data) private, following the Doom/Quake model, but for now, consider those to be MIT Licensed.
## Want to Get Involved?
Message me on Github or email me at macoymadson@gmail.com for any questions. I'd love some help!
There is a lot to the design of Galavant that does not fit in this readme. If you email me, I can fill you in on my goals with Galavant and what the game will actually be like.

9
src/ai/htn/HTNTasks.hpp

@ -26,6 +26,15 @@ protected:
TaskType Type;
};*/
// Instead of the commented code, just use a simple struct which stores all types of tasks but
// only hope to allow only one thing to be filled in for it
struct Task
{
GoalTask* Goal;
CompoundTask* Compound;
PrimitiveTask* Primitive;
};
typedef std::vector<Task*> TaskList;
//

BIN
src/experiments/flatbuffers/testFlatbuffers_write

Binary file not shown.

95
src/objectComponent/Component.cpp

@ -1,95 +0,0 @@
#ifndef COMPONENT_CPP
#define COMPONENT_CPP
#include <iostream>
#include "Component.hpp"
#include "ObjectType.hpp"
#include "Object.hpp"
Component::Component()
{
}
Component::~Component()
{
}
ComponentType Component::getType()
{
return type;
}
ObjectType Component::getOwnerType()
{
return ownerType;
}
ObjectID Component::getOwnerID()
{
return ownerID;
}
// This function should NEVER return NULL on a valid initialized Component.
// This function is used by ComponentManagers when moving Components in memory
// Make SURE you set your parentObject pointer in initialize()!
Object* Component::getParentObject()
{
return parentObject;
}
// Initialize the component. Components should be able to be reused after initialize is called.
// Components should store their parent object's address for later use
// Return false if initialization failed for any reason, and the object creation will
// be aborted
bool Component::initialize(Object* newParentObject)
{
return false;
}
// Once all sibling components in an object have been initialize, postInitialize is executed.
// Use this function to find all sibling components that your component is dependent on, as well
// as any component-component initialization communication that might need to happen.
bool Component::postInitialize()
{
return true;
}
// The parent Object has been scheduled to be destroyed. preDestroy() is called on every component
// before components are actually destroyed. This is the "last supper" for components. Use
// this time to do any component-component destruction communication
void Component::preDestroy()
{
}
// The parent Object is being destroyed. Perform any destruction necessary here. It is up to
// you to decide what is destroyed in destroy() and what is cleared in initialize().
void Component::destroy()
{
}
// Perform all logic for your component here
void Component::update(ComponentUpdateParams& updateParams)
{
}
// Output or render as much helpful information as you can about your component in this
// function.
void Component::debugPrint()
{
std::cout << "WARNING: Undefined debugPrint for component of type " << (int)type << "\n";
}
// Copy all data needed to make an exact replica of the current component to the
// new component. This function will be used when an entire Object or Component is moved.
// Return false if there was an error copying (or it is impossible to copy)
// The new component has already been initialized, but not postInitialized (should it be?)
// You should NOT set the current Component's parentObject pointer to the newComponent's
bool Component::copyComponent(Object* newParentObject, Component* newComponent)
{
return false;
}
#endif

89
src/objectComponent/Component.hpp

@ -1,89 +0,0 @@
#ifndef COMPONENT_HPP
#define COMPONENT_HPP
#include "ObjectID.hpp"
#include "ObjectType.hpp"
/* --Component--
* Components are modular bits of logic and data designed to work with other
* modular components. Objects are collections of components. Component is an abstract
* class.
*/
enum ComponentType;
struct ComponentUpdateParams;
class Object;
class ComponentManager;
class Component
{
public:
Component();
// Note that the constructor and destructor shouldn't have to be executed
// every time a Component is created. Initialize and Deinitalize should do everything
// necessary for a component to be reused
virtual ~Component();
// Getters for types
ComponentType getType();
ObjectType getOwnerType();
ObjectID getOwnerID();
// This function should NEVER return NULL on a valid initialized Component.
// This function is used by ComponentManagers when moving Components in memory
// Make SURE you set your parentObject pointer in initialize()!
Object* getParentObject();
// Initialize the component. Components should be able to be reused after initialize is called.
// Components should store their parent object's address for later use
// Return false if initialization failed for any reason, and the object creation will
// be aborted
virtual bool initialize(Object* newParentObject);
// Once all sibling components in an object have been initialize, postInitialize is executed.
// Use this function to find all sibling components that your component is dependent on, as well
// as any component-component initialization communication that might need to happen.
virtual bool postInitialize();
// The parent Object has been scheduled to be destroyed. preDestroy() is called on every component
// before components are actually destroyed. This is the "last supper" for components. Use
// this time to do any component-component destruction communication
virtual void preDestroy();
// The parent Object is being destroyed. Perform any destruction necessary here. It is up to
// you to decide what is destroyed in destroy() and what is cleared in initialize().
virtual void destroy();
// Perform all logic for your component here
virtual void update(ComponentUpdateParams& updateParams);
// Output or render as much helpful information as you can about your component in this
// function.
virtual void debugPrint();
// Copy all data needed to make an exact replica of the current component to the
// new component. This function will be used when an entire Object or Component is moved.
// Return false if there was an error copying (or it is impossible to copy)
// The new component has already been initialized, but not postInitialized (should it be?)
// You should NOT set the current Component's parentObject pointer to the newComponent's
virtual bool copyComponent(Object* newParentObject, Component* newComponent);
// TODO: Component save and load functions
//virtual bool save(SaveBuffer *saveBuffer);
//virtual bool load(LoadBuffer *loadBuffer);
// This value can be used by the ComponentManager to find a component
// in a Pool, array, list, etc
int localID;
protected:
// The parent object of this component. This value should always be
// valid and set as the ComponentManager will use it
Object* parentObject;
ComponentType type;
private:
ObjectType ownerType;
ObjectID ownerID;
};
#endif // COMPONENT_HPP

54
src/objectComponent/ComponentManager.cpp

@ -1,54 +0,0 @@
#ifndef COMPONENTMANAGER_CPP
#define COMPONENTMANAGER_CPP
#include "ComponentManager.hpp"
ComponentType ComponentManager::getType()
{
return type;
}
ComponentManager::ComponentManager()
{
}
ComponentManager::~ComponentManager()
{
}
// Initialize the ComponentManager. The manager should work without
// the constructor having been run before
bool ComponentManager::initialize()
{
return true;
}
// Do any destruction necessary for this manager.
void ComponentManager::destroy()
{
}
// Update all of the active Components, passing them the ComponentUpdateParams
void ComponentManager::updateAllComponents(ComponentUpdateParams& componentUpdateParams)
{
}
// Return a pointer to a fresh Component. Do not run initialize() or
// anything on the component - this function's caller should handle that.
// Return NULL if the request cannot be completed (e.g., the pool is full)
Component* ComponentManager::getNewRawComponent()
{
return nullptr;
}
// Run destroy() on the Component and remove the component from this manager's memory.
void ComponentManager::destroyComponent(Component* component)
{
}
#endif

46
src/objectComponent/ComponentManager.hpp

@ -1,46 +0,0 @@
#ifndef COMPONENTMANAGER_HPP
#define COMPONENTMANAGER_HPP
#include "ComponentTypes.hpp"
/* --ComponentManager--
* ComponentManagers handle the storage, creation, and updating of a single
* type of Component. ComponentManager is a polymorphic class so that
* unique behaviors can be determined for all of these functions.
* */
class Object;
class Component;
struct ComponentUpdateParams;
class ComponentManager
{
public:
ComponentManager();
virtual ~ComponentManager();
ComponentType getType();
// Initialize the ComponentManager. The manager should work without
// the constructor having been run before
virtual bool initialize();
// Do any destruction necessary for this manager.
virtual void destroy();
// Update all of the active Components, passing them the ComponentUpdateParams
virtual void updateAllComponents(ComponentUpdateParams& componentUpdateParams);
// Return a pointer to a fresh Component. Do not run initialize() or
// anything on the component - this function's caller should handle that.
// Return NULL if the request cannot be completed (e.g., the pool is full)
virtual Component* getNewRawComponent();
// Run destroy() on the Component and remove the component from this manager's memory.
virtual void destroyComponent(Component* component);
private:
ComponentType type;
};
#endif

10
src/objectComponent/ComponentTypes.hpp

@ -1,10 +0,0 @@
#ifndef COMPONENTTYPES_HPP
#define COMPONENTTYPES_HPP
enum class ComponentType : int
{
NONE = 0,
TEST
};
#endif

169
src/objectComponent/Object.cpp

@ -1,169 +0,0 @@
#ifndef OBJECT_CPP
#define OBJECT_CPP
#include <assert.h>
#include "Object.hpp"
#include "Component.hpp"
const int COMPONENTHANDLE_NULL = -1;
Object::Object()
{
initialize();
}
Object::~Object()
{
}
void Object::initialize()
{
shouldDestroy = false;
numActiveComponents = 0;
id = OBJECT_ID_NONE;
type = nullptr;
}
ObjectID Object::getObjectID()
{
return id;
}
// Provides a layer of abstraction around the internal storage of Component pointers
Component* Object::getComponentAtIndex(int i)
{
if (i >= 0 && i < numActiveComponents)
return components[i];
return nullptr;
}
// Searches through components this object is composed of for one of
// the provided type. Returns a handle
// Returns a ComponentHandle which can be used to get a pointer to
// a component of the requested type.
Object::ComponentHandle Object::getComponentHandleForType(ComponentType componentType)
{
for (int i = 0; i < numActiveComponents; i++)
{
Component* currentComponent = getComponentAtIndex(i);
if (currentComponent)
{
if (currentComponent->getType() == componentType)
return i;
}
}
return COMPONENTHANDLE_NULL;
}
// Returns true if the ComponentHandle is valid, and points to a valid
// Component.
bool Object::isValidComponentHandle(ComponentHandle componentHandle)
{
if (componentHandle == Object::COMPONENTHANDLE_NULL
|| componentHandle >= numActiveComponents)
return false;
return true;
}
// Returns a pointer to the component indicated by the handle.
// This pointer should NOT be stored on the heap! Components can
// move around in memory, so storing direct pointers is not ok!
Component* Object::getComponent(Object::ComponentHandle componentHandle)
{
if (isValidComponentHandle(componentHandle))
return getComponentAtIndex(componentHandle);
return nullptr;
}
// Returns the value of shouldDestroy. If true, whatever is managing
// the object should notify all components of the impending destruction,
// destroy the components, then destroy the object
bool Object::shouldDestroyObject()
{
return shouldDestroy;
}
// Sets the value of shouldDestroy to true. Once set, it cannot be
// undone. The actual destruction should be handled by the object's
// manager after checking shouldDestroyObject()
// This function is meant to be used by the object's components to self-destruct
// Destruction will not happen immediately - it is up to the object's manager
void Object::requestObjectDestruction()
{
shouldDestroy = true;
}
void Object::setObjectID(ObjectID newObjectID)
{
id = newObjectID;
}
void Object::setObjectType(ObjectType* newObjectType)
{
type = newObjectType;
}
void Object::addComponent(Component* newComponent)
{
if (numActiveComponents < OBJECT_MAX_COMPONENTS)
{
components[numActiveComponents] = newComponent;
numActiveComponents++;
}
else
{
// Tried to add more than OBJECT_MAX_COMPONENTS
assert(0);
}
}
int Object::getNumActiveComponents()
{
return numActiveComponents;
}
// Run postInitialize on all components
bool Object::postInitializeComponents()
{
// For each active component
for (int i = 0; i < numActiveComponents; i++)
{
Component* currentComponent = getComponentAtIndex(i);
if (currentComponent)
{
// Run postInitialize on the component
if (!currentComponent->postInitialize())
return false;
}
}
return true;
}
// Run preDestroy on all components
void Object::preDestroyComponents()
{
// For each active component
for (int i = 0; i < numActiveComponents; i++)
{
Component* currentComponent = getComponentAtIndex(i);
if (currentComponent)
{
currentComponent->preDestroy();
}
}
}
// Resets components[] by changing numActiveComponents to 0; this is
// only used if a partially initialized Object's component failed to initialize
void Object::resetComponentsArray()
{
numActiveComponents = 0;
}
#endif

113
src/objectComponent/Object.hpp

@ -1,113 +0,0 @@
#ifndef OBJECT_HPP
#define OBJECT_HPP
#include "ObjectID.hpp"
#include "ObjectType.hpp"
#include "ComponentTypes.hpp"
/* --Object--
* Objects hold a collection of Components. Object provides an abstraction
* layer for Components so that components can be moved in memory without
* affecting other Components.
*
* Note that Objects cannot hold more than one Component of the same type.
* If this is required for some reason, you should redesign the system, or
* make the component support it internally
*/
class Component;
struct ObjectType;
class ObjectComponentManager;
class Object
{
public:
Object();
~Object();
// Initialize the object
// Objects should work completely after initialize, even if the constructor isn't called
void initialize();
ObjectID getObjectID();
// A handle to a Component this Object has
// Components (and all other external users of an Object's components) should
// NEVER store pointers to an Object's components on anything other than
// the stack. ComponentHandles, however, are safe to store. This is so
// that Components can be moved around in memory without breaking references
typedef int ComponentHandle;
// Searches through components this object is composed of for one of
// the provided type.
// Returns a ComponentHandle which can be used to get a pointer to
// a component of the requested type.
// Note that Objects can only have one Component of the same type
// Check your ComponentHandle's validity with isValidComponentHandle()
ComponentHandle getComponentHandleForType(ComponentType componentType);
// Returns true if the ComponentHandle is valid, and points to a valid
// Component.
bool isValidComponentHandle(ComponentHandle componentHandle);
// Returns a pointer to the component indicated by the handle.
// This pointer should NOT be stored on the heap! Components can
// move around in memory, so storing direct pointers is not ok!
// Note that getComponent() checks the validity of the ComponentHandle
// Returns nullptr if the Handle is invalid
Component* getComponent(ComponentHandle componentHandle);
// Returns the value of shouldDestroy. If true, whatever is managing
// the object should notify all components of the impending destruction,
// destroy the components, then destroy the object
bool shouldDestroyObject();
// Sets the value of shouldDestroy to true. Once set, it cannot be
// undone. The actual destruction should be handled by the object's
// manager after checking shouldDestroyObject()
// This function is meant to be used by the object's components to self-destruct
// Destruction will not happen immediately - it is up to the object's manager
void requestObjectDestruction();
friend class ObjectComponentManager;
protected:
// Functions for ObjectComponentManager
void setObjectID(ObjectID newObjectID);
void setObjectType(ObjectType* newObjectType);
// Add a new, initialized component to this object
void addComponent(Component* newComponent);
// Run postInitialize on all components
bool postInitializeComponents();
// Run preDestroy on all components
void preDestroyComponents();
int getNumActiveComponents();
// Provides a layer of abstraction around the internal storage of Component pointers
Component* getComponentAtIndex(int i);
// Resets components[] by changing numActiveComponents to 0; this is
// only used if a partially initialized Object's component failed to initialize
void resetComponentsArray();
private:
// A list of pointers to Components the Object currently has (up to numActiveComponents)
// OBJECT_MAX_COMPONENTS is defined in ObjectType.hpp
Component* components[OBJECT_MAX_COMPONENTS];
int numActiveComponents;
ObjectType* type;
ObjectID id;
// shouldDestroy indicates whether or not the Object should be
// destroyed. This is meant to be used by Components to self-destruct.
// shouldDestroy should be checked by whatever is managing
// the object after the object's components have been updated
bool shouldDestroy;
// The NULL value for ComponentHandles
static const int COMPONENTHANDLE_NULL = -1;
};
#endif

381
src/objectComponent/ObjectComponentManager.cpp

@ -1,381 +0,0 @@
#ifndef OBJECTCOMPONENTMANAGER_CPP
#define OBJECTCOMPONENTMANAGER_CPP
#include <assert.h>
#include <iostream>
#include "ObjectComponentManager.hpp"
#include "ComponentManager.hpp"
#include "Component.hpp"
ObjectComponentManager::ObjectComponentManager():objectPool(ObjectComponentManager::OBJECT_POOL_SIZE)
{
}
ObjectComponentManager::~ObjectComponentManager()
{
destroyAllActiveObjects();
}
// Destroys all active objects
void ObjectComponentManager::destroyAllActiveObjects()
{
destroyObjectsWithRequestedDestructionInternal(true);
}
// Adds a ComponentManager to the ComponentManagerDictionary. If
// there is already a manager for the specified type, it will be overwritten
void ObjectComponentManager::addComponentManager(ComponentType managerComponentType, ComponentManager* newManager)
{
addComponentManagerToDictionary(managerComponentType, newManager);
}
// Adds an ObjectType of newObjectTypeID to the ObjectType dictionary.
// If there is already an ObjectType of the specified ObjectTypeID, it will
// be overwritten. This is the function where ObjectTypeIDs are tied to
// a specific ObjectType
void ObjectComponentManager::addObjectType(ObjectTypeID newObjectTypeID, ObjectType newObjectType)
{
addObjectTypeToDictionary(newObjectTypeID, newObjectType);
}
// Create a new Object of the specified type. Returns NULL if
// the ObjectType couldn't be found, the object pool is full, or
// Object failed to initialize
// TODO: IMPORTANT! Do extensive testing on this function, making sure things
// are being deleted when they should be if initialization fails for any reason
Object* ObjectComponentManager::createObjectOfTypeID(ObjectTypeID newObjectTypeID)
{
// Get the new Object's ObjectType
ObjectType* newObjectType = getObjectTypeByID(newObjectTypeID);
// Couldn't find the requested ObjectType
if (!newObjectType)
return nullptr;
// Create the Object
Object* newObject = createNewEmptyObject();
if (newObject)
{
// Set the Object's ObjectType
newObject->setObjectType(newObjectType);
// Add components to the new Object
if (createAndAddComponentsForObject(newObject, newObjectType))
{
// Run postInitialize on the object's components
if (postInitializeObject(newObject))
return newObject;
}
}
// Object creation failed; remove the Object
removeEmptyObject(newObject);
return nullptr;
}
bool ObjectComponentManager::addComponentOfTypeToObject(Object* object, ComponentType componentToAdd)
{
// Find the ComponentManager for the specified type
ComponentManager* componentManager = getComponentManagerForType(componentToAdd);
if (!componentManager)
{
// ComponentManager couldn't be found
return false;
}
// Get a fresh new component from the manager
Component* newComponent = componentManager->getNewRawComponent();
if (!newComponent)
{
// Failed to get new component from manager
return false;
}
// Initialize the component
if (!newComponent->initialize(object))
{
// Component failed to initialize
return false;
}
object->addComponent(newComponent);
return true;
}
bool ObjectComponentManager::createAndAddComponentsForObject(Object* object, ObjectType* newObjectType)
{
bool allComponentsSuccessfullyCreated = true;
if (!object || !newObjectType)
return false;
// Add components one by one according to the ObjectType spec
for (int i = 0; i < newObjectType->totalUsedComponents; i++)
{
ComponentType currentComponentType = newObjectType->components[i];
if (!addComponentOfTypeToObject(object, currentComponentType))
{
allComponentsSuccessfullyCreated = false;
break;
}
}
// Make sure the Object has all of its needed components
if (object->getNumActiveComponents() != newObjectType->totalUsedComponents)
{
allComponentsSuccessfullyCreated = false;
}
if (!allComponentsSuccessfullyCreated)
{
// Something went wrong during Component creation - destroy all other components on the object
// and return failure
destroyAllComponentsOnObject(object);
return false;
}
return true;
}
// Tells the ComponentManager of each component on an object to destroy the component
// Make sure to run preDestroy on all of the components before calling this function
// (it is not called within the function because this function is used when Objects
// might not be fully formed (like in createAndAddComponentsForObject) or haven't been
// postInitialized)
void ObjectComponentManager::destroyAllComponentsOnObject(Object* object)
{
for (int i = 0; i < object->getNumActiveComponents(); i++)
{
Component* currentComponent = object->getComponentAtIndex(i);
if (!currentComponent)
continue;
ComponentType currentComponentType = currentComponent->getType();
if (currentComponentType != ComponentType::NONE)
{
ComponentManager* currentComponentManager = getComponentManagerForType(currentComponentType);
if (currentComponentManager)
{
currentComponentManager->destroyComponent(currentComponent);
}
}
}
}
// Run postInitialize() on all of the Object's components
bool ObjectComponentManager::postInitializeObject(Object* newObject)
{
if (newObject)
{
return newObject->postInitializeComponents();
}
return false;
}
void ObjectComponentManager::preDestroyObject(Object* object)
{
if (object)
{
object->preDestroyComponents();
}
}
// Update the ComponentManager of the specified type
// There is no updateAll() function because it is expected that there
// will be a specific order the ComponentManagers should be updated.
// Having updateComponentManagerOfType allows that order to be explicitly determined
void ObjectComponentManager::updateComponentManagerOfType(ComponentType componentType, ComponentUpdateParams& componentUpdateParams)
{
ComponentManager* componentManager = getComponentManagerForType(componentType);
if (componentManager)
{
componentManager->updateAllComponents(componentUpdateParams);
}
else
{
// Tried to update a component manager which doesn't exist
assert(0);
}
}
// Destroy all Objects which have shouldDestroy set to true
// This function should be called once per frame/after updating all ComponentManagers
// TODO: This is currently looping through all objects. May need to optimize later
void ObjectComponentManager::destroyObjectsWithRequestedDestruction()
{
destroyObjectsWithRequestedDestructionInternal(false);
}
void ObjectComponentManager::destroyObjectsWithRequestedDestructionInternal(bool forceDestroyAllObjects)
{
std::vector<ObjectPoolHandle> objectsToDestroy;
// Build a list of all Objects that have impending destruction
// A separate list must be used because any other list could have
// data moving due to the destruction
for (ActiveObjectsDictionary::iterator it = activeObjects.begin(); it != activeObjects.end(); ++it)
{
ObjectPoolHandle currentObjectHandle = it->second;
if (currentObjectHandle)
{
Object* currentObject = &currentObjectHandle->data;
if (currentObject->shouldDestroyObject() || forceDestroyAllObjects)
objectsToDestroy.push_back(currentObjectHandle);
}
}
// Destroy all Objects in the destroy list
for (std::vector<ObjectPoolHandle>::iterator it = objectsToDestroy.begin(); it != objectsToDestroy.end(); ++it)
{
if (!(*it))
continue;
Object* currentObject = &(*it)->data;
// Have the Object tell its components that they are going to be destroyed
preDestroyObject(currentObject);
// Destroy the object's components
destroyAllComponentsOnObject(currentObject);
// Remove the now empty object from the Active Objects dictionary and the Object Pool
removeEmptyObject(currentObject);
}
}
/////////////////////////////////////////////////////////////////
// Abstraction layer for ObjectComponentManager data structures
/////////////////////////////////////////////////////////////////
// Creates a new Object, assigns its ID, and adds it to the Active Objects dictionary
// This function does not run initialize() etc
// Make sure to run removeObject() once finished with the object
Object* ObjectComponentManager::createNewEmptyObject()
{
ObjectPoolHandle newPooledObject = objectPool.getNewData();
if (newPooledObject)
{
Object* newObject = &newPooledObject->data;
// Initialize the object
newObject->initialize();
// Set the new object's ID
ObjectID newObjectID = generateUniqueObjectID();
newObject->setObjectID(newObjectID);
// Make sure the ID is unique
assert(getObjectByID(newObjectID) == nullptr);
// Add the Object to the Active Objects Dictionary
activeObjects[newObjectID] = newPooledObject;
return newObject;
}
// Pool is full!
std::cout << "WARNING: Object Pool is FULL!\n";
return nullptr;
}
Object* ObjectComponentManager::getObjectByID(ObjectID objectID)
{
ActiveObjectsDictionary::iterator findIt = activeObjects.find(objectID);
if (findIt != activeObjects.end())
{
return &findIt->second->data;
}
return nullptr;
}
// Removes an object from the ActiveObjects Dictionary and frees it from the object pool.
// This function DOES NOT remove an object's components (hence the "Empty")
// This function should NOT be called if you are iterating over activeObjects, because
// it removes values from activeObjects.
void ObjectComponentManager::removeEmptyObject(Object* objectToRemove)
{
if (objectToRemove)
{
// Find the Object in the activeObjects dictionary
ActiveObjectsDictionary::iterator findIt = activeObjects.find(objectToRemove->getObjectID());
if (findIt != activeObjects.end())
{
ObjectPoolHandle pooledObject = findIt->second;
if (pooledObject)
{
// Free the object in the pool
objectPool.removeData(pooledObject);
// Remove the Object from hte Active Objects dictionary
activeObjects.erase(findIt);
}
}
else
{
// Tried to remove an Object which isn't in this ObjectComponentManager's ActiveObjects
assert(0);
}
}
}
ComponentManager* ObjectComponentManager::getComponentManagerForType(ComponentType componentType)
{
ComponentManagerDictionary::iterator findIt = componentManagers.find(componentType);
if (findIt != componentManagers.end())
{
return findIt->second;
}
return nullptr;
}
void ObjectComponentManager::addComponentManagerToDictionary(ComponentType componentType, ComponentManager* newManager)
{
componentManagers[componentType] = newManager;
}
ObjectType* ObjectComponentManager::getObjectTypeByID(ObjectTypeID objectTypeID)
{
ObjectTypeDictionary::iterator findIt = objectTypes.find(objectTypeID);
if (findIt != objectTypes.end())
{
return &findIt->second;
}
return nullptr;
}
void ObjectComponentManager::addObjectTypeToDictionary(ObjectTypeID objectTypeID, ObjectType newObjectType)
{
objectTypes[objectTypeID] = newObjectType;
}
// TODO: Have a more explicit way to get runtime-unique object ids
static ObjectID currentAvailableObjectID = OBJECT_ID_FIRST;
ObjectID ObjectComponentManager::generateUniqueObjectID()
{
return currentAvailableObjectID++;
}
#endif

120
src/objectComponent/ObjectComponentManager.hpp

@ -1,120 +0,0 @@
#ifndef OBJECTCOMPONENTMANAGER_HPP
#define OBJECTCOMPONENTMANAGER_HPP
#include <base2.0/dataStructures/pool.hpp>
#include <map>
#include "Object.hpp"
#include "ObjectType.hpp"
#include "ComponentTypes.hpp"
#include "ObjectID.hpp"
/* --ObjectComponentManager--
* ObjectComponentManager manages ComponentManagers and Objects. It
* performs the necessary interactions between these two systems
* */
class ComponentManager;
struct ComponentUpdateParams;
class ObjectComponentManager
{
public:
ObjectComponentManager();
~ObjectComponentManager();
// Adds a ComponentManager to the ComponentManagerDictionary. If
// there is already a manager for the specified type, it will be overwritten
void addComponentManager(ComponentType managerComponentType, ComponentManager* newManager);
// Adds an ObjectType of newObjectTypeID to the ObjectType dictionary.
// If there is already an ObjectType of the specified ObjectTypeID, it will
// be overwritten. This is the function where ObjectTypeIDs are tied to
// a specific ObjectType
void addObjectType(ObjectTypeID newObjectTypeID, ObjectType newObjectType);
// Create a new Object of the specified type. Returns NULL if
// the ObjectType couldn't be found, the object pool is full, or
// Object failed to initalize
Object* createObjectOfTypeID(ObjectTypeID newObjectTypeID);
// Update the ComponentManager of the specified type
// There is no updateAll() function because it is expected that there
// will be a specific order the ComponentManagers should be updated.
// Having updateComponentManagerOfType allows that order to be explicitly determined
void updateComponentManagerOfType(ComponentType componentType, ComponentUpdateParams& componentUpdateParams);
// Destroys all active objects
void destroyAllActiveObjects();
// Destroy all Objects which have shouldDestroy set to true
// This function should be called once per frame/after updating all ComponentManagers
void destroyObjectsWithRequestedDestruction();
private:
// The structure that holds all ComponentManagers
typedef std::map<ComponentType, ComponentManager*> ComponentManagerDictionary;
ComponentManagerDictionary componentManagers;
// The pooled structure that holds all Objects
typedef Pool<Object> ObjectPool;
static const int OBJECT_POOL_SIZE = 100;
ObjectPool objectPool;
// A handle to a pooled object
typedef PoolData<Object>* ObjectPoolHandle;
// The dictionary which holds Objects associated with their IDs
typedef std::map<ObjectID, ObjectPoolHandle> ActiveObjectsDictionary;
ActiveObjectsDictionary activeObjects;
// The structure that holds all ObjectTypes
typedef std::map<ObjectTypeID, ObjectType> ObjectTypeDictionary;
ObjectTypeDictionary objectTypes;
// Abstraction layer for ObjectComponentManager data structures
// Creates a new Object, assigns its ID, and adds it to the Active Objects dictionary
// This function does not run initialize() etc
// Make sure to run removeObject() once finished with the object
Object* createNewEmptyObject();
Object* getObjectByID(ObjectID objectID);
// Removes an object from the ActiveObjects Dictionary and frees it from the object pool.
// This function DOES NOT remove an object's components (hence the "Empty")
// This function should NOT be called if you are iterating over activeObjects, because
// it removes values from activeObjects. Do not call this function if you are iterating
// over active objects in the object pool either
void removeEmptyObject(Object* objectToRemove);
ComponentManager* getComponentManagerForType(ComponentType componentType);
void addComponentManagerToDictionary(ComponentType componentType, ComponentManager* newManager);
ObjectType* getObjectTypeByID(ObjectTypeID objectTypeID);
void addObjectTypeToDictionary(ObjectTypeID objectTypeID, ObjectType newObjectType);
// Generates a globally unique ObjectID (runtime only; these aren't persisted)
ObjectID generateUniqueObjectID();
bool addComponentOfTypeToObject(Object* object, ComponentType componentToAdd);
bool createAndAddComponentsForObject(Object* newObject, ObjectType* newObjectType);
void destroyObjectsWithRequestedDestructionInternal(bool forceDestroyAllObjects);
// Tells the ComponentManager of each component on an object to destroy the component
// Make sure to run preDestroy on all of the components before calling this function
// (it is not called within the function because this function is used when Objects
// might not be fully formed (like in createAndAddComponentsForObject) or haven't been
// postInitialized)
void destroyAllComponentsOnObject(Object* newObject);
// Run postInitialize() on all of the Object's components
bool postInitializeObject(Object* newObject);
// Run preDestroy() on all of the Object's components
void preDestroyObject(Object* object);
};
#endif

16
src/objectComponent/ObjectID.cpp

@ -1,16 +0,0 @@
#ifndef OBJECTID_CPP
#define OBJECTID_CPP
#include "ObjectID.hpp"
// The Object hasn't been assigned an ID
const ObjectID OBJECT_ID_NONE = -1;
// The last possible ID that can be assigned
// TODO: Set to a better value (this was completely arbitrary)
const ObjectID OBJECT_ID_MAX = 1000000;
// Start assigning IDs at this value
const ObjectID OBJECT_ID_FIRST = 1;
#endif

15
src/objectComponent/ObjectID.hpp

@ -1,15 +0,0 @@
#ifndef OBJECTID_HPP
#define OBJECTID_HPP
typedef int ObjectID;
// The Object hasn't been assigned an ID
extern const ObjectID OBJECT_ID_NONE;
// The last possible ID that can be assigned
extern const ObjectID OBJECT_ID_MAX;
// Start assigning IDs at this value
extern const ObjectID OBJECT_ID_FIRST;
#endif

5
src/objectComponent/ObjectType.cpp

@ -1,5 +0,0 @@
#ifndef OBJECTTYPE_CPP
#define OBJECTTYPE_CPP
#endif

25
src/objectComponent/ObjectType.hpp

@ -1,25 +0,0 @@
#ifndef OBJECTTYPE_HPP
#define OBJECTTYPE_HPP
#include "ComponentTypes.hpp"
#define OBJECT_MAX_COMPONENTS 10
// ObjectTypeIDs are not tied to ObjectTypes automatically. This association
// happens in ObjectComponentManager
enum class ObjectTypeID : int
{
NONE = 0,
TEST
};
struct ObjectType
{
// An array of ComponentTypes that this ObjectType requires
ComponentType components[OBJECT_MAX_COMPONENTS];
// The number of Components this Object will actually use
int totalUsedComponents;
};
#endif

4
src/objectComponent/README.txt

@ -1,4 +0,0 @@
ObjectComponent
================
ObjectComponent is my first try at getting an Object-Component System (or Entity Component System) set up. Since then, I've redesigned how I want to do it, so this code is *DEPRECATED*. Do not use it. Use src/EntityComponentSystem instead.

2
src/unitTesting/Jamfile

@ -1,7 +1,5 @@
SubDir . src unitTesting ;
Main objectComponentTest : ObjectComponent_test.cpp ../objectComponent/Component.cpp ../objectComponent/ComponentManager.cpp ../objectComponent/Object.cpp ../objectComponent/ObjectComponentManager.cpp ../objectComponent/ObjectID.cpp ../objectComponent/ObjectType.cpp ;
Main entityComponentTest : EntityComponentSystem_test.cpp ;
LinkLibraries entityComponentTest : libGalaEntityComponent ;

167
src/unitTesting/ObjectComponent_test.cpp

@ -1,167 +0,0 @@
#include <iostream>
#include <base2.0/dataStructures/pool.hpp>
#include "../objectComponent/ObjectComponentManager.hpp"
#include "../objectComponent/ObjectType.hpp"
#include "../objectComponent/Component.hpp"
#include "../objectComponent/ComponentManager.hpp"
struct ComponentUpdateParams
{
float timeStep;
};
class TestComponent : public Component
{
public:
TestComponent()
{
std::cout << "+++ TestComponent constructed!\n";
}
virtual ~TestComponent()
{
std::cout << "--- TestComponent destructed\n";
}
virtual bool initialize(Object* newParentObject)
{
parentObject = newParentObject;
type = ComponentType::TEST;
std::cout << "Initialized new TestComponent!\n";
return true;
}
virtual bool postInitialize()
{
std::cout << " postInitialized new TestComponent!\n";
return true;
}
virtual void preDestroy()
{
std::cout << " preDestroy TestComponent!\n";
}
virtual void destroy()
{
std::cout << "destroy TestComponent!\n";
}
virtual void update(ComponentUpdateParams& updateParams)
{
std::cout << " updating TestComponent!\n";
}
virtual void debugPrint()
{
std::cout << " debugPrint TestComponent! parent obj: " << parentObject << "\n";
}
virtual bool copyComponent(Object* newParentObject, Component* newComponent)
{
std::cout << " Copying TestComponent!\n";
return true;
}
};
class TestComponentManager : public ComponentManager
{
private:
Component* activeComponents[100];
public:
TestComponentManager()
{
std::cout << "+++ TestComponentManager created\n";
initialize();
}
virtual ~TestComponentManager()
{
std::cout << "--- TestComponentManager destructor\n";
destroy();
}
virtual bool initialize()
{
std::cout << "TestComponentManager initialized\n";
for (int i = 0; i < 100; i++)
{
activeComponents[i] = nullptr;
}
return true;
}
virtual void destroy()
{
for (int i = 0; i < 100; i++)
{
if (activeComponents[i])
{
destroyComponent(activeComponents[i]);
}
}
std::cout << "TestComponentManager destroyed\n";
}
virtual void updateAllComponents(ComponentUpdateParams& componentUpdateParams)
{
std::cout << " Manager: Updating components\n";
for (int i = 0; i < 100; i++)
{
Component* currentComponent = activeComponents[i];
if (currentComponent != nullptr)
{
std::cout << " Manager: Running update on " << currentComponent << "\n";
currentComponent->update(componentUpdateParams);
}
}
}
virtual Component* getNewRawComponent()
{
std::cout << " Manager: Creating component\n";
Component* newComponent = new TestComponent;
for (int i = 0; i < 100; i++)
{
Component* currentComponent = activeComponents[i];
if (currentComponent == nullptr)
{
newComponent->localID = i;
activeComponents[i] = newComponent;
break;
}
}
return newComponent;
}
virtual void destroyComponent(Component* component)
{
std::cout << " Manager: Destroying component\n";
activeComponents[component->localID] = nullptr;
component->destroy();
delete component;
}
};
int main()
{
std::cout << "Testing ObjectComponent system\n";
TestComponentManager testComponentManager;
testComponentManager.initialize();
ObjectComponentManager objectComponentManager;
objectComponentManager.addComponentManager(ComponentType::TEST, &testComponentManager);
ObjectType testObject;
testObject.components[0] = ComponentType::TEST;
testObject.totalUsedComponents = 1;
objectComponentManager.addObjectType(ObjectTypeID::TEST, testObject);
std::cout << "First object addr: " << objectComponentManager.createObjectOfTypeID(ObjectTypeID::TEST) << "\n";
{
ComponentUpdateParams updateParams;
updateParams.timeStep = 0.016;
objectComponentManager.updateComponentManagerOfType(ComponentType::TEST, updateParams);
objectComponentManager.destroyObjectsWithRequestedDestruction();
}
std::cout << "Destroying all objects\n";
objectComponentManager.destroyAllActiveObjects();
return 1;
}
Loading…
Cancel
Save