Compare commits

...

6 Commits

Author SHA1 Message Date
cb545da50f Entity Spatial Component API draft. 2023-03-12 14:19:58 +00:00
4ab31de209 Entity System API draft. 2023-03-12 13:16:48 +00:00
5c4137506b Entity Scene API draft 2023-03-12 12:58:18 +00:00
cc5400587c Entity Section API draft 2023-03-12 12:05:01 +00:00
33b27fc9a1 Component API draft 2023-03-11 07:57:03 +00:00
387bc84985 UUID & start on IDs 2023-03-11 07:14:36 +00:00
12 changed files with 841 additions and 0 deletions

View File

@ -7,12 +7,14 @@ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
FILE(GLOB_RECURSE SOURCES
core/src/*.cpp
shadow-entity/src/*.cpp
shadow-renderer/src/*.cpp
shadow-reflection/src/*.cpp
shadow-utility/src/*.cpp
)
FILE(GLOB_RECURSE HEADERS
core/inc/*.h
shadow-entity/inc/*.h
shadow-renderer/inc/*.h
shadow-reflection/inc/*.h
shadow-utility/inc/*.h
@ -24,6 +26,7 @@ target_include_directories(shadow-engine
PRIVATE ${SDL2_INCLUDE_DIRS}
PUBLIC
core/inc
shadow-entity/inc
shadow-renderer/inc
shadow-reflection/inc
shadow-utility/inc

View File

@ -0,0 +1,64 @@
#pragma once
#include <cstdint>
#include <cstring>
#include <string>
// ShadowEntity temporary namespace
namespace SE {
/**
* Universally Unique ID.
* 128 Bits.
*
* Unique per runtime only - the suitability for serialization is undetermined.
*/
class UUID {
/**
* Data storage; 128 bits.
* 2 x 64 bit
* 4 x 32 bit
* 16 x 8 bit
*/
union Data {
uint64_t u64[2];
uint32_t u32[4];
uint8_t u8[16];
};
public:
// Create a new, unused, UUID.
static UUID Generate();
// Check whether the UUID is correctly formed.
static bool IsValidStr(char const* str);
// Create an empty UUID.
inline UUID() { std::memset(&data.u8, 0, 16); }
// Create a UUID based on the given values.
inline UUID(uint64_t i0, uint64_t i1) { data.u64[0] = i0; data.u64[1] = i1; }
inline UUID(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3) { data.u32[0] = i0; data.u32[1] = i1; data.u32[2] = i2; data.u32[3] = i3; }
inline explicit UUID(std::string const& str) : UUID(str.c_str()) {}
// Create a UUID from the given format.
explicit UUID(char const* str);
// Check whether the UUID is nonzero.
inline bool IsValid() const { return data.u64[0] != 0 && data.u64[1] != 0; }
// Set the UUID to zero.
inline void Clear() { std::memset(&data.u8, 0, 16); }
// Get a section of the UUID's data as the given bit width.
inline uint8_t GetU8(size_t idx) const { return data.u8[idx]; }
inline uint32_t GetU32(size_t idx) const { return data.u32[idx]; }
inline uint64_t GetU64(size_t idx) const { return data.u64[idx]; }
// Check whether this and a given UUID are in/equal.
__inline bool operator==(UUID const& other) const { return data.u64[0] == other.data.u64[0] && data.u64[1] == other.data.u64[1]; }
__inline bool operator!=(UUID const& other) const { return !(*this == other); }
private:
Data data {};
};
}

View File

@ -0,0 +1,23 @@
#pragma once
#include <math/transform.h>
/**
* A temporary header that contains some of the bounds implementations.
*/
namespace Math {
/**
* A bounding box that can be rotated freely.
* Can be used as the collision box for an entity.
*/
struct OrientedBB {
OrientedBB() = default;
Quaternion orientation;
Vector center;
Vector extent;
};
}

View File

@ -0,0 +1,47 @@
#pragma once
/**
* A temporary header that contains some of the core transform logic.
*
*/
#include <xmmintrin.h>
namespace Math {
struct alignas(16) Vector {
Vector() = default;
union {
struct { float x, y, z, w; };
__m128 data;
};
};
struct alignas(16) Quaternion {
inline Quaternion() = default;
union {
struct { float x, y, z, w; };
__m128 data;
};
};
class Transform {
public:
Transform() = default;
const Vector& GetTranslation() const { return translation; }
const Quaternion& GetRotation() const { return rotation; }
inline Vector GetRightVector() const;
inline Vector GetForwardVector() const;
inline Vector GetUpVector() const;
private:
Quaternion rotation;
Vector translation;
Vector scale;
};
}

