Overworld render test.

This commit is contained in:
2025-09-11 23:33:24 -05:00
parent b4d94c2cbe
commit 964a9f64f2
32 changed files with 249 additions and 1219 deletions

View File

@@ -6,8 +6,6 @@
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
direction.c
entity.c
player.c
npc.c
)

View File

@@ -1,53 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "direction.h"
#include "assert/assert.h"
float_t directionToAngle(const direction_t dir) {
switch(dir) {
case DIRECTION_NORTH: return (M_PI_2);
case DIRECTION_SOUTH: return -(M_PI_2);
case DIRECTION_EAST: return 0;
case DIRECTION_WEST: return (M_PI);
default: return 0; // Should never happen
}
}
void directionGetCoordinates(
const direction_t dir,
int8_t *x, int8_t *y
) {
assertNotNull(x, "X coordinate pointer cannot be NULL");
assertNotNull(y, "Y coordinate pointer cannot be NULL");
switch(dir) {
case DIRECTION_NORTH:
*x = 0;
*y = -1;
break;
case DIRECTION_SOUTH:
*x = 0;
*y = 1;
break;
case DIRECTION_EAST:
*x = 1;
*y = 0;
break;
case DIRECTION_WEST:
*x = -1;
*y = 0;
break;
default:
assertUnreachable("Invalid direction");
break;
}
}

View File

@@ -1,41 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef enum {
DIRECTION_SOUTH = 0,
DIRECTION_EAST = 1,
DIRECTION_WEST = 2,
DIRECTION_NORTH = 3,
DIRECTION_UP = DIRECTION_NORTH,
DIRECTION_DOWN = DIRECTION_SOUTH,
DIRECTION_LEFT = DIRECTION_WEST,
DIRECTION_RIGHT = DIRECTION_EAST,
} direction_t;
/**
* Converts a direction to an angle in float_t format.
*
* @param dir The direction to convert.
* @return The angle corresponding to the direction.
*/
float_t directionToAngle(const direction_t dir);
/**
* Gets the relative coordinates for a given direction.
*
* @param dir The direction to get coordinates for.
* @param x Pointer to store the x coordinate.
* @param y Pointer to store the y coordinate.
*/
void directionGetCoordinates(
const direction_t dir,
int8_t *x, int8_t *y
);

View File

