RPG stuff
This commit is contained in:
@@ -51,6 +51,7 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||
|
||||
consolePrint("Engine initialized");
|
||||
sceneSet(SCENE_TYPE_OVERWORLD);
|
||||
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ typedef struct chunk_s {
|
||||
tile_t tiles[CHUNK_TILE_COUNT];
|
||||
|
||||
spritebatchsprite_t sprites[CHUNK_TILE_COUNT];
|
||||
color_t testColor;
|
||||
uint32_t spriteCount;
|
||||
|
||||
// uint8_t meshCount;
|
||||
|
||||
+133
-57
@@ -16,68 +16,86 @@ map_t MAP;
|
||||
|
||||
errorret_t mapInit() {
|
||||
memoryZero(&MAP, sizeof(map_t));
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t mapIsLoaded() {
|
||||
return MAP.filePath[0] != '\0';
|
||||
}
|
||||
|
||||
errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
||||
assertStrLenMin(path, 1, "Map file path cannot be empty");
|
||||
assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long");
|
||||
|
||||
if(stringCompare(MAP.filePath, path) == 0) {
|
||||
// Same map, no need to reload
|
||||
errorOk();
|
||||
}
|
||||
|
||||
chunkindex_t i;
|
||||
|
||||
// Unload all loaded chunks
|
||||
if(mapIsLoaded()) {
|
||||
for(i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
mapChunkUnload(&MAP.chunks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Store the map file path
|
||||
stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX);
|
||||
|
||||
// Determine directory path (it is dirname)
|
||||
stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX);
|
||||
char_t *last = stringFindLastChar(MAP.dirPath, '/');
|
||||
if(last == NULL) errorThrow("Invalid map file path");
|
||||
|
||||
// Store filename, sans extension
|
||||
stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX);
|
||||
*last = '\0'; // Terminate to get directory path
|
||||
|
||||
last = stringFindLastChar(MAP.fileName, '.');
|
||||
if(last == NULL) errorThrow("Map file name has no extension");
|
||||
*last = '\0'; // Terminate to remove extension
|
||||
|
||||
// Reset map position
|
||||
MAP.chunkPosition = position;
|
||||
|
||||
// Perform "initial load"
|
||||
i = 0;
|
||||
MAP.loaded = true;
|
||||
int32_t i = 0;
|
||||
for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||
for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
||||
for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
||||
chunk_t *chunk = &MAP.chunks[i];
|
||||
chunk->position.x = x + position.x;
|
||||
chunk->position.y = y + position.y;
|
||||
chunk->position.z = z + position.z;
|
||||
chunk->position.x = x + MAP.chunkPosition.x;
|
||||
chunk->position.y = y + MAP.chunkPosition.y;
|
||||
chunk->position.z = z + MAP.chunkPosition.z;
|
||||
MAP.chunkOrder[i] = chunk;
|
||||
errorChain(mapChunkLoad(chunk));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
bool_t mapIsLoaded() {
|
||||
return MAP.loaded;
|
||||
}
|
||||
|
||||
// errorret_t mapLoad(const char_t *path, const chunkpos_t position) {
|
||||
// assertStrLenMin(path, 1, "Map file path cannot be empty");
|
||||
// assertStrLenMax(path, MAP_FILE_PATH_MAX - 1, "Map file path too long");
|
||||
|
||||
// if(stringCompare(MAP.filePath, path) == 0) {
|
||||
// // Same map, no need to reload
|
||||
// errorOk();
|
||||
// }
|
||||
|
||||
// chunkindex_t i;
|
||||
|
||||
// // Unload all loaded chunks
|
||||
// if(mapIsLoaded()) {
|
||||
// for(i = 0; i < MAP_CHUNK_COUNT; i++) {
|
||||
// mapChunkUnload(&MAP.chunks[i]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// // Store the map file path
|
||||
// stringCopy(MAP.filePath, path, MAP_FILE_PATH_MAX);
|
||||
|
||||
// // Determine directory path (it is dirname)
|
||||
// stringCopy(MAP.dirPath, path, MAP_FILE_PATH_MAX);
|
||||
// char_t *last = stringFindLastChar(MAP.dirPath, '/');
|
||||
// if(last == NULL) errorThrow("Invalid map file path");
|
||||
|
||||
// // Store filename, sans extension
|
||||
// stringCopy(MAP.fileName, last + 1, MAP_FILE_PATH_MAX);
|
||||
// *last = '\0'; // Terminate to get directory path
|
||||
|
||||
// last = stringFindLastChar(MAP.fileName, '.');
|
||||
// if(last == NULL) errorThrow("Map file name has no extension");
|
||||
// *last = '\0'; // Terminate to remove extension
|
||||
|
||||
// // Reset map position
|
||||
// MAP.chunkPosition = position;
|
||||
|
||||
// // Perform "initial load"
|
||||
// i = 0;
|
||||
// for(chunkunit_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||
// for(chunkunit_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
||||
// for(chunkunit_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
||||
// chunk_t *chunk = &MAP.chunks[i];
|
||||
// chunk->position.x = x + position.x;
|
||||
// chunk->position.y = y + position.y;
|
||||
// chunk->position.z = z + position.z;
|
||||
// MAP.chunkOrder[i] = chunk;
|
||||
// errorChain(mapChunkLoad(chunk));
|
||||
// i++;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// errorOk();
|
||||
// }
|
||||
|
||||
errorret_t mapPositionSet(const chunkpos_t newPos) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
@@ -177,21 +195,79 @@ void mapChunkUnload(chunk_t* chunk) {
|
||||
entity->type = ENTITY_TYPE_NULL;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||
if(chunk->meshes[i].vertexCount == 0) continue;
|
||||
meshDispose(&chunk->meshes[i]);
|
||||
}
|
||||
// for(uint8_t i = 0; i < chunk->meshCount; i++) {
|
||||
// if(chunk->meshes[i].vertexCount == 0) continue;
|
||||
// meshDispose(&chunk->meshes[i]);
|
||||
// }
|
||||
}
|
||||
|
||||
errorret_t mapChunkLoad(chunk_t* chunk) {
|
||||
if(!mapIsLoaded()) errorThrow("No map loaded");
|
||||
|
||||
char_t buffer[64];
|
||||
|
||||
// TODO: Can probably move this to asset load logic?
|
||||
chunk->meshCount = 0;
|
||||
memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
||||
|
||||
color_t color = COLOR_WHITE;
|
||||
if(chunk->position.y % 2 == 0) {
|
||||
if(chunk->position.x % 2 == 0) {
|
||||
color = COLOR_BLACK;
|
||||
} else {
|
||||
color = COLOR_WHITE;
|
||||
}
|
||||
} else {
|
||||
if(chunk->position.x % 2 == 0) {
|
||||
color = COLOR_WHITE;
|
||||
} else {
|
||||
color = COLOR_BLACK;
|
||||
}
|
||||
}
|
||||
// if(chunk->position.x == 0 && chunk->position.y == 0 && chunk->position.z == 0) {
|
||||
// color = COLOR_RED;
|
||||
// }
|
||||
chunk->testColor = color;
|
||||
|
||||
memorySet(chunk->tiles, TILE_SHAPE_GROUND, sizeof(chunk->tiles));
|
||||
memoryZero(chunk->sprites, sizeof(chunk->sprites));
|
||||
memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||
chunk->spriteCount = 0;
|
||||
|
||||
if(chunk->position.z != 0) {
|
||||
errorOk();
|
||||
}
|
||||
|
||||
// Set Chunk sprites.
|
||||
uint32_t i = 0;
|
||||
vec3 spriteMin = {
|
||||
chunk->position.x * CHUNK_WIDTH,
|
||||
chunk->position.y * CHUNK_HEIGHT,
|
||||
chunk->position.z * CHUNK_DEPTH
|
||||
};
|
||||
for(uint8_t x = 0; x < CHUNK_WIDTH; x++) {
|
||||
for(uint8_t y = 0; y < CHUNK_HEIGHT; y++) {
|
||||
glm_vec3_copy(spriteMin, chunk->sprites[i].min);
|
||||
glm_vec3_add(
|
||||
chunk->sprites[i].min,
|
||||
(vec3){ x, y, 0 },
|
||||
chunk->sprites[i].min
|
||||
);
|
||||
|
||||
glm_vec3_copy(chunk->sprites[i].min, chunk->sprites[i].max);
|
||||
glm_vec3_add(
|
||||
chunk->sprites[i].max,
|
||||
(vec3){ 1, 1, 0 },
|
||||
chunk->sprites[i].max
|
||||
);
|
||||
|
||||
glm_vec2_copy((vec2){ 0, 0 }, chunk->sprites[i].uvMin);
|
||||
glm_vec2_copy((vec2){ 1, 1 }, chunk->sprites[i].uvMax);
|
||||
|
||||
chunk->spriteCount++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// char_t buffer[64];
|
||||
// TODO: Can probably move this to asset load logic?
|
||||
// chunk->meshCount = 0;
|
||||
// memoryZero(chunk->meshes, sizeof(chunk->meshes));
|
||||
// memorySet(chunk->entities, 0xFF, sizeof(chunk->entities));
|
||||
|
||||
// Load.
|
||||
errorOk();
|
||||
|
||||
@@ -11,9 +11,10 @@
|
||||
#define MAP_FILE_PATH_MAX 128
|
||||
|
||||
typedef struct map_s {
|
||||
char_t filePath[MAP_FILE_PATH_MAX];
|
||||
char_t dirPath[MAP_FILE_PATH_MAX];
|
||||
char_t fileName[MAP_FILE_PATH_MAX];
|
||||
// char_t filePath[MAP_FILE_PATH_MAX];
|
||||
// char_t dirPath[MAP_FILE_PATH_MAX];
|
||||
// char_t fileName[MAP_FILE_PATH_MAX];
|
||||
bool_t loaded;
|
||||
|
||||
chunk_t chunks[MAP_CHUNK_COUNT];
|
||||
chunk_t *chunkOrder[MAP_CHUNK_COUNT];
|
||||
@@ -43,10 +44,10 @@ bool_t mapIsLoaded();
|
||||
* @param position The initial chunk position.
|
||||
* @return An error code.
|
||||
*/
|
||||
errorret_t mapLoad(
|
||||
const char_t *path,
|
||||
const chunkpos_t position
|
||||
);
|
||||
// errorret_t mapLoad(
|
||||
// const char_t *path,
|
||||
// const chunkpos_t position
|
||||
// );
|
||||
|
||||
/**
|
||||
* Updates the map.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
typedef enum {
|
||||
TILE_SHAPE_NULL,
|
||||
|
||||
TILE_SHAPE_SOLID,
|
||||
TILE_SHAPE_GROUND,
|
||||
TILE_SHAPE_RAMP_NORTH,
|
||||
TILE_SHAPE_RAMP_SOUTH,
|
||||
TILE_SHAPE_RAMP_EAST,
|
||||
|
||||
+5
-3
@@ -26,14 +26,16 @@ errorret_t rpgInit(void) {
|
||||
rpgCameraInit();
|
||||
rpgTextboxInit();
|
||||
|
||||
// Init world
|
||||
errorChain(mapPositionSet((chunkpos_t){ 0, 0, 0 }));
|
||||
|
||||
// TEST: Create some entities.
|
||||
uint8_t entIndex = entityGetAvailable();
|
||||
assertTrue(entIndex != 0xFF, "No available entity slots!.");
|
||||
entity_t *ent = &ENTITIES[entIndex];
|
||||
entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||
// RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
||||
// RPG_CAMERA.followEntity.followEntityId = ent->id;
|
||||
ent->position.x = 2, ent->position.y = 2;
|
||||
RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
||||
RPG_CAMERA.followEntity.followEntityId = ent->id;
|
||||
|
||||
// All Good!
|
||||
errorOk();
|
||||
|
||||
+14
-20
@@ -11,44 +11,38 @@
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "assert/assert.h"
|
||||
|
||||
#include "display/screen/screen.h"
|
||||
|
||||
rpgcamera_t RPG_CAMERA;
|
||||
|
||||
void rpgCameraInit(void) {
|
||||
memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t));
|
||||
|
||||
}
|
||||
|
||||
errorret_t rpgCameraUpdate(void) {
|
||||
glm_lookat(
|
||||
(vec3){ 3, 3, 3 },
|
||||
(vec3){ 0, 0, 0 }, // center
|
||||
(vec3){ 0, 1, 0 }, // up
|
||||
RPG_CAMERA.eye
|
||||
);
|
||||
|
||||
if(!mapIsLoaded()) errorOk();
|
||||
chunkpos_t chunkPos;
|
||||
|
||||
worldpos_t rpgCameraGetPosition(void) {
|
||||
switch(RPG_CAMERA.mode) {
|
||||
case RPG_CAMERA_MODE_FREE:
|
||||
worldPosToChunkPos(&RPG_CAMERA.free, &chunkPos);
|
||||
break;
|
||||
return RPG_CAMERA.free;
|
||||
|
||||
case RPG_CAMERA_MODE_FOLLOW_ENTITY: {
|
||||
entity_t *entity = &ENTITIES[RPG_CAMERA.followEntity.followEntityId];
|
||||
if(entity->type == ENTITY_TYPE_NULL) {
|
||||
errorOk();
|
||||
return (worldpos_t){ 0, 0, 0 };
|
||||
}
|
||||
|
||||
// Update map position to match camera. By default map wants to know the
|
||||
// top left but we want to set the center, so we need to sub half map size
|
||||
worldPosToChunkPos(&entity->position, &chunkPos);
|
||||
break;
|
||||
return entity->position;
|
||||
}
|
||||
|
||||
default:
|
||||
assertUnreachable("Invalid RPG camera mode");
|
||||
}
|
||||
}
|
||||
|
||||
errorret_t rpgCameraUpdate(void) {
|
||||
if(!mapIsLoaded()) errorOk();
|
||||
|
||||
chunkpos_t chunkPos;
|
||||
worldpos_t worldPos = rpgCameraGetPosition();
|
||||
worldPosToChunkPos(&worldPos, &chunkPos);
|
||||
|
||||
errorChain(mapPositionSet((chunkpos_t){
|
||||
.x = chunkPos.x - (MAP_CHUNK_WIDTH / 2),
|
||||
|
||||
@@ -19,6 +19,7 @@ typedef struct {
|
||||
|
||||
union {
|
||||
worldpos_t free;
|
||||
|
||||
struct {
|
||||
uint8_t followEntityId;
|
||||
} followEntity;
|
||||
@@ -34,6 +35,13 @@ extern rpgcamera_t RPG_CAMERA;
|
||||
*/
|
||||
void rpgCameraInit(void);
|
||||
|
||||
/**
|
||||
* Gets the RPG camera's position.
|
||||
*
|
||||
* @return The RPG camera's position.
|
||||
*/
|
||||
worldpos_t rpgCameraGetPosition(void);
|
||||
|
||||
/**
|
||||
* Updates the RPG camera.
|
||||
*
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include "display/shader/shaderunlit.h"
|
||||
#include "display/spritebatch/spritebatch.h"
|
||||
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/rpgcamera.h"
|
||||
|
||||
errorret_t sceneOverworldInit(scenedata_t *sceneData) {
|
||||
@@ -39,38 +41,121 @@ errorret_t sceneOverworldRender(scenedata_t *sceneData) {
|
||||
|
||||
glm_mat4_identity(model);
|
||||
|
||||
glm_perspective(
|
||||
glm_rad(45),
|
||||
(float)SCREEN.width / (float)SCREEN.height,
|
||||
0.1f,
|
||||
100.0f,
|
||||
proj
|
||||
);
|
||||
|
||||
errorChain(shaderBind(&SHADER_UNLIT));
|
||||
errorChain(shaderSetTexture(&SHADER_UNLIT, SHADER_UNLIT_TEXTURE, &TEXTURE_TEST));
|
||||
errorChain(shaderSetColor(&SHADER_UNLIT, SHADER_UNLIT_COLOR, COLOR_WHITE));
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_MODEL, model));
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, RPG_CAMERA.eye));
|
||||
|
||||
// Camera projection
|
||||
float_t fov = glm_rad(45.0f);
|
||||
glm_perspective(
|
||||
fov,
|
||||
(float_t)SCREEN.width / (float_t)SCREEN.height,
|
||||
0.1f,
|
||||
100.0f,
|
||||
proj
|
||||
);
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_PROJECTION, proj));
|
||||
|
||||
// Camera Eye
|
||||
float_t pixelsPerUnit = 16.0f;
|
||||
float_t worldH = (float)SCREEN.height / pixelsPerUnit;
|
||||
float_t z = (worldH * 0.5f) / tanf(fov * 0.5f);
|
||||
worldpos_t worldPos = rpgCameraGetPosition();
|
||||
float_t offset = 16.0f;
|
||||
|
||||
vec3 worldPosVec = {
|
||||
worldPos.x,
|
||||
worldPos.y,
|
||||
worldPos.z
|
||||
};
|
||||
glm_vec3_add(worldPosVec, (vec3){ 0.5f, 0.5f, 0.5f }, worldPosVec);
|
||||
|
||||
glm_lookat(
|
||||
(vec3){
|
||||
worldPosVec[0],
|
||||
worldPosVec[1] + offset,
|
||||
worldPosVec[2] + z
|
||||
},
|
||||
worldPosVec,
|
||||
(vec3){ 0, -1, 0 }, // up
|
||||
RPG_CAMERA.eye
|
||||
);
|
||||
errorChain(shaderSetMatrix(&SHADER_UNLIT, SHADER_UNLIT_VIEW, RPG_CAMERA.eye));
|
||||
|
||||
// Chunk Data
|
||||
{
|
||||
uint8_t spriteCount = 1;
|
||||
spritebatchsprite_t sprites[spriteCount];
|
||||
shadermaterial_t chunkMaterial = {
|
||||
.unlit = {
|
||||
.color = COLOR_WHITE
|
||||
}
|
||||
};
|
||||
|
||||
glm_vec3_copy((vec3){ -0.5f, -0.5f, 0 }, sprites[0].min);
|
||||
glm_vec3_copy((vec3){ 0.5f, 0.5f, 0 }, sprites[0].max);
|
||||
glm_vec2_copy((vec2){ 0, 0 }, sprites[0].uvMin);
|
||||
glm_vec2_copy((vec2){ 1, 1 }, sprites[0].uvMax);
|
||||
uint32_t i = 0;
|
||||
for(uint8_t x = 0; x < MAP_CHUNK_WIDTH; x++) {
|
||||
for(uint8_t y = 0; y < MAP_CHUNK_HEIGHT; y++) {
|
||||
for(uint8_t z = 0; z < MAP_CHUNK_DEPTH; z++) {
|
||||
chunk_t *chunk = &MAP.chunks[i];
|
||||
if(chunk->spriteCount == 0) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
shadermaterial_t material;
|
||||
material.unlit.color = COLOR_WHITE;
|
||||
material.unlit.texture = &TEXTURE_TEST;
|
||||
chunkMaterial.unlit.color = chunk->testColor;
|
||||
|
||||
spriteBatchBuffer(
|
||||
chunk->sprites, chunk->spriteCount, &SHADER_UNLIT, chunkMaterial
|
||||
);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spriteBatchBuffer(sprites, spriteCount, &SHADER_UNLIT, material);
|
||||
spriteBatchFlush();
|
||||
}
|
||||
|
||||
// Entities
|
||||
{
|
||||
uint8_t spriteCount = 0;
|
||||
spritebatchsprite_t sprites[ENTITY_COUNT];
|
||||
for(uint8_t i = 0; i < ENTITY_COUNT; i++) {
|
||||
entity_t *ent = &ENTITIES[i];
|
||||
if(ent->type == ENTITY_TYPE_NULL) continue;
|
||||
|
||||
vec3 position = {
|
||||
ent->position.x,
|
||||
ent->position.y,
|
||||
((float_t)ent->position.z) + 0.01f
|
||||
};
|
||||
|
||||
glm_vec3_copy(position, sprites[spriteCount].min);
|
||||
glm_vec3_copy(position, sprites[spriteCount].max);
|
||||
glm_vec3_add(
|
||||
sprites[spriteCount].max,
|
||||
(vec3){ 1, 1, 0 },
|
||||
sprites[spriteCount].max
|
||||
);
|
||||
|
||||
glm_vec2_copy((vec2){ 0, 0 }, sprites[spriteCount].uvMin);
|
||||
glm_vec2_copy((vec2){ 1, 1 }, sprites[spriteCount].uvMax);
|
||||
|
||||
spriteCount++;
|
||||
}
|
||||
|
||||
if(spriteCount) {
|
||||
shadermaterial_t material = {
|
||||
.unlit = {
|
||||
.color = COLOR_CYAN,
|
||||
.texture = NULL
|
||||
}
|
||||
};
|
||||
// material.unlit.texture = &TEXTURE_TEST;
|
||||
spriteBatchBuffer(sprites, spriteCount, &SHADER_UNLIT, material);
|
||||
spriteBatchFlush();
|
||||
}
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user