View File

@ -0,0 +1,56 @@
#include <id/UUID.h>
namespace SE {
static_assert(sizeof(UUID) == 16, "UUID has incorrect size");
/**
* Verify that a string has the correct format;
* XXXXXXXX-XXXX-XXX-XXXXX-XXXXXXXXXXXX
*
* The length must be 36.
* There must be dashes at index 8, 13, 18 and 23.
* @param str the input string
* @return whether the UUID string is correctly formed
*/
bool UUID::IsValidStr(const char *str) {
size_t const len = strlen(str);
if (len != 36) return false;
for (size_t i = 0; i < len; i++) {
char c = str[i];
if (c == '-') {
if (i != 8 && i != 13 && i != 18 && i != 23) return false;
} else if (! std::isxdigit(c)) {
return false;
}
}
return true;
}
UUID::UUID(char const* str ) {
// A single byte is two hex characters.
// Store them here so that we can use them later.
char c0 = '\0', c1;
size_t const len = strlen( str );
uint32_t byteIdx = 0;
for (size_t i = 0; i < len; i++ ) {
char const c = str[i];
if ( c == '-' )
continue;
// Scan for pairs of characters.
// Only assign a byte if two have been parsed.
if (c0 == '\0') {
c0 = c;
} else {
c1 = c;
data.u8[byteIdx++] = std::stoi(std::string(c0, c1));
// Reset the first char so that we can return to scanning a pair.
c0 = '\0';
}
}
}
}

View File

@ -0,0 +1,92 @@
#pragma once
#include <cstdint>
#include "id/ID.h"
namespace SE {
/**
* A Component is a part of an Entity that stores and manages data.
* This data is held separately from the Entity that requests it.
*
* Components can be Spatial (ie. Position, Rotation).
* Components can also be Visual (ie. Mesh, Collider).
* Components are part of the larger Entity-Component-System architecture.
*
* Systems operate over these Components.
* Entities may have their own Systems, and each Scene has its own set of global Systems.
* Components may be registered to only one of these.
*
* EntityComponent classes are not singleton; new EntityComponent(..) is valid.
*
*/
class EntityComponent {
public:
/**
* The Component's possible statuses.
*/
enum class Status: uint8_t {
Unloaded, // The component is not yet loaded.
Loading, // The component is being loaded.
Loaded, // The component is finished loading, but is not yet populated with data.
Failed, // The component encountered an error while loading.
Initialized // The component is finished loading, and is populated with data.
};
virtual ~EntityComponent();
// Get the ComponentID.
inline ComponentID const& GetID() const { return id; }
// Get the Name of this Component; guaranteed to be unique in a given entity.
inline std::string& GetName() { return name; }
// Get the Entity that owns this Component.
inline EntityID const& GetParent() const { return owner; }
inline Status GetStatus() const { return status; }
// Check Status
inline bool IsLoaded() const { return status == Status::Loaded; }
inline bool IsLoading() const { return status == Status::Loading; }
inline bool IsUnloaded() const { return status == Status::Unloaded; }
inline bool Failed() const { return status == Status::Failed; }
inline bool Initialized() const { return status == Status::Initialized; }
// Whether one instance of this Component is allowed per Entity
virtual bool IsSingleton() const { return false; }
protected:
EntityComponent() = default;
EntityComponent(std::string& name) : name(name) {}
// Load Component data. May perform background ops.
virtual void Load() = 0;
// Unload Component data. Must be blocking.
virtual void Unload() = 0;
// Check that everything went properly.
virtual void UpdateStatus() = 0;
// Update the status to Initialized. Must only be called if checks passed.
// The status must be Loaded.
virtual void Initialize() { status = Status::Initialized; }
// Prepare for unloading the Component. Must be called before the process begins.
// The status must be Initialized.
virtual void Close() { status == Status::Loaded; }
private:
// This Component's unique ID.
ComponentID id = ComponentID::Generate();
// The Entity that requested this Component.
EntityID owner;
// The name of the Component, for visualization
std::string name;
// The status of the Component
Status status = Status::Unloaded;
// Whether this Component is registered to the Entity's Local Systems.
bool localComponent = false;
// Whether this Component is registered to the Scene's Global Systems.
bool globalComponent = false;
};
}