@@ -8,116 +8,30 @@
#include "entity.h"
#include "assert/assert.h"
#include "util/memory.h"
// #include "world/world.h"
// #include "world/tiledata.h"
#include "time.h"
entity_t ENTITIES[ENTITY_COUNT_MAX] = {0};
entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
{ NULL, NULL }, // ENTITY_TYPE_NULL
{ playerInit, playerUpdate }, // ENTITY_TYPE_PLAYER
{ NULL, NULL }, // ENTITY_TYPE_NPC
};
// entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT] = {
// {NULL}, // ENTITY_TYPE_NULL
// {
// .load = playerEntityLoad,
// .update = playerEntityUpdate,
// },
// {
// .load = npcLoad,
// .update = npcUpdate,
// .interact = npcInteract,
// },
// };
void entityInit(entity_t *entity) {
void entityInit(entity_t *entity, const entitytype_t type) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type");
assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
assertNotNull(ENTITY_CALLBACKS[type].init, "Entity type has no init function");
memoryZero(entity, sizeof(entity_t));
entity->type = type;
// entity->type = ENTITY_TYPE_NULL;
// entity->x = 0;
// entity->y = 0;
// entity->dir = DIRECTION_SOUTH;
// entity->id = 0;
// ENTITY_CALLBACKS[entity->type].load(entity, source);
ENTITY_CALLBACKS[type].init(entity);
}
void entityUpdate(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
// assertNotNull(
// ENTITY_CALLBACKS[entity->type].update,
// "Entity type has no update callback"
// );
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
assertNotNull(ENTITY_CALLBACKS[entity->type].update, "enttype lacks update");
// ENTITY_CALLBACKS[entity->type].update(entity);
if(entity->subX > 0) {
entity->subX -= entity->moveSpeed;
} else if(entity->subX < 0) {
entity->subX += entity->moveSpeed;
}
if(entity->subY > 0) {
entity->subY -= entity->moveSpeed;
} else if(entity->subY < 0) {
entity->subY += entity->moveSpeed;
}
}
void entityMove(entity_t *entity, const uint8_t moveSpeed) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
assertFalse(
entityIsMoving(entity),
"Entity is already moving, cannot move again"
);
int8_t x = 0, y = 0;
directionGetCoordinates(entity->dir, &x, &y);
// entity in way?
entity_t *ent = entityGetAt(entity->x + x, entity->y + y);
if(ent != NULL) return;
entity->x += x;
entity->y += y;
// entity->subX = TILE_WIDTH_HEIGHT * -x;
// entity->subY = TILE_WIDTH_HEIGHT * -y;
entity->moveSpeed = moveSpeed;
}
void entityTurn(entity_t *entity, const direction_t dir) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
assertTrue(
dir >= DIRECTION_SOUTH && dir <= DIRECTION_NORTH, "Invalid direction"
);
assertFalse(
entityIsMoving(entity), "Entity is already moving, cannot turn"
);
entity->dir = dir;
}
bool_t entityIsMoving(const entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type != ENTITY_TYPE_NULL, "Entity type NULL");
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
return entity->subX != 0 || entity->subY != 0;
}
entity_t * entityGetAt(
const int32_t tileX,
const int32_t tileY
) {
entity_t *entity = ENTITIES;
do {
if(entity->type == ENTITY_TYPE_NULL) continue;
if(entity->x == tileX && entity->y == tileY) return entity;
} while((entity++) < &ENTITIES[ENTITY_COUNT_MAX - 1]);
return NULL;
}
ENTITY_CALLBACKS[entity->type].update(entity);
}

View File

