Add parent/child

This commit is contained in:
2026-05-17 21:46:08 -05:00
parent 782fd07a8d
commit 54254348b8
8 changed files with 244 additions and 103 deletions
+1 -1
View File
@@ -87,7 +87,7 @@ entityid_t componentGetEntitiesWithComponent(
componentid_t used = ENTITY_MANAGER.entitiesWithComponent[ componentid_t used = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + i type * ENTITY_COUNT_MAX + i
]; ];
if(used == 0xFF) continue; if(used == COMPONENT_ID_INVALID) continue;
assertTrue( assertTrue(
ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type, ENTITY_MANAGER.components[componentGetIndex(i, used)].type == type,
"Component type mismatch in entitiesWithComponent lookup" "Component type mismatch in entitiesWithComponent lookup"
@@ -7,6 +7,33 @@
#include "entity/entitymanager.h" #include "entity/entitymanager.h"
// Lazily recompute worldTransform from the parent chain.
static void entityPositionUpdateWorld(entityposition_t *pos) {
if(!pos->dirty) return;
if(pos->parentEntityId == ENTITY_ID_INVALID) {
glm_mat4_copy(pos->localTransform, pos->worldTransform);
} else {
entityposition_t *parent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
entityPositionUpdateWorld(parent);
glm_mat4_mul(parent->worldTransform, pos->localTransform, pos->worldTransform);
}
pos->dirty = false;
}
void entityPositionMarkDirty(entityposition_t *pos) {
pos->dirty = true;
for(uint8_t i = 0; i < pos->childCount; i++) {
entityposition_t *child = componentGetData(
pos->childEntityIds[i], pos->childComponentIds[i], COMPONENT_TYPE_POSITION
);
entityPositionMarkDirty(child);
}
}
void entityPositionInit( void entityPositionInit(
const entityid_t entityId, const entityid_t entityId,
const componentid_t componentId const componentid_t componentId
@@ -18,7 +45,12 @@ void entityPositionInit(
glm_vec3_zero(pos->position); glm_vec3_zero(pos->position);
glm_vec3_zero(pos->rotation); glm_vec3_zero(pos->rotation);
glm_vec3_one(pos->scale); glm_vec3_one(pos->scale);
glm_mat4_identity(pos->transform); glm_mat4_identity(pos->localTransform);
glm_mat4_identity(pos->worldTransform);
pos->dirty = false;
pos->parentEntityId = ENTITY_ID_INVALID;
pos->parentComponentId = COMPONENT_ID_INVALID;
pos->childCount = 0;
} }
void entityPositionLookAt( void entityPositionLookAt(
@@ -31,8 +63,9 @@ void entityPositionLookAt(
entityposition_t *pos = componentGetData( entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION entityId, componentId, COMPONENT_TYPE_POSITION
); );
glm_lookat(eye, target, up, pos->transform); glm_lookat(eye, target, up, pos->localTransform);
entityPositionDecompose(pos); entityPositionDecompose(pos);
entityPositionMarkDirty(pos);
} }
void entityPositionGetTransform( void entityPositionGetTransform(
@@ -43,7 +76,19 @@ void entityPositionGetTransform(
entityposition_t *pos = componentGetData( entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION entityId, componentId, COMPONENT_TYPE_POSITION
); );
glm_mat4_copy(pos->transform, dest); entityPositionUpdateWorld(pos);
glm_mat4_copy(pos->worldTransform, dest);
}
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
glm_mat4_copy(pos->localTransform, dest);
} }
void entityPositionGetPosition( void entityPositionGetPosition(
@@ -115,6 +160,54 @@ void entityPositionSetScale(
entityPositionRebuild(pos); entityPositionRebuild(pos);
} }
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
) {
entityposition_t *pos = componentGetData(
entityId, componentId, COMPONENT_TYPE_POSITION
);
// Remove from old parent's child list.
if(pos->parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *oldParent = componentGetData(
pos->parentEntityId, pos->parentComponentId, COMPONENT_TYPE_POSITION
);
for(uint8_t i = 0; i < oldParent->childCount; i++) {
if(
oldParent->childEntityIds[i] == entityId &&
oldParent->childComponentIds[i] == componentId
) {
oldParent->childCount--;
for(uint8_t j = i; j < oldParent->childCount; j++) {
oldParent->childEntityIds[j] = oldParent->childEntityIds[j + 1];
oldParent->childComponentIds[j] = oldParent->childComponentIds[j + 1];
}
break;
}
}
}
pos->parentEntityId = parentEntityId;
pos->parentComponentId = parentComponentId;
// Register with new parent.
if(parentEntityId != ENTITY_ID_INVALID) {
entityposition_t *parent = componentGetData(
parentEntityId, parentComponentId, COMPONENT_TYPE_POSITION
);
if(parent->childCount < ENTITY_POSITION_CHILDREN_MAX) {
parent->childEntityIds[parent->childCount] = entityId;
parent->childComponentIds[parent->childCount] = componentId;
parent->childCount++;
}
}
entityPositionMarkDirty(pos);
}
entityposition_t *entityPositionGet( entityposition_t *entityPositionGet(
const entityid_t entityId, const entityid_t entityId,
const componentid_t componentId const componentid_t componentId
@@ -125,57 +218,56 @@ entityposition_t *entityPositionGet(
} }
void entityPositionRebuild(entityposition_t *pos) { void entityPositionRebuild(entityposition_t *pos) {
glm_mat4_identity(pos->transform); glm_mat4_identity(pos->localTransform);
glm_translate(pos->transform, pos->position); glm_translate(pos->localTransform, pos->position);
glm_rotate_x(pos->transform, pos->rotation[0], pos->transform); glm_rotate_x(pos->localTransform, pos->rotation[0], pos->localTransform);
glm_rotate_y(pos->transform, pos->rotation[1], pos->transform); glm_rotate_y(pos->localTransform, pos->rotation[1], pos->localTransform);
glm_rotate_z(pos->transform, pos->rotation[2], pos->transform); glm_rotate_z(pos->localTransform, pos->rotation[2], pos->localTransform);
glm_scale(pos->transform, pos->scale); glm_scale(pos->localTransform, pos->scale);
entityPositionMarkDirty(pos);
} }
void entityPositionDecompose(entityposition_t *pos) { void entityPositionDecompose(entityposition_t *pos) {
// Translation: column 3 // Translation: column 3
pos->position[0] = pos->transform[3][0]; pos->position[0] = pos->localTransform[3][0];
pos->position[1] = pos->transform[3][1]; pos->position[1] = pos->localTransform[3][1];
pos->position[2] = pos->transform[3][2]; pos->position[2] = pos->localTransform[3][2];
// Scale: length of each basis column (xyz only) // Scale: length of each basis column (xyz only)
pos->scale[0] = sqrtf( pos->scale[0] = sqrtf(
pos->transform[0][0] * pos->transform[0][0] + pos->localTransform[0][0] * pos->localTransform[0][0] +
pos->transform[0][1] * pos->transform[0][1] + pos->localTransform[0][1] * pos->localTransform[0][1] +
pos->transform[0][2] * pos->transform[0][2] pos->localTransform[0][2] * pos->localTransform[0][2]
); );
pos->scale[1] = sqrtf( pos->scale[1] = sqrtf(
pos->transform[1][0] * pos->transform[1][0] + pos->localTransform[1][0] * pos->localTransform[1][0] +
pos->transform[1][1] * pos->transform[1][1] + pos->localTransform[1][1] * pos->localTransform[1][1] +
pos->transform[1][2] * pos->transform[1][2] pos->localTransform[1][2] * pos->localTransform[1][2]
); );
pos->scale[2] = sqrtf( pos->scale[2] = sqrtf(
pos->transform[2][0] * pos->transform[2][0] + pos->localTransform[2][0] * pos->localTransform[2][0] +
pos->transform[2][1] * pos->transform[2][1] + pos->localTransform[2][1] * pos->localTransform[2][1] +
pos->transform[2][2] * pos->transform[2][2] pos->localTransform[2][2] * pos->localTransform[2][2]
); );
// Normalize columns to isolate the rotation matrix // Normalize columns to isolate the rotation matrix.
float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f; float invS0 = pos->scale[0] > 0.0f ? 1.0f / pos->scale[0] : 0.0f;
float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f; float invS1 = pos->scale[1] > 0.0f ? 1.0f / pos->scale[1] : 0.0f;
float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f; float invS2 = pos->scale[2] > 0.0f ? 1.0f / pos->scale[2] : 0.0f;
mat4 r; mat4 r;
glm_mat4_identity(r); glm_mat4_identity(r);
r[0][0] = pos->transform[0][0] * invS0; r[0][0] = pos->localTransform[0][0] * invS0;
r[0][1] = pos->transform[0][1] * invS0; r[0][1] = pos->localTransform[0][1] * invS0;
r[0][2] = pos->transform[0][2] * invS0; r[0][2] = pos->localTransform[0][2] * invS0;
r[1][0] = pos->transform[1][0] * invS1; r[1][0] = pos->localTransform[1][0] * invS1;
r[1][1] = pos->transform[1][1] * invS1; r[1][1] = pos->localTransform[1][1] * invS1;
r[1][2] = pos->transform[1][2] * invS1; r[1][2] = pos->localTransform[1][2] * invS1;
r[2][0] = pos->transform[2][0] * invS2; r[2][0] = pos->localTransform[2][0] * invS2;
r[2][1] = pos->transform[2][1] * invS2; r[2][1] = pos->localTransform[2][1] * invS2;
r[2][2] = pos->transform[2][2] * invS2; r[2][2] = pos->localTransform[2][2] * invS2;
// Extract XYZ euler angles (R = Rx * Ry * Rz, column-major) // Extract XYZ euler angles (R = Rx * Ry * Rz, column-major)
// r[2][0] = sin(Y), r[2][1] = -sin(X)*cos(Y), r[2][2] = cos(X)*cos(Y)
// r[0][0] = cos(Y)*cos(Z), r[1][0] = -cos(Y)*sin(Z)
float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f); float sinBeta = glm_clamp(r[2][0], -1.0f, 1.0f);
pos->rotation[1] = asinf(sinBeta); pos->rotation[1] = asinf(sinBeta);
float cosBeta = cosf(pos->rotation[1]); float cosBeta = cosf(pos->rotation[1]);
@@ -184,7 +276,7 @@ void entityPositionDecompose(entityposition_t *pos) {
pos->rotation[0] = atan2f(-r[2][1], r[2][2]); pos->rotation[0] = atan2f(-r[2][1], r[2][2]);
pos->rotation[2] = atan2f(-r[1][0], r[0][0]); pos->rotation[2] = atan2f(-r[1][0], r[0][0]);
} else { } else {
// Gimbal lock: pin Z to 0, recover X from the remaining degree of freedom // Gimbal lock: pin Z to 0, recover X.
pos->rotation[2] = 0.0f; pos->rotation[2] = 0.0f;
pos->rotation[0] = (sinBeta > 0.0f) pos->rotation[0] = (sinBeta > 0.0f)
? atan2f(r[0][1], r[1][1]) ? atan2f(r[0][1], r[1][1])
@@ -8,18 +8,24 @@
#pragma once #pragma once
#include "entity/entitybase.h" #include "entity/entitybase.h"
#define ENTITY_POSITION_CHILDREN_MAX 8
typedef struct { typedef struct {
mat4 transform; mat4 localTransform;
mat4 worldTransform;
vec3 position; vec3 position;
vec3 rotation; vec3 rotation;
vec3 scale; vec3 scale;
bool dirty;
entityid_t parentEntityId;
componentid_t parentComponentId;
uint8_t childCount;
entityid_t childEntityIds[ENTITY_POSITION_CHILDREN_MAX];
componentid_t childComponentIds[ENTITY_POSITION_CHILDREN_MAX];
} entityposition_t; } entityposition_t;
/** /**
* Initialize the entity position component. * Initialize the entity position component.
*
* @param entityId The entity ID.
* @param componentId The component ID.
*/ */
void entityPositionInit( void entityPositionInit(
const entityid_t entityId, const entityid_t entityId,
@@ -27,13 +33,13 @@ void entityPositionInit(
); );
/** /**
* Transforms the entity's position to look at a target point. * Transforms the entity's local transform to look at a target point.
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param target The target point to look at. * @param target The target point to look at.
* @param up The up vector for the look at transformation. * @param up The up vector.
* @param eye The position of the camera/eye for the look at transformation. * @param eye The eye/camera position.
*/ */
void entityPositionLookAt( void entityPositionLookAt(
const entityid_t entityId, const entityid_t entityId,
@@ -44,11 +50,11 @@ void entityPositionLookAt(
); );
/** /**
* Gets the transform matrix of the entity position component. * Gets the world-space transform matrix, recomputing it lazily if dirty.
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param dest The destination matrix to write the transform to. * @param dest Destination matrix.
*/ */
void entityPositionGetTransform( void entityPositionGetTransform(
const entityid_t entityId, const entityid_t entityId,
@@ -57,11 +63,20 @@ void entityPositionGetTransform(
); );
/** /**
* Gets the cached position of the entity. * Gets the local transform matrix (does not include parent transforms).
* *
* @param entityId The entity ID. * @param entityId The entity ID.
* @param componentId The component ID. * @param componentId The component ID.
* @param dest The destination vec3 to write the position to. * @param dest Destination matrix.
*/
void entityPositionGetLocalTransform(
const entityid_t entityId,
const componentid_t componentId,
mat4 dest
);
/**
* Gets the cached local position.
*/ */
void entityPositionGetPosition( void entityPositionGetPosition(
const entityid_t entityId, const entityid_t entityId,
@@ -70,11 +85,7 @@ void entityPositionGetPosition(
); );
/** /**
* Sets the position of the entity and rebuilds the transform matrix. * Sets the local position and marks the world transform dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param position The new position.
*/ */
void entityPositionSetPosition( void entityPositionSetPosition(
const entityid_t entityId, const entityid_t entityId,
@@ -83,11 +94,7 @@ void entityPositionSetPosition(
); );
/** /**
* Gets the cached euler rotation (XYZ, radians) of the entity. * Gets the cached local euler rotation (XYZ, radians).
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the rotation to.
*/ */
void entityPositionGetRotation( void entityPositionGetRotation(
const entityid_t entityId, const entityid_t entityId,
@@ -96,12 +103,7 @@ void entityPositionGetRotation(
); );
/** /**
* Sets the euler rotation (XYZ, radians) of the entity and rebuilds the * Sets the local euler rotation (XYZ, radians) and marks the world transform dirty.
* transform matrix.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param rotation The new euler rotation in radians.
*/ */
void entityPositionSetRotation( void entityPositionSetRotation(
const entityid_t entityId, const entityid_t entityId,
@@ -110,11 +112,7 @@ void entityPositionSetRotation(
); );
/** /**
* Gets the cached scale of the entity. * Gets the cached local scale.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param dest The destination vec3 to write the scale to.
*/ */
void entityPositionGetScale( void entityPositionGetScale(
const entityid_t entityId, const entityid_t entityId,
@@ -123,11 +121,7 @@ void entityPositionGetScale(
); );
/** /**
* Sets the scale of the entity and rebuilds the transform matrix. * Sets the local scale and marks the world transform dirty.
*
* @param entityId The entity ID.
* @param componentId The component ID.
* @param scale The new scale.
*/ */
void entityPositionSetScale( void entityPositionSetScale(
const entityid_t entityId, const entityid_t entityId,
@@ -136,13 +130,24 @@ void entityPositionSetScale(
); );
/** /**
* Returns a direct pointer to the entity position component data. * Sets the parent of this entity's position component.
* After modifying position, rotation, or scale directly, call * Pass ENTITY_ID_INVALID / COMPONENT_ID_INVALID to detach from any parent.
* entityPositionRebuild() to update the transform matrix.
* *
* @param entityId The entity ID. * @param entityId The child entity ID.
* @param componentId The component ID. * @param componentId The child component ID.
* @return Pointer to the entity position component data. * @param parentEntityId The parent entity ID.
* @param parentComponentId The parent component ID.
*/
void entityPositionSetParent(
const entityid_t entityId,
const componentid_t componentId,
const entityid_t parentEntityId,
const componentid_t parentComponentId
);
/**
* Returns a direct pointer to the entity position component data.
* After modifying localTransform directly, call entityPositionMarkDirty().
*/ */
entityposition_t *entityPositionGet( entityposition_t *entityPositionGet(
const entityid_t entityId, const entityid_t entityId,
@@ -150,15 +155,18 @@ entityposition_t *entityPositionGet(
); );
/** /**
* Internal function to rebuild the transform matrix of the entity position * Rebuilds the local transform matrix from the cached position/rotation/scale,
* component based on the current position, rotation, and scale. * then marks this node and all descendants dirty.
*/ */
void entityPositionRebuild(entityposition_t *pos); void entityPositionRebuild(entityposition_t *pos);
/** /**
* Decomposes the transform matrix back into the position, rotation (XYZ euler, * Marks this node and all descendants as having a stale world transform.
* radians), and scale cache fields. Call after any direct matrix modification. */
* void entityPositionMarkDirty(entityposition_t *pos);
* @param pos Pointer to the entity position component data.
/**
* Decomposes the local transform matrix back into the position, rotation
* (XYZ euler, radians), and scale cache fields.
*/ */
void entityPositionDecompose(entityposition_t *pos); void entityPositionDecompose(entityposition_t *pos);
+4 -4
View File
@@ -22,7 +22,7 @@ void entityInit(const entityid_t entityId) {
) { ) {
ENTITY_MANAGER.entitiesWithComponent[ ENTITY_MANAGER.entitiesWithComponent[
compType * ENTITY_COUNT_MAX + entityId compType * ENTITY_COUNT_MAX + entityId
] = 0xFF; ] = COMPONENT_ID_INVALID;
} }
ent->state |= ENTITY_STATE_ACTIVE; ent->state |= ENTITY_STATE_ACTIVE;
@@ -52,7 +52,7 @@ componentid_t entityAddComponent(
} }
assertUnreachable("Entity has no more component slots available"); assertUnreachable("Entity has no more component slots available");
return 0xFF; return COMPONENT_ID_INVALID;
} }
componentid_t entityGetComponent( componentid_t entityGetComponent(
@@ -62,7 +62,7 @@ componentid_t entityGetComponent(
componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[ componentid_t compId = ENTITY_MANAGER.entitiesWithComponent[
type * ENTITY_COUNT_MAX + entityId type * ENTITY_COUNT_MAX + entityId
]; ];
if(compId == 0xFF) return compId; if(compId == COMPONENT_ID_INVALID) return compId;
assertTrue( assertTrue(
ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type, ENTITY_MANAGER.components[componentGetIndex(entityId, compId)].type == type,
"Component type mismatch" "Component type mismatch"
@@ -80,7 +80,7 @@ void entityDispose(const entityid_t entityId) {
componentDispose(entityId, i); componentDispose(entityId, i);
ENTITY_MANAGER.entitiesWithComponent[ ENTITY_MANAGER.entitiesWithComponent[
ENTITY_MANAGER.components[compInd].type * ENTITY_COUNT_MAX + entityId ENTITY_MANAGER.components[compInd].type * ENTITY_COUNT_MAX + entityId
] = 0xFF; ] = COMPONENT_ID_INVALID;
} }
ent->state = 0; ent->state = 0;
+1 -1
View File
@@ -35,7 +35,7 @@ componentid_t entityAddComponent(
/** /**
* Gets the ID of the component of the given type on the entity with the given * Gets the ID of the component of the given type on the entity with the given
* ID, or 0xFF if the entity lacks the component. * ID, or COMPONENT_ID_INVALID if the entity lacks the component.
* *
* @param entityId The ID of the entity to get the component from. * @param entityId The ID of the entity to get the component from.
* @param type The type of the component to get. * @param type The type of the component to get.
+3
View File
@@ -11,6 +11,9 @@
#define ENTITY_COUNT_MAX 20 #define ENTITY_COUNT_MAX 20
#define ENTITY_COMPONENT_COUNT_MAX 8 #define ENTITY_COMPONENT_COUNT_MAX 8
#define ENTITY_ID_INVALID 0xFF
#define COMPONENT_ID_INVALID 0xFF
typedef uint8_t entityid_t; typedef uint8_t entityid_t;
typedef uint8_t componentid_t; typedef uint8_t componentid_t;
typedef uint16_t componentindex_t; typedef uint16_t componentindex_t;
+2 -2
View File
@@ -15,7 +15,7 @@ entitymanager_t ENTITY_MANAGER;
void entityManagerInit(void) { void entityManagerInit(void) {
memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t)); memoryZero(&ENTITY_MANAGER, sizeof(entitymanager_t));
memorySet( memorySet(
ENTITY_MANAGER.entitiesWithComponent, 0xFF, ENTITY_MANAGER.entitiesWithComponent, COMPONENT_ID_INVALID,
sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX sizeof(entityid_t) * COMPONENT_TYPE_COUNT * ENTITY_COUNT_MAX
); );
@@ -33,7 +33,7 @@ entityid_t entityManagerAdd() {
return i; return i;
} }
assertUnreachable("No more entity IDs available"); assertUnreachable("No more entity IDs available");
return 0xFF; return ENTITY_ID_INVALID;
} }
void entityManagerDispose(void) { void entityManagerDispose(void) {
@@ -97,7 +97,11 @@ moduleBaseFunction(moduleEntityPositionSetScale) {
moduleBaseFunction(moduleEntityPositionLookAt) { moduleBaseFunction(moduleEntityPositionLookAt) {
if(argc < 1) return moduleBaseThrow("Expected at least 1 argument"); if(argc < 1) return moduleBaseThrow("Expected at least 1 argument");
entityposition_t *pos = moduleEntityPositionGet(callInfo); componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
entityposition_t *pos = entityPositionGet(h->eid, h->cid);
if(!pos) return jerry_undefined(); if(!pos) return jerry_undefined();
vec3 target; vec3 target;
if(!moduleVec3AnyCheck(args[0], target)) { if(!moduleVec3AnyCheck(args[0], target)) {
@@ -107,8 +111,37 @@ moduleBaseFunction(moduleEntityPositionLookAt) {
if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) { if(argc >= 2 && !moduleVec3AnyCheck(args[1], up)) {
return moduleBaseThrow("expected Vec3 up"); return moduleBaseThrow("expected Vec3 up");
} }
glm_lookat(pos->position, target, up, pos->transform); entityPositionLookAt(h->eid, h->cid, target, up, pos->position);
entityPositionDecompose(pos); return jerry_undefined();
}
moduleBaseFunction(moduleEntityPositionGetParent) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
entityposition_t *pos = entityPositionGet(h->eid, h->cid);
if(!pos || pos->parentEntityId == ENTITY_ID_INVALID) return jerry_null();
componenthandle_t ph = { .eid = pos->parentEntityId, .cid = pos->parentComponentId };
return scriptProtoCreateValue(&MODULE_ENTITY_POSITION_PROTO, &ph);
}
moduleBaseFunction(moduleEntityPositionSetParentProp) {
componenthandle_t *h = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, callInfo->this_value
);
if(!h) return jerry_undefined();
if(argc < 1 || jerry_value_is_null(args[0]) || jerry_value_is_undefined(args[0])) {
entityPositionSetParent(h->eid, h->cid, ENTITY_ID_INVALID, COMPONENT_ID_INVALID);
return jerry_undefined();
}
componenthandle_t *ph = scriptProtoGetValue(
&MODULE_ENTITY_POSITION_PROTO, args[0]
);
if(!ph) return moduleBaseThrow("expected EntityPosition");
entityPositionSetParent(h->eid, h->cid, ph->eid, ph->cid);
return jerry_undefined(); return jerry_undefined();
} }
@@ -147,4 +180,9 @@ static void moduleEntityPOSITION(void) {
&MODULE_ENTITY_POSITION_PROTO, "lookAt", &MODULE_ENTITY_POSITION_PROTO, "lookAt",
moduleEntityPositionLookAt moduleEntityPositionLookAt
); );
scriptProtoDefineProp(
&MODULE_ENTITY_POSITION_PROTO, "parent",
moduleEntityPositionGetParent, moduleEntityPositionSetParentProp
);
} }