Entity refactoring
This commit is contained in:
@@ -72,14 +72,10 @@ errorret_t engineUpdate(void) {
|
|||||||
errorChain(uiTextboxUpdate());
|
errorChain(uiTextboxUpdate());
|
||||||
physicsManagerUpdate();
|
physicsManagerUpdate();
|
||||||
errorChain(displayUpdate());
|
errorChain(displayUpdate());
|
||||||
|
|
||||||
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
|
|
||||||
|
|
||||||
// Scene update occurs last because only after rendering would we want to do
|
|
||||||
// scene switching, refer to sceneSet() for information.
|
|
||||||
errorChain(cutsceneUpdate());
|
errorChain(cutsceneUpdate());
|
||||||
errorChain(sceneUpdate());
|
errorChain(sceneUpdate());
|
||||||
|
|
||||||
|
if(inputPressed(INPUT_ACTION_RAGEQUIT)) ENGINE.running = false;
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
# https://opensource.org/licenses/MIT
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
add_subdirectory(display)
|
add_subdirectory(display)
|
||||||
|
add_subdirectory(overworld)
|
||||||
add_subdirectory(physics)
|
add_subdirectory(physics)
|
||||||
add_subdirectory(script)
|
add_subdirectory(script)
|
||||||
add_subdirectory(trigger)
|
add_subdirectory(trigger)
|
||||||
@@ -11,7 +11,14 @@
|
|||||||
#include "display/mesh/cube.h"
|
#include "display/mesh/cube.h"
|
||||||
#include "display/spritebatch/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
|
|
||||||
errorret_t entityRenderableDrawDefault() {
|
errorret_t entityRenderableDrawDefault(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
(void)entityId;
|
||||||
|
(void)componentId;
|
||||||
|
(void)user;
|
||||||
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_WHITE));
|
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_WHITE));
|
||||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
||||||
return meshDraw(&CUBE_MESH_SIMPLE, 0, -1);
|
return meshDraw(&CUBE_MESH_SIMPLE, 0, -1);
|
||||||
@@ -25,6 +32,7 @@ void entityRenderableInit(
|
|||||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||||
);
|
);
|
||||||
r->draw = entityRenderableDrawDefault;
|
r->draw = entityRenderableDrawDefault;
|
||||||
|
r->drawUser = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityRenderableDispose(
|
void entityRenderableDispose(
|
||||||
@@ -37,12 +45,18 @@ void entityRenderableDispose(
|
|||||||
void entityRenderableSetDraw(
|
void entityRenderableSetDraw(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId,
|
const componentid_t componentId,
|
||||||
errorret_t (*draw)(void)
|
errorret_t (*draw)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
),
|
||||||
|
void *user
|
||||||
) {
|
) {
|
||||||
entityrenderable_t *r = componentGetData(
|
entityrenderable_t *r = componentGetData(
|
||||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||||
);
|
);
|
||||||
r->draw = draw;
|
r->draw = draw;
|
||||||
|
r->drawUser = user;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t entityRenderableDraw(
|
errorret_t entityRenderableDraw(
|
||||||
@@ -52,5 +66,5 @@ errorret_t entityRenderableDraw(
|
|||||||
entityrenderable_t *r = componentGetData(
|
entityrenderable_t *r = componentGetData(
|
||||||
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
entityId, componentId, COMPONENT_TYPE_RENDERABLE
|
||||||
);
|
);
|
||||||
return r->draw();
|
return r->draw(entityId, componentId, r->drawUser);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,12 @@
|
|||||||
#include "display/spritebatch/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
errorret_t (*draw)(void);
|
errorret_t (*draw)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
void *drawUser;
|
||||||
} entityrenderable_t;
|
} entityrenderable_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +53,12 @@ void entityRenderableDispose(
|
|||||||
void entityRenderableSetDraw(
|
void entityRenderableSetDraw(
|
||||||
const entityid_t entityId,
|
const entityid_t entityId,
|
||||||
const componentid_t componentId,
|
const componentid_t componentId,
|
||||||
errorret_t (*draw)(void)
|
errorret_t (*draw)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
),
|
||||||
|
void *user
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
entityinteractable.c
|
||||||
|
entityoverworld.c
|
||||||
|
entityoverworldcamera.c
|
||||||
|
entityplayer.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entityinteractable.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
|
||||||
|
void entityInteractableInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityinteractable_t *inter = entityInteractableGet(entityId, componentId);
|
||||||
|
inter->onInteract = NULL;
|
||||||
|
inter->user = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityinteractable_t * entityInteractableGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
return componentGetData(entityId, componentId, COMPONENT_TYPE_INTERACTABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityInteractableSetCallback(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void (*onInteract)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
),
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
entityinteractable_t *inter = entityInteractableGet(entityId, componentId);
|
||||||
|
inter->onInteract = onInteract;
|
||||||
|
inter->user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityInteractableTrigger(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityinteractable_t *inter = entityInteractableGet(entityId, componentId);
|
||||||
|
if(inter->onInteract == NULL) return;
|
||||||
|
inter->onInteract(entityId, componentId, inter->user);
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
void (*onInteract)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
void *user;
|
||||||
|
} entityinteractable_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the interactable component, clearing the callback and user pointer.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityInteractableInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the interactable component data.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @return Pointer to the entityinteractable_t data.
|
||||||
|
*/
|
||||||
|
entityinteractable_t * entityInteractableGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the callback invoked when this interactable is triggered.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @param onInteract Function called on interaction, or NULL to clear.
|
||||||
|
* @param user Arbitrary pointer forwarded to the callback.
|
||||||
|
*/
|
||||||
|
void entityInteractableSetCallback(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void (*onInteract)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
),
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires the interactable's callback if one is set.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityInteractableTrigger(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entityoverworld.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/display/entityrenderable.h"
|
||||||
|
#include "display/shader/shaderunlit.h"
|
||||||
|
#include "display/mesh/cube.h"
|
||||||
|
|
||||||
|
void entityOverworldInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityoverworld_t *ow = entityOverworldGet(entityId, componentId);
|
||||||
|
ow->type = OVERWORLD_ENTITY_TYPE_NPC;
|
||||||
|
ow->facing = FACING_DIR_DOWN;
|
||||||
|
ow->renderCompId = entityGetComponent(entityId, COMPONENT_TYPE_RENDERABLE);
|
||||||
|
if(ow->renderCompId != COMPONENT_ID_INVALID) {
|
||||||
|
entityRenderableSetDraw(entityId, ow->renderCompId, entityOverworldDraw, NULL);
|
||||||
|
}
|
||||||
|
ow->physCompId = entityGetComponent(entityId, COMPONENT_TYPE_PHYSICS);
|
||||||
|
}
|
||||||
|
|
||||||
|
entityoverworld_t * entityOverworldGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
return componentGetData(entityId, componentId, COMPONENT_TYPE_OVERWORLD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityOverworldSetType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityoverworldtype_t type
|
||||||
|
) {
|
||||||
|
entityOverworldGet(entityId, componentId)->type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t entityOverworldDraw(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
(void)componentId; (void)user;
|
||||||
|
|
||||||
|
componentid_t owCompId = entityGetComponent(entityId, COMPONENT_TYPE_OVERWORLD);
|
||||||
|
entityoverworld_t *ow = entityOverworldGet(entityId, owCompId);
|
||||||
|
|
||||||
|
color_t col = ow->type == OVERWORLD_ENTITY_TYPE_PLAYER ? COLOR_WHITE : COLOR_BLUE;
|
||||||
|
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, col));
|
||||||
|
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
||||||
|
return meshDraw(&CUBE_MESH_SIMPLE, 0, -1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "entity/entitybase.h"
|
||||||
|
#include "overworld/facingdir.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
OVERWORLD_ENTITY_TYPE_PLAYER = 0,
|
||||||
|
OVERWORLD_ENTITY_TYPE_NPC = 1,
|
||||||
|
} entityoverworldtype_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
entityoverworldtype_t type;
|
||||||
|
facingdir_t facing;
|
||||||
|
componentid_t renderCompId;
|
||||||
|
componentid_t physCompId;
|
||||||
|
} entityoverworld_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the overworld component, wiring up the draw callback if a
|
||||||
|
* renderable component is already present on the entity.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityOverworldInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the overworld component data.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @return Pointer to the entityoverworld_t data.
|
||||||
|
*/
|
||||||
|
entityoverworld_t * entityOverworldGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overworld entity type.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @param type The type to assign.
|
||||||
|
*/
|
||||||
|
void entityOverworldSetType(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityoverworldtype_t type
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Draw callback registered on the renderable component.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId The renderable component's ID.
|
||||||
|
* @param user Unused.
|
||||||
|
* @return Error result.
|
||||||
|
*/
|
||||||
|
errorret_t entityOverworldDraw(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entityoverworldcamera.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/display/entityposition.h"
|
||||||
|
#include "entity/component/display/entitycamera.h"
|
||||||
|
|
||||||
|
void entityOverworldCameraInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityoverworldcamera_t *cam = entityOverworldCameraGet(entityId, componentId);
|
||||||
|
cam->targetEntityId = ENTITY_ID_INVALID;
|
||||||
|
cam->targetPosCompId = COMPONENT_ID_INVALID;
|
||||||
|
glm_vec3_zero(cam->targetOffset);
|
||||||
|
glm_vec3_zero(cam->eyeOffset);
|
||||||
|
cam->scale = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityoverworldcamera_t * entityOverworldCameraGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
return componentGetData(entityId, componentId, COMPONENT_TYPE_OVERWORLD_CAMERA);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityOverworldCameraSetTarget(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityid_t targetEntityId,
|
||||||
|
const componentid_t targetPosCompId
|
||||||
|
) {
|
||||||
|
entityoverworldcamera_t *cam = entityOverworldCameraGet(entityId, componentId);
|
||||||
|
cam->targetEntityId = targetEntityId;
|
||||||
|
cam->targetPosCompId = targetPosCompId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityOverworldCameraUpdate(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityoverworldcamera_t *cam = entityOverworldCameraGet(entityId, componentId);
|
||||||
|
|
||||||
|
vec3 targetPos;
|
||||||
|
entityPositionGetWorldPosition(
|
||||||
|
cam->targetEntityId, cam->targetPosCompId, targetPos
|
||||||
|
);
|
||||||
|
|
||||||
|
vec3 center = {
|
||||||
|
targetPos[0] + cam->targetOffset[0],
|
||||||
|
targetPos[1] + cam->targetOffset[1],
|
||||||
|
targetPos[2] + cam->targetOffset[2]
|
||||||
|
};
|
||||||
|
|
||||||
|
componentid_t posComp = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
|
||||||
|
componentid_t camComp = entityGetComponent(entityId, COMPONENT_TYPE_CAMERA);
|
||||||
|
entityCameraLookAtPixelPerfect(
|
||||||
|
entityId, posComp, camComp, center, cam->eyeOffset, cam->scale
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/**
|
||||||
|
* 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 {
|
||||||
|
entityid_t targetEntityId;
|
||||||
|
componentid_t targetPosCompId;
|
||||||
|
vec3 targetOffset;
|
||||||
|
vec3 eyeOffset;
|
||||||
|
float_t scale;
|
||||||
|
} entityoverworldcamera_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the overworld camera component.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityOverworldCameraInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the overworld camera component data.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @return Pointer to the entityoverworldcamera_t data.
|
||||||
|
*/
|
||||||
|
entityoverworldcamera_t * entityOverworldCameraGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the entity and position component the camera will follow.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @param targetEntityId Entity to follow.
|
||||||
|
* @param targetPosCompId Position component on the target entity.
|
||||||
|
*/
|
||||||
|
void entityOverworldCameraSetTarget(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
const entityid_t targetEntityId,
|
||||||
|
const componentid_t targetPosCompId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the camera position to track the target entity.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityOverworldCameraUpdate(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entityplayer.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/display/entityposition.h"
|
||||||
|
#include "entity/component/physics/entityphysics.h"
|
||||||
|
#include "entity/component/overworld/entityoverworld.h"
|
||||||
|
#include "entity/component/overworld/entityinteractable.h"
|
||||||
|
#include "input/input.h"
|
||||||
|
|
||||||
|
void entityPlayerInit(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityplayer_t *player = entityPlayerGet(entityId, componentId);
|
||||||
|
player->speed = ENTITY_PLAYER_SPEED;
|
||||||
|
player->runSpeed = ENTITY_PLAYER_RUN_SPEED;
|
||||||
|
}
|
||||||
|
|
||||||
|
entityplayer_t * entityPlayerGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
return componentGetData(entityId, componentId, COMPONENT_TYPE_PLAYER);
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityPlayerUpdate(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
) {
|
||||||
|
entityplayer_t *player = entityPlayerGet(entityId, componentId);
|
||||||
|
|
||||||
|
vec2 dir;
|
||||||
|
inputAngle2D(
|
||||||
|
INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT,
|
||||||
|
INPUT_ACTION_UP, INPUT_ACTION_DOWN,
|
||||||
|
dir
|
||||||
|
);
|
||||||
|
|
||||||
|
float_t speed = (
|
||||||
|
inputIsDown(INPUT_ACTION_CANCEL) ? player->runSpeed : player->speed
|
||||||
|
);
|
||||||
|
|
||||||
|
componentid_t owCompId = entityGetComponent(entityId, COMPONENT_TYPE_OVERWORLD);
|
||||||
|
entityoverworld_t *ow = entityOverworldGet(entityId, owCompId);
|
||||||
|
|
||||||
|
if(ow && glm_vec2_norm(dir) > 0.0f) {
|
||||||
|
if(fabsf(dir[0]) >= fabsf(dir[1])) {
|
||||||
|
ow->facing = dir[0] > 0.0f ? FACING_DIR_RIGHT : FACING_DIR_LEFT;
|
||||||
|
} else {
|
||||||
|
ow->facing = dir[1] > 0.0f ? FACING_DIR_DOWN : FACING_DIR_UP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 vel;
|
||||||
|
entityPhysicsGetVelocity(entityId, ow->physCompId, vel);
|
||||||
|
vel[0] = dir[0] * speed;
|
||||||
|
vel[2] = dir[1] * speed;
|
||||||
|
entityPhysicsSetVelocity(entityId, ow->physCompId, vel);
|
||||||
|
|
||||||
|
if(!inputPressed(INPUT_ACTION_ACCEPT)) return;
|
||||||
|
|
||||||
|
vec3 playerPos;
|
||||||
|
componentid_t playerPosCompId = entityGetComponent(entityId, COMPONENT_TYPE_POSITION);
|
||||||
|
if(playerPosCompId == COMPONENT_ID_INVALID) return;
|
||||||
|
entityPositionGetWorldPosition(entityId, playerPosCompId, playerPos);
|
||||||
|
|
||||||
|
vec2 facingDir;
|
||||||
|
facingDirToVec2(ow ? ow->facing : FACING_DIR_DOWN, facingDir);
|
||||||
|
|
||||||
|
for(entityid_t i = 0; i < ENTITY_COUNT_MAX; i++) {
|
||||||
|
if((ENTITY_MANAGER.entities[i].state & ENTITY_STATE_ACTIVE) == 0) continue;
|
||||||
|
if(i == entityId) continue;
|
||||||
|
|
||||||
|
componentid_t interComp = entityGetComponent(i, COMPONENT_TYPE_INTERACTABLE);
|
||||||
|
if(interComp == COMPONENT_ID_INVALID) continue;
|
||||||
|
|
||||||
|
componentid_t posComp = entityGetComponent(i, COMPONENT_TYPE_POSITION);
|
||||||
|
if(posComp == COMPONENT_ID_INVALID) continue;
|
||||||
|
|
||||||
|
vec3 targetPos;
|
||||||
|
entityPositionGetWorldPosition(i, posComp, targetPos);
|
||||||
|
|
||||||
|
vec2 toTarget = {
|
||||||
|
targetPos[0] - playerPos[0],
|
||||||
|
targetPos[2] - playerPos[2],
|
||||||
|
};
|
||||||
|
float_t forward = glm_vec2_dot(facingDir, toTarget);
|
||||||
|
if(forward <= 0.0f || forward > ENTITY_PLAYER_INTERACT_RANGE) continue;
|
||||||
|
|
||||||
|
float_t lateral = fabsf(
|
||||||
|
facingDir[0] * toTarget[1] - facingDir[1] * toTarget[0]
|
||||||
|
);
|
||||||
|
if(lateral > ENTITY_PLAYER_INTERACT_LATERAL) continue;
|
||||||
|
|
||||||
|
entityInteractableTrigger(i, interComp);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "error/error.h"
|
||||||
|
#include "entity/entitybase.h"
|
||||||
|
|
||||||
|
#define ENTITY_PLAYER_SPEED 4.0f
|
||||||
|
#define ENTITY_PLAYER_RUN_SPEED 8.0f
|
||||||
|
#define ENTITY_PLAYER_INTERACT_RANGE 1.5f
|
||||||
|
#define ENTITY_PLAYER_INTERACT_LATERAL 0.6f
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float_t speed;
|
||||||
|
float_t runSpeed;
|
||||||
|
} entityplayer_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the player component.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityPlayerInit(const entityid_t entityId, const componentid_t componentId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a pointer to the player component data.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
* @return Pointer to the entityplayer_t data.
|
||||||
|
*/
|
||||||
|
entityplayer_t * entityPlayerGet(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads input, moves the player, updates facing direction, and checks for
|
||||||
|
* interactable entities in front of the player when accept is pressed.
|
||||||
|
*
|
||||||
|
* @param entityId The owning entity.
|
||||||
|
* @param componentId This component's ID.
|
||||||
|
*/
|
||||||
|
void entityPlayerUpdate(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId
|
||||||
|
);
|
||||||
@@ -10,6 +10,10 @@
|
|||||||
#include "entity/component/display/entityrenderable.h"
|
#include "entity/component/display/entityrenderable.h"
|
||||||
#include "entity/component/physics/entityphysics.h"
|
#include "entity/component/physics/entityphysics.h"
|
||||||
#include "entity/component/trigger/entitytrigger.h"
|
#include "entity/component/trigger/entitytrigger.h"
|
||||||
|
#include "entity/component/overworld/entityoverworld.h"
|
||||||
|
#include "entity/component/overworld/entityplayer.h"
|
||||||
|
#include "entity/component/overworld/entityinteractable.h"
|
||||||
|
#include "entity/component/overworld/entityoverworldcamera.h"
|
||||||
|
|
||||||
// Name (Uppercase)
|
// Name (Uppercase)
|
||||||
// Structure
|
// Structure
|
||||||
@@ -22,3 +26,7 @@ X(CAMERA, entitycamera_t, camera, entityCameraInit, NULL)
|
|||||||
X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose)
|
X(RENDERABLE, entityrenderable_t, renderable, entityRenderableInit, entityRenderableDispose)
|
||||||
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
|
X(PHYSICS, entityphysics_t, physics, entityPhysicsInit, entityPhysicsDispose)
|
||||||
X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL)
|
X(TRIGGER, entitytrigger_t, trigger, entityTriggerInit, NULL)
|
||||||
|
X(OVERWORLD, entityoverworld_t, overworld, entityOverworldInit, NULL)
|
||||||
|
X(PLAYER, entityplayer_t, player, entityPlayerInit, NULL)
|
||||||
|
X(INTERACTABLE, entityinteractable_t, interactable, entityInteractableInit, NULL)
|
||||||
|
X(OVERWORLD_CAMERA, entityoverworldcamera_t, overworldCamera, entityOverworldCameraInit, NULL)
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ void entityDisposeDeep(const entityid_t entityId) {
|
|||||||
void entityUpdate(const entityid_t entityId) {
|
void entityUpdate(const entityid_t entityId) {
|
||||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||||
for(uint8_t i = 0; i < ent->updateCount; i++) {
|
for(uint8_t i = 0; i < ent->updateCount; i++) {
|
||||||
ent->onUpdate[i](entityId);
|
ent->onUpdate[i](entityId, ent->updateComponentId[i], ent->updateUser[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ void entityDispose(const entityid_t entityId) {
|
|||||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||||
|
|
||||||
for(uint8_t i = 0; i < ent->disposeCount; i++) {
|
for(uint8_t i = 0; i < ent->disposeCount; i++) {
|
||||||
ent->onDispose[i](entityId);
|
ent->onDispose[i](entityId, ent->disposeComponentId[i], ent->disposeUser[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
for(componentid_t i = 0; i < ENTITY_COMPONENT_COUNT_MAX; i++) {
|
||||||
@@ -108,13 +108,21 @@ void entityDispose(const entityid_t entityId) {
|
|||||||
ent->state = 0;
|
ent->state = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityUpdateAdd(const entityid_t entityId, const entitycallback_t callback) {
|
void entityUpdateAdd(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const entitycallback_t callback,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||||
assertTrue(
|
assertTrue(
|
||||||
ent->updateCount < ENTITY_UPDATE_CALLBACK_COUNT_MAX,
|
ent->updateCount < ENTITY_UPDATE_CALLBACK_COUNT_MAX,
|
||||||
"Entity update callback slots full"
|
"Entity update callback slots full"
|
||||||
);
|
);
|
||||||
ent->onUpdate[ent->updateCount++] = callback;
|
ent->onUpdate[ent->updateCount] = callback;
|
||||||
|
ent->updateComponentId[ent->updateCount] = componentId;
|
||||||
|
ent->updateUser[ent->updateCount] = user;
|
||||||
|
ent->updateCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callback) {
|
void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callback) {
|
||||||
@@ -123,19 +131,29 @@ void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callba
|
|||||||
if(ent->onUpdate[i] != callback) continue;
|
if(ent->onUpdate[i] != callback) continue;
|
||||||
ent->updateCount--;
|
ent->updateCount--;
|
||||||
for(uint8_t j = i; j < ent->updateCount; j++) {
|
for(uint8_t j = i; j < ent->updateCount; j++) {
|
||||||
ent->onUpdate[j] = ent->onUpdate[j + 1];
|
ent->onUpdate[j] = ent->onUpdate[j + 1];
|
||||||
|
ent->updateComponentId[j] = ent->updateComponentId[j + 1];
|
||||||
|
ent->updateUser[j] = ent->updateUser[j + 1];
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityDisposeAdd(const entityid_t entityId, const entitycallback_t callback) {
|
void entityDisposeAdd(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const entitycallback_t callback,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
entity_t *ent = &ENTITY_MANAGER.entities[entityId];
|
||||||
assertTrue(
|
assertTrue(
|
||||||
ent->disposeCount < ENTITY_DISPOSE_CALLBACK_COUNT_MAX,
|
ent->disposeCount < ENTITY_DISPOSE_CALLBACK_COUNT_MAX,
|
||||||
"Entity dispose callback slots full"
|
"Entity dispose callback slots full"
|
||||||
);
|
);
|
||||||
ent->onDispose[ent->disposeCount++] = callback;
|
ent->onDispose[ent->disposeCount] = callback;
|
||||||
|
ent->disposeComponentId[ent->disposeCount] = componentId;
|
||||||
|
ent->disposeUser[ent->disposeCount] = user;
|
||||||
|
ent->disposeCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void entityDisposeRemove(const entityid_t entityId, const entitycallback_t callback) {
|
void entityDisposeRemove(const entityid_t entityId, const entitycallback_t callback) {
|
||||||
@@ -144,7 +162,9 @@ void entityDisposeRemove(const entityid_t entityId, const entitycallback_t callb
|
|||||||
if(ent->onDispose[i] != callback) continue;
|
if(ent->onDispose[i] != callback) continue;
|
||||||
ent->disposeCount--;
|
ent->disposeCount--;
|
||||||
for(uint8_t j = i; j < ent->disposeCount; j++) {
|
for(uint8_t j = i; j < ent->disposeCount; j++) {
|
||||||
ent->onDispose[j] = ent->onDispose[j + 1];
|
ent->onDispose[j] = ent->onDispose[j + 1];
|
||||||
|
ent->disposeComponentId[j] = ent->disposeComponentId[j + 1];
|
||||||
|
ent->disposeUser[j] = ent->disposeUser[j + 1];
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,22 @@
|
|||||||
#define ENTITY_UPDATE_CALLBACK_COUNT_MAX 5
|
#define ENTITY_UPDATE_CALLBACK_COUNT_MAX 5
|
||||||
#define ENTITY_DISPOSE_CALLBACK_COUNT_MAX 5
|
#define ENTITY_DISPOSE_CALLBACK_COUNT_MAX 5
|
||||||
|
|
||||||
typedef void (*entitycallback_t)(const entityid_t entityId);
|
typedef void (*entitycallback_t)(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
uint8_t updateCount;
|
uint8_t updateCount;
|
||||||
uint8_t disposeCount;
|
uint8_t disposeCount;
|
||||||
entitycallback_t onUpdate[ENTITY_UPDATE_CALLBACK_COUNT_MAX];
|
entitycallback_t onUpdate[ENTITY_UPDATE_CALLBACK_COUNT_MAX];
|
||||||
|
componentid_t updateComponentId[ENTITY_UPDATE_CALLBACK_COUNT_MAX];
|
||||||
|
void *updateUser[ENTITY_UPDATE_CALLBACK_COUNT_MAX];
|
||||||
entitycallback_t onDispose[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
|
entitycallback_t onDispose[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
|
||||||
|
componentid_t disposeComponentId[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
|
||||||
|
void *disposeUser[ENTITY_DISPOSE_CALLBACK_COUNT_MAX];
|
||||||
} entity_t;
|
} entity_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,7 +93,12 @@ void entityDisposeDeep(const entityid_t entityId);
|
|||||||
* @param entityId The entity to register on.
|
* @param entityId The entity to register on.
|
||||||
* @param callback The function to call.
|
* @param callback The function to call.
|
||||||
*/
|
*/
|
||||||
void entityUpdateAdd(const entityid_t entityId, const entitycallback_t callback);
|
void entityUpdateAdd(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const entitycallback_t callback,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a previously registered update callback.
|
* Removes a previously registered update callback.
|
||||||
@@ -102,7 +115,12 @@ void entityUpdateRemove(const entityid_t entityId, const entitycallback_t callba
|
|||||||
* @param entityId The entity to register on.
|
* @param entityId The entity to register on.
|
||||||
* @param callback The function to call.
|
* @param callback The function to call.
|
||||||
*/
|
*/
|
||||||
void entityDisposeAdd(const entityid_t entityId, const entitycallback_t callback);
|
void entityDisposeAdd(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const entitycallback_t callback,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a previously registered dispose callback.
|
* Removes a previously registered dispose callback.
|
||||||
|
|||||||
@@ -8,11 +8,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
#define ENTITY_COUNT_MAX 100
|
#define ENTITY_COUNT_MAX 64
|
||||||
#define ENTITY_COMPONENT_COUNT_MAX 24
|
#define ENTITY_COMPONENT_COUNT_MAX 16
|
||||||
|
|
||||||
#define ENTITY_ID_INVALID 0xFF
|
#define ENTITY_ID_INVALID 0xFF
|
||||||
#define COMPONENT_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;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
facingdir.c
|
||||||
maptypes.c
|
maptypes.c
|
||||||
map.c
|
map.c
|
||||||
mapchunk.c
|
mapchunk.c
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "facingdir.h"
|
||||||
|
|
||||||
|
void facingDirToVec2(facingdir_t facing, vec2 dest) {
|
||||||
|
switch(facing) {
|
||||||
|
case FACING_DIR_UP: dest[0] = 0.0f; dest[1] = -1.0f; return;
|
||||||
|
case FACING_DIR_LEFT: dest[0] = -1.0f; dest[1] = 0.0f; return;
|
||||||
|
case FACING_DIR_RIGHT: dest[0] = 1.0f; dest[1] = 0.0f; return;
|
||||||
|
default: dest[0] = 0.0f; dest[1] = 1.0f; return;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FACING_DIR_DOWN = 0,
|
||||||
|
FACING_DIR_UP = 1,
|
||||||
|
FACING_DIR_LEFT = 2,
|
||||||
|
FACING_DIR_RIGHT = 3,
|
||||||
|
FACING_DIR_SOUTH = FACING_DIR_DOWN,
|
||||||
|
FACING_DIR_NORTH = FACING_DIR_UP,
|
||||||
|
FACING_DIR_WEST = FACING_DIR_LEFT,
|
||||||
|
FACING_DIR_EAST = FACING_DIR_RIGHT,
|
||||||
|
} facingdir_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a facing direction to a normalized XZ vec2.
|
||||||
|
*
|
||||||
|
* @param facing The facing direction.
|
||||||
|
* @param dest Output vec2 — [0] is X, [1] is Z.
|
||||||
|
*/
|
||||||
|
void facingDirToVec2(facingdir_t facing, vec2 dest);
|
||||||
@@ -6,6 +6,7 @@
|
|||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
overworldground.c
|
overworldground.c
|
||||||
|
overworldnpc.c
|
||||||
overworldplayer.c
|
overworldplayer.c
|
||||||
overworldscene.c
|
overworldscene.c
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -14,7 +14,14 @@
|
|||||||
|
|
||||||
#define OVERWORLD_GROUND_SIZE 20.0f
|
#define OVERWORLD_GROUND_SIZE 20.0f
|
||||||
|
|
||||||
static errorret_t overworldGroundDraw(void) {
|
static errorret_t overworldGroundDraw(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
(void)entityId;
|
||||||
|
(void)componentId;
|
||||||
|
(void)user;
|
||||||
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_MAGENTA));
|
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_MAGENTA));
|
||||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, NULL));
|
||||||
return meshDraw(&PLANE_MESH_SIMPLE, 0, -1);
|
return meshDraw(&PLANE_MESH_SIMPLE, 0, -1);
|
||||||
@@ -33,7 +40,7 @@ void overworldGroundAdd(overworldground_t *ground) {
|
|||||||
vec3 scale = { OVERWORLD_GROUND_SIZE * 2.0f, 1.0f, OVERWORLD_GROUND_SIZE * 2.0f };
|
vec3 scale = { OVERWORLD_GROUND_SIZE * 2.0f, 1.0f, OVERWORLD_GROUND_SIZE * 2.0f };
|
||||||
entityPositionSetLocalPosition(ground->entityId, ground->posCompId, pos);
|
entityPositionSetLocalPosition(ground->entityId, ground->posCompId, pos);
|
||||||
entityPositionSetLocalScale(ground->entityId, ground->posCompId, scale);
|
entityPositionSetLocalScale(ground->entityId, ground->posCompId, scale);
|
||||||
entityRenderableSetDraw(ground->entityId, renderComp, overworldGroundDraw);
|
entityRenderableSetDraw(ground->entityId, renderComp, overworldGroundDraw, NULL);
|
||||||
|
|
||||||
// Separate physics entity centered on the finite ground area.
|
// Separate physics entity centered on the finite ground area.
|
||||||
// The visual entity's position is its corner {-size, 0, -size}, not its
|
// The visual entity's position is its corner {-size, 0, -size}, not its
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "overworldnpc.h"
|
||||||
|
#include "entity/entitymanager.h"
|
||||||
|
#include "entity/component/physics/entityphysics.h"
|
||||||
|
#include "entity/component/trigger/entitytrigger.h"
|
||||||
|
#include "entity/component/overworld/entityoverworld.h"
|
||||||
|
#include "entity/component/overworld/entityinteractable.h"
|
||||||
|
|
||||||
|
void overworldNpcAdd(overworldnpc_t *npc, vec3 position) {
|
||||||
|
npc->entityId = entityManagerAdd();
|
||||||
|
npc->posCompId = entityAddComponent(npc->entityId, COMPONENT_TYPE_POSITION);
|
||||||
|
(void)entityAddComponent(npc->entityId, COMPONENT_TYPE_RENDERABLE);
|
||||||
|
(void)entityAddComponent(npc->entityId, COMPONENT_TYPE_PHYSICS);
|
||||||
|
npc->overworldCompId = entityAddComponent(npc->entityId, COMPONENT_TYPE_OVERWORLD);
|
||||||
|
npc->triggerCompId = entityAddComponent(npc->entityId, COMPONENT_TYPE_TRIGGER);
|
||||||
|
npc->interactableCompId = entityAddComponent(
|
||||||
|
npc->entityId, COMPONENT_TYPE_INTERACTABLE
|
||||||
|
);
|
||||||
|
|
||||||
|
entityPositionSetLocalPosition(npc->entityId, npc->posCompId, position);
|
||||||
|
|
||||||
|
componentid_t physCompId = entityOverworldGet(npc->entityId, npc->overworldCompId)->physCompId;
|
||||||
|
entityPhysicsSetBodyType(npc->entityId, physCompId, PHYSICS_BODY_STATIC);
|
||||||
|
physicsshape_t shape = {
|
||||||
|
.type = PHYSICS_SHAPE_CAPSULE,
|
||||||
|
.data.capsule = { .radius = 0.4f, .halfHeight = 0.1f }
|
||||||
|
};
|
||||||
|
entityPhysicsSetShape(npc->entityId, physCompId, shape);
|
||||||
|
|
||||||
|
vec3 min = {
|
||||||
|
position[0] - OVERWORLD_NPC_INTERACT_RANGE,
|
||||||
|
position[1] - OVERWORLD_NPC_INTERACT_RANGE,
|
||||||
|
position[2] - OVERWORLD_NPC_INTERACT_RANGE
|
||||||
|
};
|
||||||
|
vec3 max = {
|
||||||
|
position[0] + OVERWORLD_NPC_INTERACT_RANGE,
|
||||||
|
position[1] + OVERWORLD_NPC_INTERACT_RANGE,
|
||||||
|
position[2] + OVERWORLD_NPC_INTERACT_RANGE
|
||||||
|
};
|
||||||
|
entityTriggerSetBounds(npc->entityId, npc->triggerCompId, min, max);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "entity/entitybase.h"
|
||||||
|
|
||||||
|
#define OVERWORLD_NPC_INTERACT_RANGE 1.5f
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
entityid_t entityId;
|
||||||
|
componentid_t posCompId;
|
||||||
|
componentid_t overworldCompId;
|
||||||
|
componentid_t triggerCompId;
|
||||||
|
componentid_t interactableCompId;
|
||||||
|
} overworldnpc_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the NPC entity at the given world position.
|
||||||
|
*
|
||||||
|
* @param npc The NPC state to initialize.
|
||||||
|
* @param position World-space position to spawn the NPC at.
|
||||||
|
*/
|
||||||
|
void overworldNpcAdd(overworldnpc_t *npc, vec3 position);
|
||||||
@@ -8,43 +8,31 @@
|
|||||||
#include "overworldplayer.h"
|
#include "overworldplayer.h"
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
#include "entity/component/physics/entityphysics.h"
|
#include "entity/component/physics/entityphysics.h"
|
||||||
#include "input/input.h"
|
#include "entity/component/overworld/entityoverworld.h"
|
||||||
|
#include "entity/component/overworld/entityplayer.h"
|
||||||
#define OVERWORLD_PLAYER_SPEED 4.0f
|
|
||||||
#define OVERWORLD_PLAYER_RUN_SPEED 8.0f
|
|
||||||
|
|
||||||
void overworldPlayerAdd(overworldplayer_t *player) {
|
void overworldPlayerAdd(overworldplayer_t *player) {
|
||||||
player->entityId = entityManagerAdd();
|
player->entityId = entityManagerAdd();
|
||||||
player->posCompId = entityAddComponent(player->entityId, COMPONENT_TYPE_POSITION);
|
player->posCompId = entityAddComponent(player->entityId, COMPONENT_TYPE_POSITION);
|
||||||
(void)entityAddComponent(player->entityId, COMPONENT_TYPE_RENDERABLE);
|
(void)entityAddComponent(player->entityId, COMPONENT_TYPE_RENDERABLE);
|
||||||
player->physCompId = entityAddComponent(player->entityId, COMPONENT_TYPE_PHYSICS);
|
(void)entityAddComponent(player->entityId, COMPONENT_TYPE_PHYSICS);
|
||||||
|
componentid_t owCompId = entityAddComponent(player->entityId, COMPONENT_TYPE_OVERWORLD);
|
||||||
|
entityOverworldSetType(player->entityId, owCompId, OVERWORLD_ENTITY_TYPE_PLAYER);
|
||||||
|
player->playerCompId = entityAddComponent(player->entityId, COMPONENT_TYPE_PLAYER);
|
||||||
|
|
||||||
vec3 pos = { 0.0f, 0.5f, 0.0f };
|
vec3 pos = { 0.0f, 0.5f, 0.0f };
|
||||||
entityPositionSetLocalPosition(player->entityId, player->posCompId, pos);
|
entityPositionSetLocalPosition(player->entityId, player->posCompId, pos);
|
||||||
|
|
||||||
entityPhysicsSetBodyType(player->entityId, player->physCompId, PHYSICS_BODY_DYNAMIC);
|
componentid_t physCompId = entityOverworldGet(player->entityId, owCompId)->physCompId;
|
||||||
|
entityPhysicsSetBodyType(player->entityId, physCompId, PHYSICS_BODY_DYNAMIC);
|
||||||
physicsshape_t shape = {
|
physicsshape_t shape = {
|
||||||
.type = PHYSICS_SHAPE_CAPSULE,
|
.type = PHYSICS_SHAPE_CAPSULE,
|
||||||
.data.capsule = { .radius = 0.4f, .halfHeight = 0.1f }
|
.data.capsule = { .radius = 0.4f, .halfHeight = 0.1f }
|
||||||
};
|
};
|
||||||
entityPhysicsSetShape(player->entityId, player->physCompId, shape);
|
entityPhysicsSetShape(player->entityId, physCompId, shape);
|
||||||
|
entityPhysicsGet(player->entityId, physCompId)->gravityScale = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void overworldPlayerUpdate(overworldplayer_t *player) {
|
void overworldPlayerUpdate(overworldplayer_t *player) {
|
||||||
vec2 dir;
|
entityPlayerUpdate(player->entityId, player->playerCompId);
|
||||||
inputAngle2D(
|
|
||||||
INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT,
|
|
||||||
INPUT_ACTION_UP, INPUT_ACTION_DOWN,
|
|
||||||
dir
|
|
||||||
);
|
|
||||||
|
|
||||||
float_t speed = inputIsDown(INPUT_ACTION_CANCEL)
|
|
||||||
? OVERWORLD_PLAYER_RUN_SPEED
|
|
||||||
: OVERWORLD_PLAYER_SPEED;
|
|
||||||
|
|
||||||
vec3 vel;
|
|
||||||
entityPhysicsGetVelocity(player->entityId, player->physCompId, vel);
|
|
||||||
vel[0] = dir[0] * speed;
|
|
||||||
vel[2] = dir[1] * speed;
|
|
||||||
entityPhysicsSetVelocity(player->entityId, player->physCompId, vel);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
entityid_t entityId;
|
entityid_t entityId;
|
||||||
componentid_t posCompId;
|
componentid_t posCompId;
|
||||||
componentid_t physCompId;
|
componentid_t playerCompId;
|
||||||
} overworldplayer_t;
|
} overworldplayer_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,60 +8,60 @@
|
|||||||
#include "overworldscene.h"
|
#include "overworldscene.h"
|
||||||
#include "overworldplayer.h"
|
#include "overworldplayer.h"
|
||||||
#include "overworldground.h"
|
#include "overworldground.h"
|
||||||
|
#include "overworldnpc.h"
|
||||||
#include "console/console.h"
|
#include "console/console.h"
|
||||||
#include "entity/entitymanager.h"
|
#include "entity/entitymanager.h"
|
||||||
#include "entity/component/physics/entityphysics.h"
|
#include "entity/component/overworld/entityinteractable.h"
|
||||||
|
#include "entity/component/overworld/entityoverworldcamera.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
|
||||||
#define OVERWORLD (SCENE.data.overworld)
|
#define OVERWORLD (SCENE.data.overworld)
|
||||||
|
|
||||||
|
static void overworldSceneNpcInteract(
|
||||||
|
const entityid_t entityId,
|
||||||
|
const componentid_t componentId,
|
||||||
|
void *user
|
||||||
|
) {
|
||||||
|
(void)entityId; (void)componentId; (void)user;
|
||||||
|
consolePrint("NPC interacted with!");
|
||||||
|
}
|
||||||
|
|
||||||
void overworldSceneInit(void) {
|
void overworldSceneInit(void) {
|
||||||
consolePrint("Overworld scene initialized");
|
consolePrint("Overworld scene initialized");
|
||||||
|
|
||||||
OVERWORLD.cameraEntityId = entityManagerAdd();
|
|
||||||
OVERWORLD.cameraPosCompId = entityAddComponent(
|
|
||||||
OVERWORLD.cameraEntityId, COMPONENT_TYPE_POSITION
|
|
||||||
);
|
|
||||||
OVERWORLD.cameraCamCompId = entityAddComponent(
|
|
||||||
OVERWORLD.cameraEntityId, COMPONENT_TYPE_CAMERA
|
|
||||||
);
|
|
||||||
|
|
||||||
overworldGroundAdd(&OVERWORLD.ground);
|
overworldGroundAdd(&OVERWORLD.ground);
|
||||||
overworldPlayerAdd(&OVERWORLD.player);
|
overworldPlayerAdd(&OVERWORLD.player);
|
||||||
|
|
||||||
OVERWORLD.refCubeEntityId = entityManagerAdd();
|
vec3 npcPos = { 3.0f, 0.5f, 3.0f };
|
||||||
componentid_t refPosComp = entityAddComponent(
|
overworldNpcAdd(&OVERWORLD.npc, npcPos);
|
||||||
OVERWORLD.refCubeEntityId, COMPONENT_TYPE_POSITION
|
|
||||||
);
|
|
||||||
(void)entityAddComponent(OVERWORLD.refCubeEntityId, COMPONENT_TYPE_RENDERABLE);
|
|
||||||
vec3 refPos = { 3.0f, 0.5f, 3.0f };
|
|
||||||
entityPositionSetLocalPosition(OVERWORLD.refCubeEntityId, refPosComp, refPos);
|
|
||||||
|
|
||||||
componentid_t refPhysComp = entityAddComponent(
|
OVERWORLD.cameraEntityId = entityManagerAdd();
|
||||||
OVERWORLD.refCubeEntityId, COMPONENT_TYPE_PHYSICS
|
(void)entityAddComponent(OVERWORLD.cameraEntityId, COMPONENT_TYPE_POSITION);
|
||||||
|
(void)entityAddComponent(OVERWORLD.cameraEntityId, COMPONENT_TYPE_CAMERA);
|
||||||
|
OVERWORLD.cameraOverworldCompId = entityAddComponent(
|
||||||
|
OVERWORLD.cameraEntityId, COMPONENT_TYPE_OVERWORLD_CAMERA
|
||||||
|
);
|
||||||
|
entityOverworldCameraSetTarget(
|
||||||
|
OVERWORLD.cameraEntityId, OVERWORLD.cameraOverworldCompId,
|
||||||
|
OVERWORLD.player.entityId, OVERWORLD.player.posCompId
|
||||||
|
);
|
||||||
|
entityoverworldcamera_t *camData = entityOverworldCameraGet(
|
||||||
|
OVERWORLD.cameraEntityId, OVERWORLD.cameraOverworldCompId
|
||||||
|
);
|
||||||
|
glm_vec3_copy((vec3){ 0.5f, 0.5f, 0.5f }, camData->targetOffset);
|
||||||
|
glm_vec3_copy((vec3){ 0.0f, 0.0f, 5.0f }, camData->eyeOffset);
|
||||||
|
camData->scale = 32.0f;
|
||||||
|
entityInteractableSetCallback(
|
||||||
|
OVERWORLD.npc.entityId, OVERWORLD.npc.interactableCompId,
|
||||||
|
overworldSceneNpcInteract, NULL
|
||||||
);
|
);
|
||||||
entityPhysicsSetBodyType(OVERWORLD.refCubeEntityId, refPhysComp, PHYSICS_BODY_STATIC);
|
|
||||||
physicsshape_t refShape = {
|
|
||||||
.type = PHYSICS_SHAPE_CAPSULE,
|
|
||||||
.data.capsule = { .radius = 0.4f, .halfHeight = 0.1f }
|
|
||||||
};
|
|
||||||
entityPhysicsSetShape(OVERWORLD.refCubeEntityId, refPhysComp, refShape);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t overworldSceneUpdate(void) {
|
errorret_t overworldSceneUpdate(void) {
|
||||||
overworldPlayerUpdate(&OVERWORLD.player);
|
overworldPlayerUpdate(&OVERWORLD.player);
|
||||||
|
|
||||||
vec3 pos;
|
entityOverworldCameraUpdate(
|
||||||
entityPositionGetLocalPosition(
|
OVERWORLD.cameraEntityId, OVERWORLD.cameraOverworldCompId
|
||||||
OVERWORLD.player.entityId, OVERWORLD.player.posCompId, pos
|
|
||||||
);
|
|
||||||
vec3 center = { pos[0] + 0.5f, pos[1] + 0.5f, pos[2] + 0.5f };
|
|
||||||
vec3 eyeOffset = { 0.0f, 0.0f, 5.0f };
|
|
||||||
entityCameraLookAtPixelPerfect(
|
|
||||||
OVERWORLD.cameraEntityId,
|
|
||||||
OVERWORLD.cameraPosCompId,
|
|
||||||
OVERWORLD.cameraCamCompId,
|
|
||||||
center, eyeOffset, 32.0f
|
|
||||||
);
|
);
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
@@ -69,12 +69,15 @@ errorret_t overworldSceneUpdate(void) {
|
|||||||
|
|
||||||
void overworldSceneDispose(void) {
|
void overworldSceneDispose(void) {
|
||||||
OVERWORLD.cameraEntityId = ENTITY_ID_INVALID;
|
OVERWORLD.cameraEntityId = ENTITY_ID_INVALID;
|
||||||
OVERWORLD.cameraPosCompId = COMPONENT_ID_INVALID;
|
OVERWORLD.cameraOverworldCompId = COMPONENT_ID_INVALID;
|
||||||
OVERWORLD.cameraCamCompId = COMPONENT_ID_INVALID;
|
|
||||||
OVERWORLD.ground.entityId = ENTITY_ID_INVALID;
|
OVERWORLD.ground.entityId = ENTITY_ID_INVALID;
|
||||||
OVERWORLD.ground.posCompId = COMPONENT_ID_INVALID;
|
OVERWORLD.ground.posCompId = COMPONENT_ID_INVALID;
|
||||||
OVERWORLD.ground.floorEntityId = ENTITY_ID_INVALID;
|
OVERWORLD.ground.floorEntityId = ENTITY_ID_INVALID;
|
||||||
OVERWORLD.player.entityId = ENTITY_ID_INVALID;
|
OVERWORLD.player.entityId = ENTITY_ID_INVALID;
|
||||||
OVERWORLD.player.posCompId = COMPONENT_ID_INVALID;
|
OVERWORLD.player.posCompId = COMPONENT_ID_INVALID;
|
||||||
OVERWORLD.refCubeEntityId = ENTITY_ID_INVALID;
|
OVERWORLD.npc.entityId = ENTITY_ID_INVALID;
|
||||||
|
OVERWORLD.npc.posCompId = COMPONENT_ID_INVALID;
|
||||||
|
OVERWORLD.npc.overworldCompId = COMPONENT_ID_INVALID;
|
||||||
|
OVERWORLD.npc.triggerCompId = COMPONENT_ID_INVALID;
|
||||||
|
OVERWORLD.npc.interactableCompId = COMPONENT_ID_INVALID;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,14 +10,14 @@
|
|||||||
#include "entity/entitybase.h"
|
#include "entity/entitybase.h"
|
||||||
#include "scene/overworld/overworldplayer.h"
|
#include "scene/overworld/overworldplayer.h"
|
||||||
#include "scene/overworld/overworldground.h"
|
#include "scene/overworld/overworldground.h"
|
||||||
|
#include "scene/overworld/overworldnpc.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
entityid_t cameraEntityId;
|
entityid_t cameraEntityId;
|
||||||
componentid_t cameraPosCompId;
|
componentid_t cameraOverworldCompId;
|
||||||
componentid_t cameraCamCompId;
|
|
||||||
overworldplayer_t player;
|
overworldplayer_t player;
|
||||||
overworldground_t ground;
|
overworldground_t ground;
|
||||||
entityid_t refCubeEntityId;
|
overworldnpc_t npc;
|
||||||
} overworldscene_t;
|
} overworldscene_t;
|
||||||
|
|
||||||
void overworldSceneInit(void);
|
void overworldSceneInit(void);
|
||||||
|
|||||||
Reference in New Issue
Block a user