@@ -6,94 +6,51 @@
*/
#pragma once
#include "direction.h"
// #include "direction.h"
#include "rpg/entity/player.h"
#include "npc.h"
// #include "npc.h"
#define ENTITY_COUNT_MAX 32
#define ENTITY_TURN_DURATION 0.075f // Duration for turning in seconds
#define ENTITY_MOVE_DURATION 0.1f // Duration for moving 1 tile, in seconds.
#define ENTITY_PLAYER_INDEX 0
// #define ENTITY_TURN_DURATION 0.075f // Duration for turning in seconds
// #define ENTITY_MOVE_DURATION 0.1f // Duration for moving 1 tile, in seconds.
// #define ENTITY_PLAYER_INDEX 0
typedef struct {
void (*init)(entity_t *entity);
void (*update)(entity_t *entity);
} entitycallback_t;
typedef enum {
ENTITY_TYPE_NULL = 0,
ENTITY_TYPE_PLAYER = 1,
ENTITY_TYPE_NPC = 2,
ENTITY_TYPE_NULL,
ENTITY_TYPE_PLAYER,
ENTITY_TYPE_NPC,
ENTITY_TYPE_COUNT
} entitytype_t;
#define ENTITY_TYPE_COUNT 3
typedef struct _entity_t {
uint32_t id;// Completely unique ID for this entity.
int32_t x, y;
int8_t subX, subY;
uint8_t moveSpeed;
typedef struct entity_s {
// uint32_t id;// Completely unique ID for this entity.
float_t x, y;
entitytype_t type;
direction_t dir;
// direction_t dir;
union {
npc_t npc;
playerentity_t player;
player_t player;
};
} entity_t;
// typedef struct {
// void (*load) (entity_t *entity, const entity_t *source);
// void (*update) (entity_t *entity);
// void (*interact)(entity_t *player, entity_t *self);
// } entitycallback_t;
extern entity_t ENTITIES[ENTITY_COUNT_MAX];
// extern entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT];
extern entitycallback_t ENTITY_CALLBACKS[ENTITY_TYPE_COUNT];
/**
* Loads an entity from the generated entity data.
* Initializes an entity structure.
*
* @param entity Pointer to the entity to initialize.
* @param source Pointer to the source entity data.
* @param entity Pointer to the entity structure to initialize.
* @param type The type of the entity.
*/
void entityInit(entity_t *entity);
void entityInit(entity_t *entity, const entitytype_t type);
/**
* Updates the entity's state.
* Updates an entity.
*
* @param entity Pointer to the entity to update.
* @param entity Pointer to the entity structure to update.
*/
void entityUpdate(entity_t *entity);
/**
* Moves the entity by the specified x and y offsets.
*
* @param entity Pointer to the entity to move.
* @param moveSpeed The speed at which to move the entity.
*/
void entityMove(entity_t *entity, const uint8_t moveSpeed);
/**
* Turns the entity to face the specified direction.
*
* @param entity Pointer to the entity to turn.
* @param dir The direction to turn the entity to.
*/
void entityTurn(entity_t *entity, const direction_t dir);
/**
* Returns whether or not an entity is currently moving.
*
* @param entity Pointer to the entity to check.
* @return True if the entity is moving, false otherwise.
*/
bool_t entityIsMoving(const entity_t *entity);
/**
* Gets the entity at the specified tile coordinates.
*
* @param tileX The x coordinate of the tile to get the entity from.
* @param tileY The y coordinate of the tile to get the entity from.
* @return Pointer to the entity at the specified coordinates, or NULL if no
* entity exists there.
*/
entity_t *entityGetAt(
const int32_t tileX,
const int32_t tileY
);
void entityUpdate(entity_t *entity);

View File

@@ -1,45 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity.h"
// #include "ui/uitextbox.h"
// #include "locale/language.h"
#include "assert/assert.h"
void npcLoad(entity_t *entity, const entity_t *source) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertNotNull(source, "Source entity pointer cannot be NULL");
assertTrue(source->type == ENTITY_TYPE_NPC, "Source entity type must be NPC");
entity->npc = source->npc;
}
void npcUpdate(entity_t *entity) {
}
void npcInteract(entity_t *player, entity_t *self) {
assertTrue(self->type == ENTITY_TYPE_NPC, "Entity must be of type NPC");
switch(self->npc.interactType) {
case NPC_INTERACT_TYPE_NONE:
break;
case NPC_INTERACT_TYPE_TEXT:
// uiTextboxSetText(languageGet(self->npc.text));
break;
case NPC_INTERACT_TYPE_CONVO:
break;
case NPC_INTERACT_TYPE_EVENT:
// eventSetActive(self->npc.eventData);
break;
default:
assertUnreachable("Unknown NPC interaction type");
}
}

View File

@@ -1,44 +0,0 @@
#pragma once
#include "dusk.h"
typedef struct _entity_t entity_t;
typedef enum {
NPC_INTERACT_TYPE_NONE = 0,
NPC_INTERACT_TYPE_TEXT = 1,
NPC_INTERACT_TYPE_CONVO = 2,
NPC_INTERACT_TYPE_EVENT = 3,
} npcinteracttype_t;
typedef struct {
npcinteracttype_t interactType;
union {
const char_t* text;
// const eventdata_t *eventData;
};
} npc_t;
/**
* Initializes the NPC entity.
*
* @param entity The entity to initialize.
* @param source The source entity to copy data from.
*/
void npcLoad(entity_t *entity, const entity_t *source);
/**
* Updates the NPC entity.
*
* @param entity The entity to update.
*/
void npcUpdate(entity_t *entity);
/**
* Handles interaction between the player and the NPC.
*
* @param player The player entity interacting with the NPC.
* @param self The NPC entity being interacted with.
*/
void npcInteract(entity_t *player, entity_t *self);

View File