View File

@ -0,0 +1,130 @@
#pragma once
#include <array>
namespace SE {
/**
* An Entity Component that has a Spatial context.
* AKA, a Component with a position, a rotation, and a size.
*
* Spatial Components may exist in a hierarchy; where each subsequent object inherits the spatial positions of its' parents.
* This allows for things like complex articulation of large machines, etc.
*/
class EntitySpatialComponent : public EntityComponent {
public:
// Whether this is the root spatial component for this Entity.
inline bool IsSpatialRoot() const { return parent == nullptr; }
// Fetch the transforms and bounds.
inline Math::Transform const& GetLocalTransform() const { return transform; }
inline Math::OrientedBB const& GetLocalBounds() const { return bounds; }
inline Math::Transform const& GetWorldTransform() const { return worldTransform; }
inline Math::OrientedBB const& GetWorldBounds() const { return worldBounds; }
// Get the position in world-space.
inline Math::Vector const& GetPosition() const { return worldTransform.GetTranslation(); }
// Get the rotation in world-space.
inline Math::Quaternion const& GetRotation() const { return worldTransform.GetRotation(); }
// Get vectors relative to this spatial component.
inline Math::Vector GetForwardVector() const { return worldTransform.GetForwardVector(); }
inline Math::Vector GetUpVector() const { return worldTransform.GetUpVector(); }
inline Math::Vector GetRightVector() const { return worldTransform.GetRightVector(); }
// Update the local and world transforms
inline void SetLocalTransform(Math::Transform const& newTransform);
inline void SetWorldTransform(Math::Transform const& newTransform);
// Move this component by the specified amount of transform, rotation
inline void MoveBy(Math::Transform const& delta);
// Is there a child spatial component
inline bool HasChildren() const { return !children.empty(); }
// Get the ID of the parent of this Spatial Component
inline ComponentID const& GetParentID() const { return parent->GetID(); }
// Get the transform of the parent component
inline Math::Transform const& GetParentTransform() const { return parent->worldTransform; }
// Fetch how deep in the spatial hierarchy this Component is.
size_t GetHierarchyDepth(bool singleEntity = true) const;
// Check if we are a child of a given Component
bool IsChildOf(EntitySpatialComponent const* parent) const;
// Get the ID of the socket we are attached to
inline std::string const& GetAttachmentSocketID() const { return attachmentSocket; }
// Set the name of the socket we wish to be attached to.
inline void SetAttachmentSocket(std::string& id) { attachmentSocket = id;}
// Fetch the transform of a specific attachment.
Math::Transform const& GetAttachmentTransform(std::string& id) const;
// Whether this Component supports local scaling
virtual bool LocalScale() const { return false; }
// Fetch the local scale, if supported. { 1, 1, 1 } otherwise.
virtual std::array<float, 3> const& GetLocalScale() const { static auto ones = std::array<float, 3> { 1, 1, 1 }; return ones; }
// Convert a given world-space transform to a model-space transform.
inline Math::Transform const& ConvertWorldToLocalTransform(Math::Transform const& world);
protected:
virtual void Initialize() override;
// Set the local scale, if supported
virtual void SetLocalScale(std::array<float, 3> const& newScale) {}
// Calculate the local bounding box for the Component; the position should always be close to origin.
virtual Math::OrientedBB CalculateBounds() const;
// Update the local and world bounds for the Component.
void UpdateBounds();
// Attempt to find the given Socket in this Component, and return its' Transform if present.
bool GetAttachmentTransform(std::string& socketId, Math::Transform& out) const;
virtual bool FindAttachmentTransform(std::string& socketId, Math::Transform& out) const;
// Whether this Component has the given Socket.
// Default: No sockets.
virtual bool HasSocket(std::string& socket) const { return false;}
// Process the creation/destruction/movement of a Socket.
void UpdateSockets();
// Called whenever the World Transform is updated.
virtual void OnMoved() {}
// Set the World Transform for a component.
// Skips a lot of internal processing.
inline void SetWorldTransform(Math::Transform& newTransform, bool callback = true);
private:
inline void CalculateWorldTransform(bool callback = true);
// The location of this Component, relative to the world.
Math::Transform transform;
// The collision boundary of this Component.
Math::OrientedBB bounds;
// The world transform of this component; how to get to the position from the world origin.
Math::Transform worldTransform;
Math::OrientedBB worldBounds;
// The parent of this Spatial Component
EntitySpatialComponent* parent = nullptr;
// The socket (attachment point) of the parent entity that this Component is attached to.
std::string attachmentSocket;
// The Components that are attached to this Component.
std::vector<EntitySpatialComponent*> children;
};
}

