Setup rpg stuff
This commit is contained in:
@@ -36,7 +36,7 @@ add_subdirectory(error)
|
|||||||
add_subdirectory(input)
|
add_subdirectory(input)
|
||||||
# add_subdirectory(locale)
|
# add_subdirectory(locale)
|
||||||
add_subdirectory(physics)
|
add_subdirectory(physics)
|
||||||
# add_subdirectory(rpg)
|
add_subdirectory(rpg)
|
||||||
add_subdirectory(scene)
|
add_subdirectory(scene)
|
||||||
add_subdirectory(thread)
|
add_subdirectory(thread)
|
||||||
add_subdirectory(time)
|
add_subdirectory(time)
|
||||||
|
@@ -29,7 +29,6 @@ static const char_t ASSET_MANAGER_SEARCH_PATHS[][FILENAME_MAX] = {
|
|||||||
)
|
)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t nothing;
|
|
||||||
zip_t *zip;
|
zip_t *zip;
|
||||||
asset_t assets[ASSET_MANAGER_ASSET_COUNT_MAX];
|
asset_t assets[ASSET_MANAGER_ASSET_COUNT_MAX];
|
||||||
uint8_t assetCount;
|
uint8_t assetCount;
|
||||||
|
@@ -15,6 +15,11 @@ void cmdScene(const consolecmdexec_t *exec) {
|
|||||||
consolePrint("Usage: scene <name>");
|
consolePrint("Usage: scene <name>");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strcmp(exec->argv[0], "null") == 0) {
|
||||||
|
sceneManagerSetScene(NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scene_t *scene = sceneManagerGetSceneByName(exec->argv[0]);
|
scene_t *scene = sceneManagerGetSceneByName(exec->argv[0]);
|
||||||
if(scene == NULL) {
|
if(scene == NULL) {
|
||||||
@@ -22,17 +27,16 @@ void cmdScene(const consolecmdexec_t *exec) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((scene->flags & SCENE_FLAG_INITIALIZED) == 0) {
|
|
||||||
if(scene->init) {
|
|
||||||
errorret_t ret = errorPrint(scene->init(&SCENE_MANAGER.sceneData));
|
|
||||||
if(ret.code != ERROR_OK) {
|
|
||||||
errorCatch(ret);
|
|
||||||
consolePrint("Error: Failed to initialize scene '%s'.", exec->argv[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
scene->flags |= SCENE_FLAG_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
sceneManagerSetScene(scene);
|
sceneManagerSetScene(scene);
|
||||||
|
|
||||||
|
if(scene->init) {
|
||||||
|
errorret_t ret = errorPrint(scene->init(&SCENE_MANAGER.sceneData));
|
||||||
|
if(ret.code != ERROR_OK) {
|
||||||
|
errorCatch(ret);
|
||||||
|
sceneManagerSetScene(NULL);
|
||||||
|
consolePrint("Error: Failed to initialize scene '%s'.", exec->argv[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene->flags |= SCENE_FLAG_INITIALIZED;
|
||||||
}
|
}
|
@@ -13,6 +13,7 @@
|
|||||||
#include "display/display.h"
|
#include "display/display.h"
|
||||||
#include "scene/scenemanager.h"
|
#include "scene/scenemanager.h"
|
||||||
#include "asset/assetmanager.h"
|
#include "asset/assetmanager.h"
|
||||||
|
#include "rpg/rpg.h"
|
||||||
|
|
||||||
engine_t ENGINE;
|
engine_t ENGINE;
|
||||||
|
|
||||||
@@ -29,6 +30,7 @@ errorret_t engineInit(void) {
|
|||||||
inputInit();
|
inputInit();
|
||||||
errorChain(assetManagerInit());
|
errorChain(assetManagerInit());
|
||||||
errorChain(displayInit());
|
errorChain(displayInit());
|
||||||
|
errorChain(rpgInit());
|
||||||
errorChain(sceneManagerInit());
|
errorChain(sceneManagerInit());
|
||||||
|
|
||||||
// Init scripts
|
// Init scripts
|
||||||
@@ -47,6 +49,7 @@ errorret_t engineUpdate(void) {
|
|||||||
consoleUpdate();
|
consoleUpdate();
|
||||||
assetManagerUpdate();
|
assetManagerUpdate();
|
||||||
|
|
||||||
|
rpgUpdate();
|
||||||
sceneManagerUpdate();
|
sceneManagerUpdate();
|
||||||
errorChain(displayUpdate());
|
errorChain(displayUpdate());
|
||||||
|
|
||||||
@@ -59,6 +62,7 @@ void engineExit(void) {
|
|||||||
|
|
||||||
errorret_t engineDispose(void) {
|
errorret_t engineDispose(void) {
|
||||||
sceneManagerDispose();
|
sceneManagerDispose();
|
||||||
|
rpgDispose();
|
||||||
errorChain(displayDispose());
|
errorChain(displayDispose());
|
||||||
assetManagerDispose();
|
assetManagerDispose();
|
||||||
consoleDispose();
|
consoleDispose();
|
||||||
|
13
src/rpg/CMakeLists.txt
Normal file
13
src/rpg/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2025 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
|
PRIVATE
|
||||||
|
rpg.c
|
||||||
|
)
|
||||||
|
|
||||||
|
# Subdirs
|
||||||
|
add_subdirectory(entity)
|
13
src/rpg/entity/CMakeLists.txt
Normal file
13
src/rpg/entity/CMakeLists.txt
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Copyright (c) 2025 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
|
PRIVATE
|
||||||
|
entity.c
|
||||||
|
npc.c
|
||||||
|
player.c
|
||||||
|
direction.c
|
||||||
|
)
|
48
src/rpg/entity/direction.c
Normal file
48
src/rpg/entity/direction.c
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* 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 directionGetVec2(const direction_t dir, vec2 out) {
|
||||||
|
assertNotNull(out, "Output vector cannot be NULL");
|
||||||
|
|
||||||
|
switch(dir) {
|
||||||
|
case DIRECTION_NORTH:
|
||||||
|
out[0] = 0.0f;
|
||||||
|
out[1] = 1.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION_SOUTH:
|
||||||
|
out[0] = 0.0f;
|
||||||
|
out[1] = -1.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION_EAST:
|
||||||
|
out[0] = 1.0f;
|
||||||
|
out[1] = 0.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DIRECTION_WEST:
|
||||||
|
out[0] = -1.0f;
|
||||||
|
out[1] = 0.0f;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assertUnreachable("Invalid direction");
|
||||||
|
}
|
||||||
|
}
|
37
src/rpg/entity/direction.h
Normal file
37
src/rpg/entity/direction.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a direction to a vec2 unit vector.
|
||||||
|
*
|
||||||
|
* @param dir The direction to convert.
|
||||||
|
* @param out Pointer to the vec2 array to populate.
|
||||||
|
*/
|
||||||
|
void directionGetVec2(const direction_t dir, vec2 out);
|
107
src/rpg/entity/entity.c
Normal file
107
src/rpg/entity/entity.c
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entity.h"
|
||||||
|
#include "rpg/world/map.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "display/tileset/tileset_entities.h"
|
||||||
|
#include "time/time.h"
|
||||||
|
#include "util/math.h"
|
||||||
|
|
||||||
|
void entityInit(entity_t *entity, const entitytype_t type, map_t *map) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
assertNotNull(map, "Map pointer cannot be NULL");
|
||||||
|
assertTrue(type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
||||||
|
assertTrue(type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
|
||||||
|
|
||||||
|
memoryZero(entity, sizeof(entity_t));
|
||||||
|
entity->type = type;
|
||||||
|
entity->map = map;
|
||||||
|
|
||||||
|
// Init. I did use a callback struct but it was not flexible enough.
|
||||||
|
switch(type) {
|
||||||
|
case ENTITY_TYPE_PLAYER:
|
||||||
|
playerInit(entity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENTITY_TYPE_NPC:
|
||||||
|
npcInit(entity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void entityUpdate(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
assertTrue(entity->type < ENTITY_TYPE_COUNT, "Invalid entity type");
|
||||||
|
assertTrue(entity->type != ENTITY_TYPE_NULL, "Cannot have NULL entity type");
|
||||||
|
|
||||||
|
// Handle movement logic
|
||||||
|
switch(entity->type) {
|
||||||
|
case ENTITY_TYPE_PLAYER:
|
||||||
|
playerMovement(entity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ENTITY_TYPE_NPC:
|
||||||
|
npcUpdate(entity);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply velocity
|
||||||
|
if(entity->velocity[0] != 0.0f || entity->velocity[1] != 0.0f) {
|
||||||
|
entity->position[0] += entity->velocity[0] * TIME.delta;
|
||||||
|
entity->position[1] += entity->velocity[1] * TIME.delta;
|
||||||
|
|
||||||
|
// Hit test on other entities.
|
||||||
|
entity_t *start = entity->map->entities;
|
||||||
|
entity_t *end = &entity->map->entities[entity->map->entityCount];
|
||||||
|
|
||||||
|
// Our hitbox
|
||||||
|
physicscircle_t self;
|
||||||
|
glm_vec2_copy(entity->position, self.position);
|
||||||
|
self.radius = TILESET_ENTITIES.tileWidth / 2.0f;
|
||||||
|
|
||||||
|
physicscircle_t other;
|
||||||
|
other.radius = self.radius;
|
||||||
|
|
||||||
|
// TODO: what if multiple collisions?
|
||||||
|
do {
|
||||||
|
if(start == entity) continue;
|
||||||
|
if(start->type == ENTITY_TYPE_NULL) continue;
|
||||||
|
glm_vec2_copy(start->position, other.position);
|
||||||
|
|
||||||
|
physicscirclecircleresult_t result;
|
||||||
|
physicsCircleCheckCircle(self, other, &result);
|
||||||
|
|
||||||
|
if(result.hit) {
|
||||||
|
entity->position[0] -= result.normal[0] * result.depth;
|
||||||
|
entity->position[1] -= result.normal[1] * result.depth;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while((start++) != end);
|
||||||
|
|
||||||
|
// Friction (and dampening)
|
||||||
|
entity->velocity[0] *= ENTITY_FRICTION * TIME.delta;
|
||||||
|
entity->velocity[1] *= ENTITY_FRICTION * TIME.delta;
|
||||||
|
if(mathAbs(entity->velocity[0]) < ENTITY_MIN_VELOCITY) {
|
||||||
|
entity->velocity[0] = 0.0f;
|
||||||
|
}
|
||||||
|
if(mathAbs(entity->velocity[1]) < ENTITY_MIN_VELOCITY) {
|
||||||
|
entity->velocity[1] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(entity->type == ENTITY_TYPE_PLAYER) {
|
||||||
|
playerInteraction(entity);
|
||||||
|
}
|
||||||
|
}
|
55
src/rpg/entity/entity.h
Normal file
55
src/rpg/entity/entity.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "direction.h"
|
||||||
|
#include "rpg/entity/player.h"
|
||||||
|
#include "npc.h"
|
||||||
|
#include "physics/physics.h"
|
||||||
|
|
||||||
|
#define ENTITY_FRICTION 0.9f
|
||||||
|
#define ENTITY_MIN_VELOCITY 0.05f
|
||||||
|
|
||||||
|
typedef struct map_s map_t;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ENTITY_TYPE_NULL,
|
||||||
|
ENTITY_TYPE_PLAYER,
|
||||||
|
ENTITY_TYPE_NPC,
|
||||||
|
|
||||||
|
ENTITY_TYPE_COUNT
|
||||||
|
} entitytype_t;
|
||||||
|
|
||||||
|
typedef struct entity_s {
|
||||||
|
map_t *map;
|
||||||
|
entitytype_t type;
|
||||||
|
direction_t direction;
|
||||||
|
|
||||||
|
vec2 position;
|
||||||
|
vec2 velocity;
|
||||||
|
|
||||||
|
union {
|
||||||
|
player_t player;
|
||||||
|
npc_t npc;
|
||||||
|
};
|
||||||
|
} entity_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an entity structure.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the entity structure to initialize.
|
||||||
|
* @param type The type of the entity.
|
||||||
|
* @param map Pointer to the map the entity belongs to.
|
||||||
|
*/
|
||||||
|
void entityInit(entity_t *entity, const entitytype_t type, map_t *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the entity structure to update.
|
||||||
|
*/
|
||||||
|
void entityUpdate(entity_t *entity);
|
17
src/rpg/entity/npc.c
Normal file
17
src/rpg/entity/npc.c
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entity.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
void npcInit(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
void npcUpdate(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
}
|
29
src/rpg/entity/npc.h
Normal file
29
src/rpg/entity/npc.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef struct entity_s entity_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *nothing;
|
||||||
|
} npc_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an NPC entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the entity structure to initialize.
|
||||||
|
*/
|
||||||
|
void npcInit(entity_t *entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates an NPC entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the entity structure to update.
|
||||||
|
*/
|
||||||
|
void npcUpdate(entity_t *entity);
|
114
src/rpg/entity/player.c
Normal file
114
src/rpg/entity/player.c
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "entity.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "input/input.h"
|
||||||
|
#include "display/tileset/tileset_entities.h"
|
||||||
|
|
||||||
|
void playerInit(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerMovement(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
|
||||||
|
// Update velocity.
|
||||||
|
vec2 dir = {
|
||||||
|
inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT),
|
||||||
|
inputAxis(INPUT_ACTION_DOWN, INPUT_ACTION_UP)
|
||||||
|
};
|
||||||
|
if(dir[0] == 0 && dir[1] == 0) return;
|
||||||
|
|
||||||
|
glm_vec2_normalize(dir);
|
||||||
|
entity->velocity[0] += PLAYER_SPEED * dir[0];
|
||||||
|
entity->velocity[1] += PLAYER_SPEED * dir[1];
|
||||||
|
|
||||||
|
// Update direction.
|
||||||
|
if(dir[0] > 0) {
|
||||||
|
if(entity->direction == DIRECTION_RIGHT) {
|
||||||
|
entity->direction = DIRECTION_RIGHT;
|
||||||
|
} else {
|
||||||
|
if(dir[1] < 0) {
|
||||||
|
entity->direction = DIRECTION_UP;
|
||||||
|
} else if(dir[1] > 0) {
|
||||||
|
entity->direction = DIRECTION_DOWN;
|
||||||
|
} else {
|
||||||
|
entity->direction = DIRECTION_RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(dir[0] < 0) {
|
||||||
|
if(entity->direction == DIRECTION_LEFT) {
|
||||||
|
entity->direction = DIRECTION_LEFT;
|
||||||
|
} else {
|
||||||
|
if(dir[1] < 0) {
|
||||||
|
entity->direction = DIRECTION_UP;
|
||||||
|
} else if(dir[1] > 0) {
|
||||||
|
entity->direction = DIRECTION_DOWN;
|
||||||
|
} else {
|
||||||
|
entity->direction = DIRECTION_LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if(dir[1] < 0) {
|
||||||
|
entity->direction = DIRECTION_UP;
|
||||||
|
} else if(dir[1] > 0) {
|
||||||
|
entity->direction = DIRECTION_DOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void playerInteraction(entity_t *entity) {
|
||||||
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
|
|
||||||
|
if(!inputPressed(INPUT_ACTION_ACCEPT)) return;
|
||||||
|
|
||||||
|
physicsbox_t interactBox;
|
||||||
|
|
||||||
|
// Get direction vector
|
||||||
|
directionGetVec2(entity->direction, interactBox.min);
|
||||||
|
|
||||||
|
// Scale by interact range
|
||||||
|
glm_vec2_scale(interactBox.min, PLAYER_INTERACTION_RANGE, interactBox.min);
|
||||||
|
|
||||||
|
// Add entity position, this makes the center of the box.
|
||||||
|
glm_vec2_add(interactBox.min, entity->position, interactBox.min);
|
||||||
|
|
||||||
|
// Copy to max
|
||||||
|
glm_vec2_copy(interactBox.min, interactBox.max);
|
||||||
|
|
||||||
|
// Size of the hitbox
|
||||||
|
vec2 halfSize = {
|
||||||
|
TILESET_ENTITIES.tileWidth * PLAYER_INTERACTION_SIZE * 0.5f,
|
||||||
|
TILESET_ENTITIES.tileHeight * PLAYER_INTERACTION_SIZE * 0.5f
|
||||||
|
};
|
||||||
|
|
||||||
|
// Subtract from min, add to max.
|
||||||
|
glm_vec2_sub(interactBox.min, halfSize, interactBox.min);
|
||||||
|
glm_vec2_add(interactBox.max, halfSize, interactBox.max);
|
||||||
|
|
||||||
|
// For each entity
|
||||||
|
entity_t *start = entity->map->entities;
|
||||||
|
entity_t *end = &entity->map->entities[entity->map->entityCount];
|
||||||
|
vec2 otherSize = { TILESET_ENTITIES.tileWidth, TILESET_ENTITIES.tileHeight };
|
||||||
|
physicsbox_t otherBox;
|
||||||
|
physicsboxboxresult_t result;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(start->type != ENTITY_TYPE_NPC) continue;
|
||||||
|
|
||||||
|
// Setup other box.
|
||||||
|
glm_vec2_copy(start->position, otherBox.min);
|
||||||
|
glm_vec2_copy(start->position, otherBox.max);
|
||||||
|
glm_vec2_sub(otherBox.min, otherSize, otherBox.min);
|
||||||
|
glm_vec2_add(otherBox.min, otherSize, otherBox.max);
|
||||||
|
|
||||||
|
physicsBoxCheckBox(interactBox, otherBox, &result);
|
||||||
|
if(!result.hit) continue;
|
||||||
|
|
||||||
|
printf("Interacted with entity at (%.2f, %.2f)\n", start->position[0], start->position[1]);
|
||||||
|
break;
|
||||||
|
} while(++start != end);
|
||||||
|
}
|
40
src/rpg/entity/player.h
Normal file
40
src/rpg/entity/player.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
#define PLAYER_SPEED 64.0f
|
||||||
|
#define PLAYER_INTERACTION_RANGE 1.0f
|
||||||
|
#define PLAYER_INTERACTION_SIZE 0.5f
|
||||||
|
|
||||||
|
typedef struct entity_s entity_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void *nothing;
|
||||||
|
} player_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a player entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the entity structure to initialize.
|
||||||
|
*/
|
||||||
|
void playerInit(entity_t *entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles movement logic for the player entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the player entity structure.
|
||||||
|
*/
|
||||||
|
void playerMovement(entity_t *entity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles interaction logic for the player entity.
|
||||||
|
*
|
||||||
|
* @param entity Pointer to the player entity structure.
|
||||||
|
*/
|
||||||
|
void playerInteraction(entity_t *entity);
|
20
src/rpg/rpg.c
Normal file
20
src/rpg/rpg.c
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rpg.h"
|
||||||
|
|
||||||
|
errorret_t rpgInit(void) {
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpgUpdate(void) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpgDispose(void) {
|
||||||
|
|
||||||
|
}
|
@@ -6,8 +6,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "error/error.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
map_t map;
|
int32_t nothing;
|
||||||
} rpg_t;
|
} rpg_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the RPG subsystem.
|
||||||
|
*
|
||||||
|
* @return An error code and state.
|
||||||
|
*/
|
||||||
|
errorret_t rpgInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the RPG subsystem.
|
||||||
|
*/
|
||||||
|
void rpgUpdate(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dispose of the RPG subsystem.
|
||||||
|
*/
|
||||||
|
void rpgDispose(void);
|
54
src/rpg/world/worldunit.h
Normal file
54
src/rpg/world/worldunit.h
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position in SUBTILE space in a world, each unit represents a single subtile.
|
||||||
|
* This is divided by the size of the tile, e.g. if a tile is 16x16 then there
|
||||||
|
* are 256 / tile size = units per pixel of a tile. This means there are always
|
||||||
|
* uint8_t max subtiles in a tile.
|
||||||
|
*/
|
||||||
|
typedef uint8_t worldsubtile_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position in TILE space in a world, each unit represents a single tile. This
|
||||||
|
* is within CHUNK space. This is not different depending on chunk size, if the
|
||||||
|
* chunks are 32 tiles wide then the max tile value is 31.
|
||||||
|
*/
|
||||||
|
typedef uint8_t worldtile_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a position in a world in SUBTILE and TILE space. This is basically
|
||||||
|
* just a convenience struct so you don't have to pass two variables around.
|
||||||
|
*
|
||||||
|
* For example, an entity may be at tile (2, 3) and subtile (8, 12).
|
||||||
|
* meaning that the entity is at pixel (2 * TILE_SIZE + 8, 3 * TILE_SIZE + 12)
|
||||||
|
* in world space.
|
||||||
|
*
|
||||||
|
* This is still within CHUNK space.
|
||||||
|
*/
|
||||||
|
typedef struct worldchunkpos_s {
|
||||||
|
worldsubtile_t subtile;
|
||||||
|
worldtile_t tile;
|
||||||
|
} worldchunkpos_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Position in CHUNK space in a world, each unit represents a single chunk.
|
||||||
|
*/
|
||||||
|
typedef uint8_t worldchunk_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a position in a world in SUBTILE, TILE and CHUNK space. This is in
|
||||||
|
* WORLD space, so this is the full position of an entity in the world.
|
||||||
|
*/
|
||||||
|
typedef struct worldpos_s {
|
||||||
|
worldsubtile_t subtile;
|
||||||
|
worldtile_t tile;
|
||||||
|
worldchunk_t chunk;
|
||||||
|
} worldpos_t;
|
@@ -22,5 +22,6 @@ static scene_t SCENE_TEST = {
|
|||||||
.init = sceneTestInit,
|
.init = sceneTestInit,
|
||||||
.update = sceneTestUpdate,
|
.update = sceneTestUpdate,
|
||||||
.render = sceneTestRender,
|
.render = sceneTestRender,
|
||||||
.dispose = sceneTestDispose
|
.dispose = sceneTestDispose,
|
||||||
|
.flags = 0
|
||||||
};
|
};
|
@@ -65,8 +65,8 @@ void sceneManagerSetScene(scene_t *scene) {
|
|||||||
|
|
||||||
if(scene) {
|
if(scene) {
|
||||||
assertTrue(
|
assertTrue(
|
||||||
scene->flags & SCENE_FLAG_INITIALIZED,
|
(scene->flags & SCENE_FLAG_INITIALIZED) == 0,
|
||||||
"Scene not initialized"
|
"Scene should not yet be initialized"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user