Basic ECS
This commit is contained in:
@@ -19,9 +19,6 @@
|
||||
#include "entity/entitymanager.h"
|
||||
#include "game/game.h"
|
||||
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
|
||||
engine_t ENGINE;
|
||||
|
||||
errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
@@ -42,12 +39,14 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
entityManagerInit();
|
||||
errorChain(gameInit());
|
||||
|
||||
entityid_t ent0 = entityAdd();
|
||||
entityAddComponent(ent0, ENTITY_POSITION_DATA);
|
||||
entityAddComponent(ent0, ENTITY_CAMERA_DATA);
|
||||
// FOF
|
||||
entityid_t ent0 = entityManagerAdd();
|
||||
componentid_t ent0c0 = entityAddComponent(ent0, COMPONENT_TYPE_POSITION);
|
||||
|
||||
entityid_t ent1 = entityAdd();
|
||||
entityAddComponent(ent0, ENTITY_POSITION_DATA);
|
||||
entityid_t ent1 = entityManagerAdd();
|
||||
|
||||
entityid_t ent2 = entityManagerAdd();
|
||||
// EOF
|
||||
|
||||
// Run the init script.
|
||||
scriptcontext_t ctx;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entity.c
|
||||
entitycomponent.c
|
||||
entitymanager.c
|
||||
component.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
# Subdirs
|
||||
add_subdirectory(component)
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "assert/assert.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
componentdefinition_t COMPONENT_DEFINITIONS[] = {
|
||||
[COMPONENT_TYPE_NULL] = { 0 },
|
||||
|
||||
#define X(enumName, type, field, iMethod, dMethod) \
|
||||
[COMPONENT_TYPE_##enumName] = { .init = iMethod, .dispose = dMethod },
|
||||
#include "componentlist.h"
|
||||
#undef X
|
||||
|
||||
[COMPONENT_TYPE_COUNT] = { 0 }
|
||||
};
|
||||
|
||||
void componentInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
assertTrue(type < COMPONENT_TYPE_COUNT, "Component type OOB");
|
||||
assertTrue(type != COMPONENT_TYPE_NULL, "Cannot initialize null component");
|
||||
|
||||
component_t *cmp = &ENTITY_MANAGER.entities[entityId].components[componentId];
|
||||
memoryZero(cmp, sizeof(component_t));
|
||||
|
||||
cmp->type = type;
|
||||
if(COMPONENT_DEFINITIONS[type].init) {
|
||||
COMPONENT_DEFINITIONS[type].init(entityId, componentId);
|
||||
}
|
||||
}
|
||||
|
||||
void * componentGetData(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
|
||||
component_t *cmp = &ENTITY_MANAGER.entities[entityId].components[componentId];
|
||||
if(cmp->type == COMPONENT_TYPE_NULL) return NULL;
|
||||
|
||||
return &cmp->data;
|
||||
}
|
||||
|
||||
void componentDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
assertTrue(entityId < ENTITY_COUNT_MAX, "Entity ID OOB");
|
||||
assertTrue(componentId < ENTITY_COMPONENT_COUNT_MAX, "Component ID OOB");
|
||||
|
||||
component_t *cmp = &ENTITY_MANAGER.entities[entityId].components[componentId];
|
||||
if(cmp->type == COMPONENT_TYPE_NULL) return;
|
||||
|
||||
if(COMPONENT_DEFINITIONS[cmp->type].dispose) {
|
||||
COMPONENT_DEFINITIONS[cmp->type].dispose(entityId, componentId);
|
||||
}
|
||||
|
||||
cmp->type = COMPONENT_TYPE_NULL;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitybase.h"
|
||||
|
||||
#define X(enumName, type, field, init, dispose) \
|
||||
// do nothing
|
||||
#include "componentlist.h"
|
||||
#undef X
|
||||
|
||||
typedef union {
|
||||
#define X(enumName, type, field, init, dispose) type field;
|
||||
#include "componentlist.h"
|
||||
#undef X
|
||||
} componentdata_t;
|
||||
|
||||
typedef struct {
|
||||
void (*init)(const entityid_t, const componentid_t);
|
||||
void (*dispose)(const entityid_t, const componentid_t);
|
||||
} componentdefinition_t;
|
||||
|
||||
typedef enum {
|
||||
COMPONENT_TYPE_NULL,
|
||||
|
||||
#define X(enumName, type, field, init, dispose) \
|
||||
COMPONENT_TYPE_##enumName,
|
||||
#include "componentlist.h"
|
||||
#undef X
|
||||
|
||||
COMPONENT_TYPE_COUNT
|
||||
} componenttype_t;
|
||||
|
||||
typedef struct {
|
||||
componenttype_t type;
|
||||
componentdata_t data;
|
||||
} component_t;
|
||||
|
||||
extern componentdefinition_t COMPONENT_DEFINITIONS[];
|
||||
|
||||
/**
|
||||
* Initializes a component of the given type for the entity with component ID.
|
||||
*
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @param type The type of the component to initialize.
|
||||
*/
|
||||
void componentInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId,
|
||||
const componenttype_t type
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the pointer to the data of a component for the entity with component ID.
|
||||
*
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
* @return A pointer to the component data.
|
||||
*/
|
||||
void * componentGetData(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of a component for the entity with component ID.
|
||||
*
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void componentDispose(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -1,12 +1,10 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
add_subdirectory(display)
|
||||
entityposition.c
|
||||
)
|
||||
@@ -1,12 +0,0 @@
|
||||
# Copyright (c) 2026 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
entityposition.c
|
||||
)
|
||||
|
||||
# Subdirectories
|
||||
@@ -1,20 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entitycamera.h"
|
||||
|
||||
ENTITY_COMPONENT_DEFINE(entitycamera_t, entityCameraInit, NULL)
|
||||
|
||||
void entityCameraInit(const entityandentitycomponentid_t id) {
|
||||
entityid_t entityId =
|
||||
|
||||
// Default to perspective camera with default values.
|
||||
data->projType = CAMERA_PROJECTION_TYPE_PERSPECTIVE;
|
||||
data->perspective.fov = glm_rad(45.0f);
|
||||
data->nearClip = 0.1f;
|
||||
data->farClip = 10000.0f;
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitymanager.h"
|
||||
#include "display/camera/camera.h"
|
||||
|
||||
#define ENTITY_CAMERA_COUNT_MAX 2
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
struct {
|
||||
float_t fov;
|
||||
} perspective;
|
||||
|
||||
struct {
|
||||
float_t left;
|
||||
float_t right;
|
||||
float_t top;
|
||||
float_t bottom;
|
||||
} orthographic;
|
||||
};
|
||||
|
||||
float_t nearClip;
|
||||
float_t farClip;
|
||||
|
||||
cameraprojectiontype_t projType;
|
||||
} entitycamera_t;
|
||||
|
||||
/**
|
||||
* Initializes the camera component for an entity.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
*/
|
||||
void entityCameraInit(const entityandentitycomponentid_t id);
|
||||
@@ -1,26 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entityposition.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
entityposition_t ENTITY_POSITION_DATA[ENTITY_COUNT_MAX];
|
||||
|
||||
void entityPositionInit(const entityid_t id, entityposition_t *data) {
|
||||
memoryZero(data, sizeof(entityposition_t));
|
||||
|
||||
glm_mat4_identity(data->transform);
|
||||
}
|
||||
|
||||
void entityPositionLookAt(
|
||||
const entityid_t id,
|
||||
const vec3 target,
|
||||
const vec3 up,
|
||||
const vec3 eye
|
||||
) {
|
||||
glm_lookat(eye, target, up, ENTITY_POSITION_DATA[id].transform);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entity.h"
|
||||
|
||||
typedef struct {
|
||||
mat4 transform;
|
||||
} entityposition_t;
|
||||
|
||||
/**
|
||||
* Initializes the position component for an entity.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
*/
|
||||
void entityPositionInit(const entityandentitycomponentid_t id);
|
||||
|
||||
/**
|
||||
* Sets the position component of an entity to look at a target point.
|
||||
*
|
||||
* @param id The component entity id.
|
||||
* @param target The target point to look at.
|
||||
* @param up The up vector to use for the look at calculation.
|
||||
* @param eye The eye position to use for the look at calculation.
|
||||
*/
|
||||
void entityPositionLookAt(
|
||||
const entityandentitycomponentid_t id,
|
||||
const vec3 target,
|
||||
const vec3 up,
|
||||
const vec3 eye
|
||||
);
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity/entitymanager.h"
|
||||
|
||||
void entityPositionInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
) {
|
||||
entityposition_t *pos = componentGetData(entityId, componentId);
|
||||
|
||||
glm_mat4_identity(pos->transform);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entity/entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
mat4 transform;
|
||||
} entityposition_t;
|
||||
|
||||
/**
|
||||
* Initialize the entity position component.
|
||||
*
|
||||
* @param entityId The entity ID.
|
||||
* @param componentId The component ID.
|
||||
*/
|
||||
void entityPositionInit(
|
||||
const entityid_t entityId,
|
||||
const componentid_t componentId
|
||||
);
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "entity/component/entityposition.h"
|
||||
|
||||
X(POSITION, entityposition_t, position, entityPositionInit, NULL)
|
||||
+32
-93
@@ -9,98 +9,37 @@
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
entityid_t entityAdd() {
|
||||
entityid_t id = 0xFF;
|
||||
|
||||
// Quick search for an available slot.
|
||||
for(uint8_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
id = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if(id >= ENTITY_COUNT_MAX) {
|
||||
assertUnreachable("No available entity slots.");
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
// Init the entity.
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
memoryZero(entity, sizeof(entity_t));
|
||||
entity->state |= ENTITY_STATE_ACTIVE;
|
||||
return id;
|
||||
}
|
||||
|
||||
entitycomponentid_t entityAddComponent(
|
||||
const entityid_t id,
|
||||
void *componentData
|
||||
) {
|
||||
entitycomponentid_t compId = entityComponentGetByData(componentData);
|
||||
assertTrue(compId != 0xFF, "Component not found in entity manager.");
|
||||
|
||||
// Find empty entity slot.
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[compId];
|
||||
uint8_t x = 0xFF;// Entity slot within the component
|
||||
for(uint8_t i = 0; i < comp->entityMax; i++) {
|
||||
if(comp->entities[i] != 0xFF) {
|
||||
continue;
|
||||
}
|
||||
x = i;
|
||||
break;
|
||||
}
|
||||
assertTrue(x != 0xFF, "No available component entity slots.");
|
||||
|
||||
// Set the entity id.
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
assertTrue(
|
||||
entity->componentCount < ENTITY_COMPONENT_COUNT_MAX,
|
||||
"Entity has too many components."
|
||||
);
|
||||
comp->entities[x] = id;
|
||||
entity->components[entity->componentCount++] = compId;
|
||||
|
||||
if(comp->init != NULL) {
|
||||
void *data = (uint8_t *)comp->data + (comp->dataSize * x);
|
||||
comp->init(id, data);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
void entityRemove(const entityid_t id) {
|
||||
assertTrue(id < ENTITY_COUNT_MAX, "Invalid entity ID.");
|
||||
|
||||
entity_t *entity = &ENTITY_MANAGER.entities[id];
|
||||
entity->state &= ~ENTITY_STATE_ACTIVE;
|
||||
|
||||
// Remove components.
|
||||
for(uint8_t i = 0; i < entity->componentCount; i++) {
|
||||
entitycomponentid_t compId = entity->components[i];
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[compId];
|
||||
|
||||
// Find the component slot for this entity.
|
||||
uint8_t x = 0xFF;
|
||||
for(uint8_t j = 0; j < comp->entityMax; j++) {
|
||||
if(comp->entities[j] == id) {
|
||||
x = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTrue(x != 0xFF, "Entity does not have this component.");
|
||||
|
||||
// Clear the component slot.
|
||||
comp->entities[x] = 0xFF;
|
||||
|
||||
// Dispose
|
||||
if(comp->dispose != NULL) {
|
||||
void *data = (uint8_t *)comp->data + (comp->dataSize * x);
|
||||
comp->dispose(id, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entityid_t entityGetId(const entityandentitycomponentid_t id) {
|
||||
void entityInit(const entityid_t entityId) {
|
||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||
|
||||
memoryZero(ent, sizeof(entity_t));
|
||||
|
||||
ent->state |= ENTITY_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
componentid_t entityAddComponent(
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
) {
|
||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||
|
||||
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
||||
if(ent->components[i].type != COMPONENT_TYPE_NULL) continue;
|
||||
componentInit(entityId, i, type);
|
||||
return i;
|
||||
}
|
||||
|
||||
assertUnreachable("Entity has no more component slots available");
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void entityDispose(const entityid_t entityId) {
|
||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||
|
||||
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
||||
if(ent->components[i].type == COMPONENT_TYPE_NULL) continue;
|
||||
componentDispose(entityId, i);
|
||||
}
|
||||
|
||||
ent->state = 0;
|
||||
}
|
||||
+15
-24
@@ -6,46 +6,37 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitybase.h"
|
||||
#include "component.h"
|
||||
|
||||
#define ENTITY_STATE_ACTIVE (1 << 0)
|
||||
|
||||
typedef struct {
|
||||
entitycomponentid_t components[ENTITY_COMPONENT_COUNT_MAX];
|
||||
uint8_t componentCount;
|
||||
uint8_t state;
|
||||
component_t components[ENTITY_COMPONENT_COUNT_MAX];
|
||||
} entity_t;
|
||||
|
||||
/**
|
||||
* Adds an entity to the entity manager and initializes it.
|
||||
* Initializes an entity with the given ID.
|
||||
*
|
||||
* @return The ID of the added entity.
|
||||
* @param entityId The ID of the entity to initialize.
|
||||
*/
|
||||
entityid_t entityAdd();
|
||||
void entityInit(const entityid_t entityId);
|
||||
|
||||
/**
|
||||
* Adds a component to an entity.
|
||||
* Adds a component of the given type to the entity with the given ID.
|
||||
*
|
||||
* @param id The ID of the entity to add the component to.
|
||||
* @param componentData The data of the component to add.
|
||||
* @return The ID of the added component.
|
||||
* @param entityId The ID of the entity to add the component to.
|
||||
* @param type The type of the component to add.
|
||||
* @return The ID of the entity with component.
|
||||
*/
|
||||
entitycomponentid_t entityAddComponent(
|
||||
const entityid_t id,
|
||||
void *componentData
|
||||
componentid_t entityAddComponent(
|
||||
const entityid_t entityId,
|
||||
const componenttype_t type
|
||||
);
|
||||
|
||||
/**
|
||||
* Disposes of an entity with the given ID, this will dispose of its components.
|
||||
* Disposes of an entity with the given ID.
|
||||
*
|
||||
* @param id The ID of the entity to dispose.
|
||||
* @param entityId The ID of the entity to dispose of.
|
||||
*/
|
||||
void entityRemove(const entityid_t id);
|
||||
|
||||
/**
|
||||
* Gets an entity id by the entity and entity component id provided.
|
||||
*
|
||||
* @param id Id to get the entity id for.
|
||||
* @return The entity id.
|
||||
*/
|
||||
entityid_t entityGetId(const entityandentitycomponentid_t id);
|
||||
void entityDispose(const entityid_t entityId);
|
||||
@@ -8,10 +8,8 @@
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
#define ENTITY_COUNT_MAX 256
|
||||
#define ENTITY_COMPONENT_COUNT_MAX 16
|
||||
#define ENTITY_MANAGER_COMPONENT_COUNT_MAX 64
|
||||
#define ENTITY_COUNT_MAX 128
|
||||
#define ENTITY_COMPONENT_COUNT_MAX 24
|
||||
|
||||
typedef uint8_t entityid_t;
|
||||
typedef uint8_t entitycomponentid_t;
|
||||
typedef uint16_t entityandentitycomponentid_t;
|
||||
typedef uint8_t componentid_t;
|
||||
@@ -1,85 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
entitycomponentid_t entityComponentInit(
|
||||
void *data,
|
||||
const size_t dataSize,
|
||||
const uint8_t entityCountMax,
|
||||
void (*init)(const entityid_t id, void *data),
|
||||
void (*dispose)(const entityid_t id, void *data)
|
||||
) {
|
||||
assertNotNull(data, "Component data cannot be null.");
|
||||
assertTrue(dataSize > 0, "Component data size must be greater than 0.");
|
||||
assertTrue(entityCountMax > 0, "Component entity count max be at least 1");
|
||||
|
||||
// Get next available component slot.
|
||||
entitycomponentid_t componentIndex = 0xFF;
|
||||
for(uint8_t i = 0; i <ENTITY_MANAGER_COMPONENT_COUNT_MAX ; i++) {
|
||||
if(ENTITY_MANAGER.components[i].data != NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
componentIndex = i;
|
||||
break;
|
||||
}
|
||||
assertTrue(
|
||||
componentIndex < ENTITY_MANAGER_COMPONENT_COUNT_MAX,
|
||||
"No available component slots."
|
||||
);
|
||||
|
||||
entitycomponent_t *component = &ENTITY_MANAGER.components[componentIndex];
|
||||
memoryZero(component, sizeof(entitycomponent_t));
|
||||
component->data = data;
|
||||
component->dataSize = dataSize;
|
||||
component->entityMax = entityCountMax;
|
||||
component->init = init;
|
||||
component->dispose = dispose;
|
||||
|
||||
// Fill with 0xFF
|
||||
memorySet(component->entities, 0xFF, sizeof(entityid_t) * ENTITY_COUNT_MAX);
|
||||
|
||||
return componentIndex;
|
||||
}
|
||||
|
||||
entitycomponentid_t entityComponentGetByData(const void *data) {
|
||||
assertNotNull(data, "Component data cannot be null.");
|
||||
|
||||
for(uint8_t i = 0; i < ENTITY_MANAGER_COMPONENT_COUNT_MAX; i++) {
|
||||
if(ENTITY_MANAGER.components[i].data == data) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void * entityComponentGetData(
|
||||
const entitycomponentid_t componentId,
|
||||
const entityid_t entityId
|
||||
) {
|
||||
assertTrue(
|
||||
componentId < ENTITY_MANAGER_COMPONENT_COUNT_MAX,
|
||||
"Component ID is out of bounds."
|
||||
);
|
||||
assertTrue(
|
||||
entityId < ENTITY_COUNT_MAX,
|
||||
"Entity ID is out of bounds."
|
||||
);
|
||||
entitycomponent_t *comp = &ENTITY_MANAGER.components[componentId];
|
||||
for(uint8_t i = 0; i < comp->entityMax; i++) {
|
||||
if(comp->entities[i] == entityId) {
|
||||
return (uint8_t *)comp->data + (comp->dataSize * i);
|
||||
}
|
||||
}
|
||||
assertUnreachable("Entity does not have the component.");
|
||||
return NULL;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "entitybase.h"
|
||||
|
||||
typedef struct {
|
||||
size_t dataSize;
|
||||
entityid_t entities[ENTITY_COUNT_MAX];
|
||||
uint8_t entityMax;
|
||||
|
||||
void (*init)(const entityid_t id, void *data);
|
||||
void (*dispose)(const entityid_t id, void *data);
|
||||
} entitycomponent_t;
|
||||
|
||||
#define ENTITY_COMPONENT_DEFINE(name, stc, init, dispose) \
|
||||
static const entitycomponent_t name = { \
|
||||
.dataSize = sizeof(*stc), \
|
||||
.entities = {0}, \
|
||||
.entityMax = ENTITY_COUNT_MAX, \
|
||||
.init = init, \
|
||||
.dispose = dispose \
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a component to the entity manager / Initializes a component slot.
|
||||
*
|
||||
* @param data The data of the component.
|
||||
* @param dataSize The size of the component data.
|
||||
* @param entityCountMax The maximum number of entities that can have this component.
|
||||
* @param init The function to initialize the component for an entity.
|
||||
* @param dispose The function to dispose of the component for an entity.
|
||||
* @return The ID of the added component.
|
||||
*/
|
||||
entitycomponentid_t entityComponentInit(
|
||||
void *data,
|
||||
const size_t dataSize,
|
||||
const uint8_t entityCountMax,
|
||||
void (*init)(const entityid_t id, void *data),
|
||||
void (*dispose)(const entityid_t id, void *data)
|
||||
);
|
||||
|
||||
/**
|
||||
* Gets the component ID of a component by its data pointer.
|
||||
*
|
||||
* @param data The data pointer of the component.
|
||||
* @return The ID of the component, or 0xFF if not found.
|
||||
*/
|
||||
entitycomponentid_t entityComponentGetByData(const void *data);
|
||||
|
||||
/**
|
||||
* Gets the component data for a given component and entity ID.
|
||||
*
|
||||
* @param componentId The ID of the component.
|
||||
* @param entityId The ID of the entity.
|
||||
* @return The component data.
|
||||
*/
|
||||
void * entityComponentGetData(
|
||||
const entitycomponentid_t componentId,
|
||||
const entityid_t entityId
|
||||
);
|
||||
@@ -6,39 +6,28 @@
|
||||
*/
|
||||
|
||||
#include "entitymanager.h"
|
||||
#include "util/memory.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "entity/component/display/entityposition.h"
|
||||
#include "entity/component/display/entitycamera.h"
|
||||
#include "util/memory.h"
|
||||
|
||||
entitymanager_t ENTITY_MANAGER;
|
||||
|
||||
void entityManagerInit(void) {
|
||||
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
|
||||
}
|
||||
|
||||
// Init components.
|
||||
entityComponentInit(
|
||||
ENTITY_POSITION_DATA,
|
||||
sizeof(entityposition_t),
|
||||
ENTITY_COUNT_MAX,
|
||||
NULL, NULL
|
||||
);
|
||||
|
||||
entityComponentInit(
|
||||
ENTITY_CAMERA_DATA,
|
||||
sizeof(entitycamera_t),
|
||||
ENTITY_CAMERA_COUNT_MAX,
|
||||
entityCameraInit, NULL
|
||||
);
|
||||
entityid_t entityManagerAdd() {
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) != 0) continue;
|
||||
entityInit(i);
|
||||
return i;
|
||||
}
|
||||
assertUnreachable("No more entity IDs available");
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void entityManagerDispose(void) {
|
||||
for(uint8_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entityRemove(i);
|
||||
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
|
||||
entityDispose(i);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,9 @@
|
||||
|
||||
#pragma once
|
||||
#include "entity.h"
|
||||
#include "entitycomponent.h"
|
||||
|
||||
typedef struct {
|
||||
entity_t entities[ENTITY_COUNT_MAX];
|
||||
entitycomponent_t components[ENTITY_MANAGER_COMPONENT_COUNT_MAX];
|
||||
} entitymanager_t;
|
||||
|
||||
extern entitymanager_t ENTITY_MANAGER;
|
||||
@@ -22,6 +20,13 @@ extern entitymanager_t ENTITY_MANAGER;
|
||||
void entityManagerInit(void);
|
||||
|
||||
/**
|
||||
* Disposes of the entity manager, this will dispose active entities.
|
||||
* Adds / Reserves a new entity ID.
|
||||
*
|
||||
* @return The new entity ID.
|
||||
*/
|
||||
entityid_t entityManagerAdd();
|
||||
|
||||
/**
|
||||
* Disposes of the entity manager, in turn freeing all entities and components.
|
||||
*/
|
||||
void entityManagerDispose(void);
|
||||
Reference in New Issue
Block a user