View File

@ -0,0 +1,61 @@
#pragma once
#include <id/UUID.h> // Shadow-Engine/core/inc/id
namespace SE {
// An ID for a section of the scene (which may be unloaded separately of the level; for ie. open world Cells.)
using EntitySectionID = UUID;
// An ID for a scene (which contains all sections and entities).
using EntitySceneID = UUID;
/**
* Contains the common data and functions for the Entity System's identifiers.
*/
struct IDContainer {
public:
IDContainer() = default;
explicit IDContainer(uint64_t v) : id(v) {}
// Check if the ID is valid (non-zero)
__inline virtual bool Valid() const { return id != 0; }
// Set this ID to be invalid (zero).
__inline virtual void Invalidate() { id = 0; }
// Check for in/equality against another ID.
__inline virtual bool operator==(IDContainer const& other) const { return id == other.id; }
__inline virtual bool operator!=(IDContainer const& other) const { return id != other.id; }
__inline virtual bool operator<(IDContainer const& other) const { return id < other.id; }
uint64_t id;
};
/**
* An ID used for an Entity.
* Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the entities within).
*/
struct EntityID : public IDContainer {
/**
* @return a new, unused Entity ID.
*/
static EntityID Generate();
EntityID() = default;
explicit EntityID(uint64_t v) : IDContainer(v) {}
};
/**
* An ID used for a Component (a segment of data attached to an Entity).
* Is only guaranteed to be unique in the current scene (ie. a level change may also change the IDs of the components within).
*/
struct ComponentID : public IDContainer {
/**
* @return a new, unused Component ID.
*/
static ComponentID Generate();
ComponentID() = default;
explicit ComponentID(uint64_t v) : IDContainer(v) {}
};
}

View File

