Skip to content

Instantly share code, notes, and snippets.

@veryjos
Created May 20, 2018 02:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save veryjos/ae448fa48a12d1e0926375866c1ab407 to your computer and use it in GitHub Desktop.
Save veryjos/ae448fa48a12d1e0926375866c1ab407 to your computer and use it in GitHub Desktop.
#pragma once
#include <memory>
#include <unordered_map>
#include <vector>
namespace tdrp {
// ComponentID's uniquely identify a Component
using ComponentID = int;
struct ComponentMeta {
const char* name = nullptr;
const ComponentID componentID = -1;
};
/**
* Base class for each Component.
*
* Anything that wants to implement Component should derive from this class
* and also expand the COMPONENT_ENABLE inside the class before anything else
*/
class Component {
public:
Component() {};
virtual ~Component() {};
virtual const ComponentMeta& GetComponentMeta() const = 0;
virtual ComponentID GetComponentID() const {
return GetComponentMeta().componentID;
};
protected:
const ComponentMeta _2drp_com_meta;
protected:
static ComponentID AllocComponentID() {
static ComponentID componentIDCounter;
return componentIDCounter++;
};
static ComponentMeta AllocComponentMeta(const char* name) {
return {
name,
AllocComponentID()
};
};
};
/**
* ComponentEntity can hold any number of Components
*/
class ComponentEntity {
public:
ComponentEntity() {};
virtual ~ComponentEntity() {};
/**
* Adds a component by template parameter.
* Accepts any number of arguments for the constructor..
*
* @return true if success, false if fail
*/
template <typename T, typename ...Args>
bool AddComponent(Args ...args) {
// Don't allow adding two of the same component
if (HasComponent<T>()) {
return false;
}
// Create and add the component
auto component = std::make_shared<T>(args...);
m_components[T::GetMeta().componentID] = std::move(component);
return true;
};
template <typename T>
bool AddComponent() {
if (HasComponent<T>()) {
return false;
}
// Create and add the component
auto component = std::make_shared<T>();
m_components[T::GetMeta().componentID] = std::move(component);
return true;
};
/**
* Adds a component.
*
* @return true if success, false if fail
*/
bool AddComponent(const std::shared_ptr<Component>& component) {
// Don't allow adding two of the same component
if (HasComponent(component->GetComponentMeta().componentID)) {
return false;
}
m_components[component->GetComponentMeta().componentID] = std::move(component);
return true;
};
/**
* Checks if this entity has as specific component type by template parameter.
*
* @retunr true if yes, false if no
*/
template <typename T>
bool HasComponent() {
return HasComponent(T::GetMeta().componentID);
};
/**
* Checks if this entity has a specific component type
*
* @return true if yes, false if no
*/
bool HasComponent(const ComponentID componentID) {
return m_components.find(componentID) != m_components.end();
};
/**
* Gets a component, if this ComponentEntity has it.
*/
template <typename T>
std::weak_ptr<T> GetComponent() {
if (!HasComponent<T>()) {
return std::weak_ptr<T>();
}
return std::weak_ptr(std::static_pointer_cast<T>(m_components[T::GetMeta().componentID]));
};
private:
std::unordered_map<ComponentID, std::shared_ptr<Component>> m_components;
};
}
#define COMPONENT_ENABLE(name) \
private: \
static inline ComponentMeta _2d_com_meta_ = tdrp::Component::AllocComponentMeta(#name); \
public: \
static const ComponentMeta& GetMeta() { \
return _2d_com_meta_; \
} \
\
const ComponentMeta& GetComponentMeta() const override { \
return name::GetMeta(); \
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment