This commit is contained in:
2024-10-03 20:09:10 -05:00
parent 2ff1a159bc
commit ad317da97e
303 changed files with 1613 additions and 21403 deletions

View File

@ -0,0 +1,10 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
add_subdirectory(entity)
add_subdirectory(world)
# Sources

View File

@ -0,0 +1,14 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
entity.c
entitydirection.c
player.c
)

View File

@ -0,0 +1,102 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entity.h"
#include "entitydirection.h"
#include "rpg/world/map.h"
#include "assert/assert.h"
void entityInit(
entity_t *entity,
const uint8_t type,
map_t *map
) {
assertNotNull(entity, "Entity cannot be NULL.");
assertNotNull(map, "Map cannot be NULL.");
memset(entity, 0, sizeof(entity_t));
entity->type = type;
entity->map = map;
switch(type) {
case ENTITY_TYPE_NULL:
assertUnreachable("Should not be initializing a NULL entity.");
break;
case ENTITY_TYPE_PLAYER:
playerInit(entity);
break;
case ENTITY_TYPE_NPC:
break;
default:
assertUnreachable("Unknown entity type.");
}
}
void entityUpdate(entity_t *entity) {
assertNotNull(entity, "Entity cannot be NULL.");
switch(entity->type) {
case ENTITY_TYPE_NULL:
assertUnreachable("Should not be updating a NULL entity.");
break;
case ENTITY_TYPE_PLAYER:
playerUpdate(entity);
break;
case ENTITY_TYPE_NPC:
break;
default:
assertUnreachable("Unknown entity type.");
}
}
void entityWalk(entity_t *entity, const uint8_t dir) {
assertNotNull(entity, "Entity cannot be NULL.");
uint16_t newX = entity->x, newY = entity->y;
entityDirectionOffsetAdd(dir, &newX, &newY);
// Update direction, this happens regardless of if the player can move
entity->direction = dir;
// Walking OOB?
if(newX >= entity->map->width || newY >= entity->map->height) {
return;
}
// Get tile at position
tile_t tileAtPosition = mapTileGetByPosition(
entity->map,
newX,
newY,
entity->layer
);
if(tileIsSolid(tileAtPosition)) return;
// Get entity at position
entity_t *entityAtPosition = mapEntityGetByPosition(
entity->map,
newX,
newY
);
if(entityAtPosition != NULL) return;
// Commit to move
entity->x = newX;
entity->y = newY;
}
void entityPositionSet(entity_t *entity, const uint16_t x, const uint16_t y) {
assertNotNull(entity, "Entity cannot be NULL.");
entity->x = x;
entity->y = y;
}

View File

@ -0,0 +1,64 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "player.h"
#define ENTITY_TYPE_NULL 0
#define ENTITY_TYPE_PLAYER 1
#define ENTITY_TYPE_NPC 2
typedef struct _map_t map_t;
typedef struct _entity_t {
map_t *map;
uint8_t type;
uint16_t x;
uint16_t y;
uint8_t layer;
uint8_t direction;
union {
player_t player;
};
} entity_t;
/**
* Initializes an entity.
*
* @param entity Entity to initialize.
* @param type Type of entity to initialize.
*/
void entityInit(
entity_t *entity,
const uint8_t type,
map_t *map
);
/**
* Updates an entity.
*
* @param entity Entity to update.
*/
void entityUpdate(entity_t *entity);
/**
* Moves an entity.
*
* @param entity Entity to move.
* @param dir Direction to move.
*/
void entityWalk(entity_t *entity, const uint8_t dir);
/**
* Sets the position of an entity. Performs an immediate move.
*
* @param entity Entity to set position of.
* @param x X position to set.
* @param y Y position to set.
*/
void entityPositionSet(entity_t *entity, const uint16_t x, const uint16_t y);