@@ -7,81 +7,23 @@
#include "entity.h"
#include "assert/assert.h"
#include "time/time.h"
#include "input/input.h"
// #include "display/render.h"
// #include "world/world.h"
// #include "ui/uitextbox.h"
inventory_t PLAYER_INVENTORY;
void playerInit() {
entity_t *ent = &ENTITIES[ENTITY_PLAYER_INDEX];
entityInit(ent);
inventoryInit(&PLAYER_INVENTORY, INVENTORY_SIZE_MAX);
void playerInit(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
}
void playerEntityLoad(entity_t *entity, const entity_t *source) {
void playerUpdate(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertNotNull(source, "Source entity pointer cannot be NULL");
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER");
assertTrue(source->type == entity->type, "Source/Entity type mismatch");
}
void playerEntityUpdate(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL");
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity type must be PLAYER");
// TODO: make this just a method somewhere.
// if(UI_TEXTBOX.visible) return;
if(entityIsMoving(entity)) return;
// const uint8_t moveSpeed = inputIsDown(INPUT_BIND_CANCEL) ? PLAYER_SPEED_RUN : PLAYER_SPEED_WALK;
const uint8_t moveSpeed = PLAYER_SPEED_WALK;
// if(inputIsDown(INPUT_BIND_UP)) {
// if(entity->dir != DIRECTION_NORTH) {
// entityTurn(entity, DIRECTION_NORTH);
// return;
// }
// entityMove(entity, moveSpeed);
// return;
// } else if(inputIsDown(INPUT_BIND_DOWN)) {
// if(entity->dir != DIRECTION_SOUTH) {
// entityTurn(entity, DIRECTION_SOUTH);
// return;
// }
// entityMove(entity, moveSpeed);
// return;
// } else if(inputIsDown(INPUT_BIND_LEFT)) {
// if(entity->dir != DIRECTION_WEST) {
// entityTurn(entity, DIRECTION_WEST);
// return;
// }
// entityMove(entity, moveSpeed);
// return;
// } else if(inputIsDown(INPUT_BIND_RIGHT)) {
// if(entity->dir != DIRECTION_EAST) {
// entityTurn(entity, DIRECTION_EAST);
// return;
// }
// entityMove(entity, moveSpeed);
// return;
// }
// Interact
// if(inputPressed(INPUT_BIND_ACTION)) {
// int8_t x, y;
// directionGetCoordinates(entity->dir, &x, &y);
// entity_t *ent = entityGetAt(entity->x + x, entity->y + y);
// // if(ent != NULL && ENTITY_CALLBACKS[ent->type].interact != NULL) {
// // assertTrue(ent->type < ENTITY_TYPE_COUNT, "Entity type out of bounds");
// // ENTITY_CALLBACKS[ent->type].interact(entity, ent);
// // }
// }
// testing only
float_t move = TIME.delta * 128.0f; // tiles per second
vec2 dir = {
inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT),
inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN)
};
glm_vec2_normalize(dir);
entity->x += move * dir[0];
entity->y -= move * dir[1];
}

View File

@@ -7,37 +7,23 @@
#pragma once
#include "dusk.h"
#include "rpg/item/inventory.h"
#define PLAYER_SPEED_WALK 1
#define PLAYER_SPEED_RUN 2
typedef struct _entity_t entity_t;
typedef struct entity_s entity_t;
typedef struct {
uint32_t nothing;
} playerentity_t;
#define PLAYER_ENTITY_ID (UINT32_MAX-1)
extern inventory_t PLAYER_INVENTORY;
void *nothing;
} player_t;
/**
* Initializes the player and all player-related entities.
*/
void playerInit(void);
/**
* Loads the player entity.
* Initializes a player entity.
*
* @param entity The entity to initialize.
* @param source The source entity to copy data from.
* @param entity Pointer to the entity structure to initialize.
*/
void playerEntityLoad(entity_t *entity, const entity_t *source);
void playerInit(entity_t *entity);
/**
* Updates the player entity.
* Updates a player entity.
*
* @param entity The entity to update.
* @param entity Pointer to the entity structure to update.
*/
void playerEntityUpdate(entity_t *entity);
void playerUpdate(entity_t *entity);