@ -0,0 +1,172 @@
#pragma once
#include <scene/EntitySection.h>
namespace SE {
/**
* A scene is a collection of Sections that contain Entities.
* Scenes have support for asynchronous task management.
* Scenes have their own input state, local to the world.
* Scenes have Systems that operate over all Scene Components of all entities within.
* Scenes can be either for Tools or for Gameplay.
*
* Scenes each have a primary viewport and any number of secondary viewports.
*
* Scenes contain Sections, which contain Entities.
* One of the Sections in the Scene is always loaded; similar to Spawn Chunks.
*
* Scenes have a local timescale, which can be increased to make physics and logic run faster.
*/
class EntityScene {
/**
* The type of the scene.
* More-or-less exists to allow differentiating between an Editor and a Runtime.
*/
enum Type {
TOOLS, // This scene exists for tooling support, ie. the builtin editor.
GAME // This scene exists for gameplay, ie. the runtime.
};
public:
EntityScene(Type wType = Type::GAME);
~EntityScene();
// Fetch the ID of this scene.
inline EntitySceneID const& GetID() const { return id; }
// Whether this is a Gameplay scene.
inline bool IsGameScene() const { return type == Type::GAME; }
// Prepare the Scene for processing entity updates. TODO: Systems.
void Initialize();
// Prepare all Regions and Entities for the closing of the Scene.
void Shutdown();
// Whether or not updates are suspended. ( Game is Paused )
inline bool IsSuspended() const { return suspended; }
// Stop all Regions, Entities and Systems from updating.
void Suspend() { suspended = true; }
// Resume updates to the Entities and Systems within.
void Resume() { suspended = false; }
// Run a single tick of Entity and System updates. TODO: context
void Update();
// Handle Entities, Regions, Resources that want to load or unload.
void UpdateLoads();
// TODO: Systems
// TODO: Input
// Check whether time is paused; the Scene itself can be unpaused during this, to allow movement through a paused world.
inline bool IsTimePaused() const { return timeScale <= 0.0f; }
// Pause time in the Scene.
inline void PauseTime() { timeScale = 0.0f; }
// The Time Scale for the Scene
inline float GetTimeScale() const { return timeScale; }
// Set the Time Scale for the Scene.
inline void SetTimeScale(float newScale) { timeScale = newScale; }
// Request a Time Step through a paused world.
inline void TimeStep() { timeStepNeeded = true; }
// Whether a Scene with Paused Time needs a time step
inline bool TimeStepRequested() const { return timeStepNeeded; }
// How long a single Time Step last, at most.
inline float TimeStepLength() const { return timeStepLength; }
// Set the maximum length of a Time Step.
inline void SetTimeStepLength(float newStep) { timeStepLength = newStep; }
// TODO: Viewports
// Fetch the Section that is always present and loaded; be careful adding things to this.
EntitySection* GetPersistentSection() { return sections[0]; }
EntitySection const* GetPersistentSection() const { return sections[0]; }
// Get the first Section that is not persistent, if present.
EntitySection* GetFirstNonPersistentSection() { return sections.size() > 1 ? sections[1] : nullptr; }
EntitySection const* GetFirstNonPersistentSection() const { return sections.size() > 1 ? sections[1] : nullptr; }
// Create a transient (memory-resident) Section.
EntitySection* CreateTransientSection();
// Get a Section from memory.
EntitySection const* GetSection(EntitySectionID const& sID) const;
EntitySection* GetSection(EntitySectionID const& sID);
// Whether anything is loading into a Section
bool IsLoading() const;
// Whether a Section exists in this scene
bool HasSection(const EntitySectionID& eID) const;
// Whether the Section in this scene is loaded.
bool isSectionLoaded(const EntitySectionID& sID) const;
// Load a Section from the Scene file into memory.
EntitySectionID LoadSection(EntitySectionID& section);
// Unload a section from memory; delete every entity within.
void UnloadSection(EntitySectionID& section);
inline Entity* FindEntity(EntityID& entity) const {
Entity* e = nullptr;
for (auto const& section : sections) {
e = section->GetEntity(entity);
if (e != nullptr) break;
}
return e;
}
private:
// The ID of this Scene.
EntitySceneID id = UUID::Generate();
// The system that manages asynchronous background tasks for this Scene, such as Systems and Entity management.
// Tasks* tasks;
// The local Input State, which exists relative to the viewport, allowing for tri picking.
// Input input;
// TODO: Loading/Initialization
// TODO: Scene Systems
// The type of this Scene; default to game.
Type type = Type::GAME;
// Whether or not everything in the map is ready to start.
bool initialized = false;
// Whether or not everything in the map is paused; no logic runs, nothing updates.
bool suspended = false;
// TODO: Viewport
// The list of Sections in this Scene.
std::vector<EntitySection*> sections;
// Every entity that is eligible for updates.
// Ie. Every Initialized Entity in every Loaded Section.
std::vector<Entity*> entityUpdateList;
//TODO: Scene Systems 2
// The multiplier for the number of steps per second (1/timescale * stepInterval)
float timeScale = 1.0f;
// The maximum length of each time step; if a step goes over this, it is aborted and the next begins processing.
float timeStepLength = 1.0f/30;
// Whether or not a new Time Step should begin immediately. Only applicable to Scenes with Paused Time.
bool timeStepNeeded = false;
};
}

View File