View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "entitydirection.h"
#include "assert/assert.h"
void entityDirectionOffsetGet(const uint8_t dir, uint16_t *x, uint16_t *y) {
switch(dir) {
case ENTITY_DIRECTION_SOUTH:
*x = 0;
*y = 1;
break;
case ENTITY_DIRECTION_NORTH:
*x = 0;
*y = -1;
break;
case ENTITY_DIRECTION_WEST:
*x = -1;
*y = 0;
break;
case ENTITY_DIRECTION_EAST:
*x = 1;
*y = 0;
break;
default:
assertUnreachable("Invalid entity direction.");
}
}
void entityDirectionOffsetAdd(const uint8_t dir, uint16_t *x, uint16_t *y) {
switch(dir) {
case ENTITY_DIRECTION_SOUTH:
*y += 1;
break;
case ENTITY_DIRECTION_NORTH:
*y -= 1;
break;
case ENTITY_DIRECTION_WEST:
*x -= 1;
break;
case ENTITY_DIRECTION_EAST:
*x += 1;
break;
default:
assertUnreachable("Invalid entity direction.");
}
}
uint8_t entityDirectionLookAt(
const uint16_t srcX, const uint16_t srcY,
const uint16_t trgX, const uint16_t trgY
) {
if(srcX < trgX) return ENTITY_DIRECTION_EAST;
if(srcX > trgX) return ENTITY_DIRECTION_WEST;
if(srcY < trgY) return ENTITY_DIRECTION_SOUTH;
if(srcY > trgY) return ENTITY_DIRECTION_NORTH;
return ENTITY_DIRECTION_SOUTH;
}

View File

@ -0,0 +1,46 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
#define ENTITY_DIRECTION_SOUTH 0
#define ENTITY_DIRECTION_NORTH 1
#define ENTITY_DIRECTION_WEST 2
#define ENTITY_DIRECTION_EAST 3
/**
* Returns the offset for a given direction.
*
* @param dir Direction to get offset for.
* @param x Pointer to store x offset.
* @param y Pointer to store y offset.
*/
void entityDirectionOffsetGet(const uint8_t dir, uint16_t *x, uint16_t *y);
/**
* Adds the offset for a given direction to the given x and y.
*
* @param dir Direction to get offset for.
* @param x Pointer to add x offset to.
* @param y Pointer to add y offset to.
*/
void entityDirectionOffsetAdd(const uint8_t dir, uint16_t *x, uint16_t *y);
/**
* Returns the direction to look at from one point to another.
*
* @param srcX Source X position.
* @param srcY Source Y position.
* @param trgX Target X position.
* @param trgY Target Y position.
* @return Direction to look at.
*/
uint8_t entityDirectionLookAt(
const uint16_t srcX, const uint16_t srcY,
const uint16_t trgX, const uint16_t trgY
);

View File

@ -0,0 +1,47 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "player.h"
#include "entity.h"
#include "entitydirection.h"
#include "rpg/world/map.h"
#include "input.h"
#include "assert/assert.h"
void playerInit(entity_t *entity) {
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity is not a player.");
}
void playerUpdate(entity_t *entity) {
assertTrue(entity->type == ENTITY_TYPE_PLAYER, "Entity is not a player.");
if(inputIsDown(INPUT_BIND_DOWN)) {
return entityWalk(entity, ENTITY_DIRECTION_SOUTH);
} else if(inputIsDown(INPUT_BIND_UP)) {
return entityWalk(entity, ENTITY_DIRECTION_NORTH);
} else if(inputIsDown(INPUT_BIND_LEFT)) {
return entityWalk(entity, ENTITY_DIRECTION_WEST);
} else if(inputIsDown(INPUT_BIND_RIGHT)) {
return entityWalk(entity, ENTITY_DIRECTION_EAST);
}
if(inputIsDown(INPUT_BIND_ACCEPT)) {
// Check what the player is trying to interact with
uint16_t x = entity->x, y = entity->y;
entityDirectionOffsetAdd(entity->direction, &x, &y);
entity_t *target = mapEntityGetByPosition(entity->map, x, y);
if(target) {
// Interact with the target
target->direction = entityDirectionLookAt(
target->x, target->y,
entity->x, entity->y
);
return;
}
}
}

View File

@ -0,0 +1,29 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
typedef struct _entity_t entity_t;
typedef struct {
uint8_t mana;
} player_t;
/**
* Initializes a player entity.
*
* @param entity Player entity to initialize.
*/
void playerInit(entity_t *entity);
/**
* Updates a player entity.
*
* @param entity Player entity to update.
*/
void playerUpdate(entity_t *entity);

View File

@ -0,0 +1,13 @@
# Copyright (c) 2024 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Subdirs
# Sources
target_sources(${DAWN_TARGET_NAME}
PRIVATE
tile.c
map.c
)

128
src/dawn/rpg/world/map.c Normal file
View File

@ -0,0 +1,128 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "map.h"
#include "assert/assert.h"
void mapInit(
map_t *map,
const uint16_t width,
const uint16_t height,
const uint8_t layers
) {
assertNotNull(map, "Map cannot be NULL.");
assertTrue(
width > 0,
"Map width must be greater than 0."
);
assertTrue(
width < MAP_WIDTH_MAX,
"Map width must be less than or equal to MAP_WIDTH_MAX."
);
assertTrue(
height > 0,
"Map height must be greater than 0."
);
assertTrue(
height < MAP_HEIGHT_MAX,
"Map height must be less than or equal to MAP_HEIGHT_MAX."
);
assertTrue(
layers > 0,
"Map layers must be greater than 0."
);
assertTrue(
layers < MAP_LAYERS_MAX,
"Map layers must be less than or equal to MAP_LAYERS_MAX."
);
memset(map, 0, sizeof(map));
map->width = width;
map->height = height;
map->layers = layers;
}
void mapUpdate(map_t *map) {
for(uint8_t i = 0; i < map->entityCount; i++) {
entity_t *entity = &map->entities[i];
entityUpdate(entity);
}
}
entity_t * mapEntityAdd(map_t *map) {
assertTrue(
map->entityCount < MAP_ENTITIES_MAX,
"Cannot add any more entities to map."
);
entity_t *entity = &map->entities[map->entityCount];
map->entityCount++;
return entity;
}
entity_t * mapEntityGetByPosition(
map_t *map,
const uint16_t x,
const uint16_t y
) {
if(x >= map->width || y >= map->height) return NULL;
for(uint8_t i = 0; i < map->entityCount; i++) {
entity_t *entity = &map->entities[i];
if(entity->x == x && entity->y == y) {
return entity;
}
}
return NULL;
}
tile_t mapTileGetByPosition(
const map_t *map,
const uint16_t x,
const uint16_t y,
const uint8_t layer
) {
assertTrue(
x < map->width,
"X position must be less than map width."
);
assertTrue(
y < map->height,
"Y position must be less than map height."
);
assertTrue(
layer < map->layers,
"Layer must be less than map layers."
);
return map->tiles[
(layer * map->width * map->height) +
(y * map->width) +
x
];
}
void mapTilesSet(
map_t *map,
const tile_t tiles[],
const uint8_t layer
) {
assertNotNull(map, "Map cannot be NULL.");
assertNotNull(tiles, "Tiles cannot be NULL.");
assertTrue(
layer < map->layers,
"Layer must be less than map layers."
);
memcpy(
map->tiles + (layer * map->width * map->height),
tiles,
map->width * map->height * sizeof(tile_t)
);
}

98
src/dawn/rpg/world/map.h Normal file
View File