@ -0,0 +1,132 @@
#pragma once
#include <vector>
#include <map>
namespace SE {
// Forward declaration, see inc/entity/Entity.h
class Entity;
/**
* A section is a collection of Entities with linked runtime.
* ie. a game level could have one giant linked Section.
* a cell of an open-world game could represent one Region,
* and rooms of a BSP level could represent one Region.
*/
class EntitySection {
/**
* The possible statuses for this Section.
* Entities are not valid until the Loaded status is reached.
*/
enum class Status {
Failed = -1, // An error occurred during loading.
Unloaded = 0, // The Section is present, but none of the data is populated.
Loading, // The Section is being loaded with data.
Loaded, // The Section is present and contains valid data.
Unloading // The Section is present but preparing to unload.
};
/**
* Request the deletion of an entity, after ie. destruction or death.
*/
struct PendingRemoval {
PendingRemoval(Entity* entity, bool destroy)
: entity(entity), destroy(destroy) {}
Entity* entity = nullptr;
bool destroy = false;
};
public:
EntitySection();
EntitySection(EntitySection const& section);
EntitySection(EntitySection&& section);
~EntitySection();
EntitySection& operator=(EntitySection const& section);
EntitySection& operator=(EntitySection&& section);
// Get the ID of this Section
inline EntitySectionID GetID() const { return id; }
// Whether or not this Section was generated, without being loaded from disk.
inline bool IsTransient() const { return isTransient; }
// TODO: Contexts?
void Load();
void Unload();
// Check that everything went properly, and update state accordingly.
bool UpdateState();
// Whether there are any pending entity removals or additions.
inline bool HasPendingEntityChanges() const { return (entitiesPendingLoading.size() + entitiesPendingRemoval.size()) > 0; }
bool IsLoading() const { return status == Status::Loading; }
inline bool IsLoaded() const { return status == Status::Loaded; }
inline bool IsUnloaded() const { return status == Status::Unloaded; }
inline bool LoadingFailed() const { return status == Status::Failed; }
// Get the total number of entities in the section
inline size_t GetEntityCount() const { return entities.size(); }
// Get all entities in the region.
inline std::vector<Entity*> const& GetEntities() const { return entities; }
// Get a specific entity by its' ID.
inline Entity* GetEntity(const EntityID& eID) const {
auto i = entityLookup.find(eID);
return (i != entityLookup.end()) ? i->second : nullptr;
}
// Check whether this region contains the specified entity.
inline bool ContainsEntity(const EntityID& eID) const { return GetEntity(eID) != nullptr; }
// Add all of the specified entities to the region.
// Transfers ownership if already present.
// This operation takes time, but is guaranteed to be finished by the start of the next frame.
void AddEntities(const std::vector<Entity*>& entities);
// Add an entity to the region.
// Transfers ownership if already present.
void AddEntity(Entity* entity);
// Queue an entity for removal from this region.
// Transfers ownership to the caller.
// This operation takes time, and no guarantee is given for completion.
Entity* RemoveEntity(const EntityID& eID);
// Queue an entity for unloading from this region.
// This operation takes time, and no guarantee is given for completion.
void DestroyEntity(const EntityID& eID);
private:
// A callback for when an entity's state changes (ie. when loading)
void EntityStateUpdated(Entity* entity);
// TODO: Process Loading, Unloading, Entity Shutdown, Entity Removal, Entity Loading.
private:
EntitySectionID id = UUID::Generate();
Status status = Status::Unloaded;
// Transient = created on-the-fly, rather than existing on disk.
bool const isTransient = false;
// The list of every entity in the Section, including those that are not yet loaded, or those that are due to be unloaded.
std::vector<Entity*> entities;
// A fast map for looking up entities by ID.
std::map<EntityID, Entity*> entityLookup;
// The list of entities that are currently being initialized to be put into the Section.
std::vector<Entity*> entitiesLoading;
// The list of entities that are waiting to be loaded.
std::vector<Entity*> entitiesPendingLoading;
// The list of entities that are waiting to be removed.
std::vector<Entity*> entitiesPendingRemoval;
};
}

View File

@ -0,0 +1,45 @@
#pragma once
#include <string>
namespace SE {
// Forward declaration.
class EntityComponent;
/**
* A System is a routine that operates over the Components in an Entity.
* A System may be local to a given Entity, or it may be glboal to the Scene.
*
* Components must be registered to the System that works over them.
*
* TODO: Think of better names for these functions
*/
class EntitySystem {
public:
virtual ~EntitySystem();
virtual std::string& GetName() const = 0;
// Pre-Component Register
virtual void Initialize() {}
// Post-Component Register
virtual void Initialized() {}
// Pre-Component Unregister
virtual void Uninitialize() {}
// Post-Component Unregister
virtual void Uninitialized() {}
protected:
// Register a Component with this System
virtual void RegisterComponent(EntityComponent* component) = 0;
// Unregister a Component from this system
virtual void UnregisterComponent(EntityComponent* component) = 0;
// Update over all Components. TODO: Context?
virtual void Update() = 0;
};
}

View File

@ -0,0 +1,16 @@
#include <id/ID.h>
#include <atomic>
namespace SE {
static std::atomic<uint64_t> entityID = 1;
EntityID EntityID::Generate() {
EntityID id(entityID++);
return id;
}
static std::atomic<uint64_t> componentID = 1;
ComponentID ComponentID::Generate() {
ComponentID id(componentID++);
return id;
}
}