@ -0,0 +1,98 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "tile.h"
#include "rpg/entity/entity.h"
#define MAP_WIDTH_MAX 2048
#define MAP_HEIGHT_MAX 2048
#define MAP_LAYERS_MAX 4
#define MAP_ENTITIES_MAX 256
typedef struct _map_t {
tile_t tiles[MAP_WIDTH_MAX * MAP_HEIGHT_MAX * MAP_LAYERS_MAX];
uint16_t width;
uint16_t height;
uint8_t layers;
entity_t entities[MAP_ENTITIES_MAX];
uint8_t entityCount;
} map_t;
/**
* Initializes a map.
*
* @param map Map to initialize.
* @param width Width of the map.
* @param height Height of the map.
* @param layers Number of layers in the map.
*/
void mapInit(
map_t *map,
const uint16_t width,
const uint16_t height,
const uint8_t layers
);
/**
* Updates the map and all entities on it.
*
* @param map Map to update.
*/
void mapUpdate(map_t *map);
/**
* Adds an entity to the map.
*
* @param map Map to add the entity to.
* @param entity Entity to add to the map.
*/
entity_t * mapEntityAdd(map_t *map);
/**
* Gets the entity at the specified position.
*
* @param map Map to get the entity from.
* @param x X position of the entity.
* @param y Y position of the entity.
* @return Entity at the specified position, or NULL if no entity is there.
*/
entity_t * mapEntityGetByPosition(
map_t *map,
const uint16_t x,
const uint16_t y
);
/**
* Gets the tile at the specified position.
*
* @param map Map to get the tile from.
* @param x X position of the tile.
* @param y Y position of the tile.
* @param layer Layer of the tile.
* @return Tile at the specified position.
*/
tile_t mapTileGetByPosition(
const map_t *map,
const uint16_t x,
const uint16_t y,
const uint8_t layer
);
/**
* Quickly set an entire layer of tiles at once.
*
* @param map Map to set the tiles on.
* @param ids Array of tiles to set.
* @param layer Layer to set the tiles on.
*/
void mapTilesSet(
map_t *map,
const tile_t tiles[],
const uint8_t layer
);

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/world/map.h"
#include "assert/assert.h"
void testMapInit(map_t *map) {
mapInit(map, 20, 20, 1);
entity_t *player = mapEntityAdd(map);
entityInit(player, ENTITY_TYPE_PLAYER, map);
entityPositionSet(player, 5, 5);
entity_t *npc = mapEntityAdd(map);
entityInit(npc, ENTITY_TYPE_NPC, map);
entityPositionSet(npc, 10, 10);
tile_t tiles[42 * 42];
memset(tiles, 0, sizeof(tiles));
tiles[0].id = TILE_ID_GRASS;
tiles[1].id = TILE_ID_GRASS;
tiles[2].id = TILE_ID_GRASS;
tiles[3].id = TILE_ID_GRASS;
tiles[4].id = TILE_ID_GRASS;
tiles[5].id = TILE_ID_GRASS;
tiles[6].id = TILE_ID_GRASS;
tiles[7].id = TILE_ID_GRASS;
tiles[8].id = TILE_ID_GRASS;
tiles[9].id = TILE_ID_GRASS;
tiles[10].id = TILE_ID_GRASS;
tiles[11].id = TILE_ID_WATER;
tiles[12].id = TILE_ID_WATER;
tiles[13].id = TILE_ID_WATER;
tiles[14].id = TILE_ID_WATER;
tiles[15].id = TILE_ID_WATER;
tiles[16].id = TILE_ID_GRASS;
tiles[17].id = TILE_ID_GRASS;
tiles[18].id = TILE_ID_GRASS;
tiles[19].id = TILE_ID_GRASS;
tiles[20].id = TILE_ID_GRASS;
tiles[21].id = TILE_ID_GRASS;
tiles[22].id = TILE_ID_GRASS;
tiles[23].id = TILE_ID_GRASS;
tiles[24].id = TILE_ID_GRASS;
tiles[25].id = TILE_ID_GRASS;
tiles[26].id = TILE_ID_GRASS;
tiles[27].id = TILE_ID_GRASS;
tiles[28].id = TILE_ID_GRASS;
tiles[29].id = TILE_ID_GRASS;
tiles[30].id = TILE_ID_WATER;
tiles[31].id = TILE_ID_WATER;
tiles[32].id = TILE_ID_WATER;
tiles[33].id = TILE_ID_WATER;
tiles[34].id = TILE_ID_WATER;
tiles[35].id = TILE_ID_WATER;
tiles[36].id = TILE_ID_GRASS;
tiles[37].id = TILE_ID_GRASS;
tiles[38].id = TILE_ID_GRASS;
tiles[39].id = TILE_ID_GRASS;
mapTilesSet(map, tiles, 0);
}

19
src/dawn/rpg/world/tile.c Normal file
View File

@ -0,0 +1,19 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "tile.h"
bool_t tileIsSolid(const tile_t tile) {
switch(tile.id) {
case TILE_ID_WATER:
return true;
default:
return false;
}
return false;
}

25
src/dawn/rpg/world/tile.h Normal file
View File

@ -0,0 +1,25 @@
/**
* Copyright (c) 2024 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawn.h"
#define TILE_ID_NULL 0
#define TILE_ID_GRASS 1
#define TILE_ID_WATER 2
typedef struct {
uint8_t id;
} tile_t;
/**
* Returns whether or not the tile is solid.
*
* @param tile Tile to check.
* @return True if the tile is solid, false otherwise.
*/
bool_t tileIsSolid(const tile_t tile);