prog
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
rpg.c
|
rpg.c
|
||||||
|
rpgcamera.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
@@ -24,6 +24,7 @@ void entityInit(entity_t *entity, const entitytype_t type) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
memoryZero(entity, sizeof(entity_t));
|
memoryZero(entity, sizeof(entity_t));
|
||||||
|
entity->id = (uint8_t)(entity - ENTITIES);
|
||||||
entity->type = type;
|
entity->type = type;
|
||||||
|
|
||||||
// Init. I did use a callback struct but it was not flexible enough.
|
// Init. I did use a callback struct but it was not flexible enough.
|
||||||
@@ -54,7 +55,7 @@ void entityUpdate(entity_t *entity) {
|
|||||||
for(uint8_t i = 0; i < WORLD_DIMENSIONS; i++) {
|
for(uint8_t i = 0; i < WORLD_DIMENSIONS; i++) {
|
||||||
if(entity->velocity[i] == 0) continue;
|
if(entity->velocity[i] == 0) continue;
|
||||||
|
|
||||||
worldChunkPosAdd(&entity->position[i], entity->velocity[i]);
|
worldPosAddSubtile(&entity->position[i], entity->velocity[i]);
|
||||||
|
|
||||||
// Friction
|
// Friction
|
||||||
worldsubtile_t v = entity->velocity[i];
|
worldsubtile_t v = entity->velocity[i];
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#include "physics/physics.h"
|
#include "physics/physics.h"
|
||||||
#include "rpg/world/worldunit.h"
|
#include "rpg/world/worldunit.h"
|
||||||
|
|
||||||
#define ENTITY_FRICTION 1
|
#define ENTITY_FRICTION 2
|
||||||
#define ENTITY_MIN_VELOCITY 1
|
#define ENTITY_MIN_VELOCITY 1
|
||||||
#define ENTITY_COUNT 256
|
#define ENTITY_COUNT 256
|
||||||
|
|
||||||
@@ -27,9 +27,10 @@ typedef enum {
|
|||||||
} entitytype_t;
|
} entitytype_t;
|
||||||
|
|
||||||
typedef struct entity_s {
|
typedef struct entity_s {
|
||||||
|
uint8_t id;
|
||||||
entitytype_t type;
|
entitytype_t type;
|
||||||
direction_t direction;
|
direction_t direction;
|
||||||
worldchunkpos_t position[WORLD_DIMENSIONS];
|
worldpos_t position[WORLD_DIMENSIONS];
|
||||||
worldsubtile_t velocity[WORLD_DIMENSIONS];
|
worldsubtile_t velocity[WORLD_DIMENSIONS];
|
||||||
|
|
||||||
union {
|
union {
|
||||||
|
@@ -9,6 +9,8 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "input/input.h"
|
#include "input/input.h"
|
||||||
#include "display/tileset/tileset_entities.h"
|
#include "display/tileset/tileset_entities.h"
|
||||||
|
#include "rpg/rpgcamera.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
void playerInit(entity_t *entity) {
|
void playerInit(entity_t *entity) {
|
||||||
assertNotNull(entity, "Entity pointer cannot be NULL");
|
assertNotNull(entity, "Entity pointer cannot be NULL");
|
||||||
@@ -20,13 +22,13 @@ void playerMovement(entity_t *entity) {
|
|||||||
// Get movement angle as 0-> normalized vector.
|
// Get movement angle as 0-> normalized vector.
|
||||||
vec2 dir = {
|
vec2 dir = {
|
||||||
inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT),
|
inputAxis(INPUT_ACTION_LEFT, INPUT_ACTION_RIGHT),
|
||||||
inputAxis(INPUT_ACTION_DOWN, INPUT_ACTION_UP)
|
inputAxis(INPUT_ACTION_UP, INPUT_ACTION_DOWN)
|
||||||
};
|
};
|
||||||
if(dir[0] == 0 && dir[1] == 0) return;
|
if(dir[0] == 0 && dir[1] == 0) return;
|
||||||
glm_vec2_normalize(dir);
|
glm_vec2_normalize(dir);
|
||||||
|
|
||||||
entity->velocity[0] += (worldsubtile_t)(PLAYER_SPEED * dir[0]);
|
entity->velocity[0] += (worldsubtile_t)((float_t)PLAYER_SPEED * dir[0]);
|
||||||
entity->velocity[1] += (worldsubtile_t)(PLAYER_SPEED * dir[1]);
|
entity->velocity[1] += (worldsubtile_t)((float_t)PLAYER_SPEED * dir[1]);
|
||||||
|
|
||||||
// Update direction.
|
// Update direction.
|
||||||
if(dir[0] > 0) {
|
if(dir[0] > 0) {
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
#define PLAYER_SPEED 3
|
#define PLAYER_SPEED 4
|
||||||
#define PLAYER_INTERACTION_RANGE 1.0f
|
#define PLAYER_INTERACTION_RANGE 1.0f
|
||||||
#define PLAYER_INTERACTION_SIZE 0.5f
|
#define PLAYER_INTERACTION_SIZE 0.5f
|
||||||
|
|
||||||
|
@@ -8,14 +8,24 @@
|
|||||||
#include "rpg.h"
|
#include "rpg.h"
|
||||||
#include "entity/entity.h"
|
#include "entity/entity.h"
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
|
#include "rpgcamera.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
errorret_t rpgInit(void) {
|
errorret_t rpgInit(void) {
|
||||||
// TEST
|
memoryZero(ENTITIES, sizeof(ENTITIES));
|
||||||
entityInit(&ENTITIES[0], ENTITY_TYPE_PLAYER);
|
|
||||||
// ENTITIES[0].position[0].tile = 2;
|
rpgCameraInit();
|
||||||
// ENTITIES[0].position[0].subtile = 8;
|
|
||||||
// ENTITIES[0].position[1].tile = 3;
|
entity_t *ent;
|
||||||
// ENTITIES[0].position[1].subtile = 12;
|
ent = &ENTITIES[0];
|
||||||
|
entityInit(ent, ENTITY_TYPE_PLAYER);
|
||||||
|
RPG_CAMERA.mode = RPG_CAMERA_MODE_FOLLOW_ENTITY;
|
||||||
|
RPG_CAMERA.followEntity.followEntityId = ent->id;
|
||||||
|
ent->position[0].tile = 32, ent->position[1].tile = 32;
|
||||||
|
|
||||||
|
ent = &ENTITIES[1];
|
||||||
|
entityInit(ent, ENTITY_TYPE_NPC);
|
||||||
|
ent->position[0].tile = 40, ent->position[1].tile = 32;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
@@ -28,6 +38,8 @@ void rpgUpdate(void) {
|
|||||||
if(ent->type == ENTITY_TYPE_NULL) continue;
|
if(ent->type == ENTITY_TYPE_NULL) continue;
|
||||||
entityUpdate(ent);
|
entityUpdate(ent);
|
||||||
} while(++ent < &ENTITIES[ENTITY_COUNT]);
|
} while(++ent < &ENTITIES[ENTITY_COUNT]);
|
||||||
|
|
||||||
|
rpgCameraUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpgDispose(void) {
|
void rpgDispose(void) {
|
||||||
|
34
src/rpg/rpgcamera.c
Normal file
34
src/rpg/rpgcamera.c
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "rpgcamera.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "rpg/entity/entity.h"
|
||||||
|
|
||||||
|
rpgcamera_t RPG_CAMERA = {
|
||||||
|
.position = { 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
void rpgCameraInit(void) {
|
||||||
|
memoryZero(&RPG_CAMERA, sizeof(rpgcamera_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpgCameraUpdate(void) {
|
||||||
|
switch(RPG_CAMERA.mode) {
|
||||||
|
case RPG_CAMERA_MODE_FOLLOW_ENTITY:
|
||||||
|
if(RPG_CAMERA.followEntity.followEntityId >= ENTITY_COUNT) break;
|
||||||
|
entity_t *ent = &ENTITIES[RPG_CAMERA.followEntity.followEntityId];
|
||||||
|
if(ent->type == ENTITY_TYPE_NULL) break;
|
||||||
|
memoryCopy(
|
||||||
|
&RPG_CAMERA.position, ent->position, sizeof(RPG_CAMERA.position)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
37
src/rpg/rpgcamera.h
Normal file
37
src/rpg/rpgcamera.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 "world/worldunit.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
RPG_CAMERA_MODE_FREE,
|
||||||
|
RPG_CAMERA_MODE_FOLLOW_ENTITY,
|
||||||
|
} rpgcameramode_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
worldpos_t position[WORLD_DIMENSIONS];
|
||||||
|
rpgcameramode_t mode;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
uint8_t followEntityId;
|
||||||
|
} followEntity;
|
||||||
|
};
|
||||||
|
} rpgcamera_t;
|
||||||
|
|
||||||
|
extern rpgcamera_t RPG_CAMERA;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the RPG camera.
|
||||||
|
*/
|
||||||
|
void rpgCameraInit(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the RPG camera.
|
||||||
|
*/
|
||||||
|
void rpgCameraUpdate(void);
|
@@ -8,7 +8,7 @@
|
|||||||
#include "worldunit.h"
|
#include "worldunit.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
|
||||||
void worldChunkPosAdd(worldchunkpos_t *pos, worldsubtile_t amt) {
|
void worldChunkPosAdd(worldchunkpos_t *pos, const worldsubtile_t amt) {
|
||||||
assertNotNull(pos, "Position pointer cannot be NULL");
|
assertNotNull(pos, "Position pointer cannot be NULL");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -29,12 +29,34 @@ void worldChunkPosAdd(worldchunkpos_t *pos, worldsubtile_t amt) {
|
|||||||
pos->tile = (uint8_t)(pos->tile + (uint8_t)tileCarry);
|
pos->tile = (uint8_t)(pos->tile + (uint8_t)tileCarry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void worldPosAddSubtile(worldpos_t *pos, const worldsubtile_t amt) {
|
||||||
|
assertNotNull(pos, "Position pointer cannot be NULL");
|
||||||
|
|
||||||
|
// Same as worldChunkPosAdd but with chunk handling.
|
||||||
|
int32_t shiftedTotal = (int32_t)pos->subtile + (int32_t)amt + 128;
|
||||||
|
int32_t tileCarry = shiftedTotal >> 8; // divide by 256
|
||||||
|
int32_t wrappedSubtile = shiftedTotal - (tileCarry << 8);
|
||||||
|
pos->subtile = (int8_t)(wrappedSubtile - 128);
|
||||||
|
int32_t newTile = (int32_t)pos->tile + (int32_t)tileCarry;
|
||||||
|
int32_t chunkCarry = newTile / WORLD_CHUNK_SIZE;
|
||||||
|
pos->tile = (uint8_t)(newTile % WORLD_CHUNK_SIZE);
|
||||||
|
pos->chunk = (uint8_t)(pos->chunk + (uint8_t)chunkCarry);
|
||||||
|
}
|
||||||
|
|
||||||
float_t worldChunkPosToF32(worldchunkpos_t pos, const uint8_t tileSize) {
|
float_t worldChunkPosToF32(const worldchunkpos_t pos, const uint8_t tileSize) {
|
||||||
const float scaleFactor = (float)tileSize * (1.0f / 256.0f);
|
const float_t scaleFactor = (float_t)tileSize * (1.0f / 256.0f);
|
||||||
return (
|
return (
|
||||||
(float)pos.tile * (float)tileSize + ((float)pos.subtile + 128.0f) *
|
(float_t)pos.tile * (float_t)tileSize + ((float_t)pos.subtile + 128.0f) *
|
||||||
scaleFactor
|
scaleFactor
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
float_t worldPosToF32(const worldpos_t pos, const uint8_t tileSize) {
|
||||||
|
const float_t scaleFactor = (float_t)tileSize * (1.0f / 256.0f);
|
||||||
|
const float_t chunkFactor = WORLD_CHUNK_SIZE * (float_t)tileSize;
|
||||||
|
return (
|
||||||
|
(float_t)pos.chunk * chunkFactor +
|
||||||
|
(float_t)pos.tile * (float_t)tileSize +
|
||||||
|
((float_t)pos.subtile + 128.0f) * scaleFactor
|
||||||
|
);
|
||||||
}
|
}
|
@@ -11,6 +11,7 @@
|
|||||||
#define WORLD_DIMENSIONS 3
|
#define WORLD_DIMENSIONS 3
|
||||||
#define WORLD_SUBTITLE_MIN -128
|
#define WORLD_SUBTITLE_MIN -128
|
||||||
#define WORLD_SUBTITLE_MAX 127
|
#define WORLD_SUBTITLE_MAX 127
|
||||||
|
#define WORLD_CHUNK_SIZE 256 // Tiles per axis per chunk.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Position in SUBTILE space in a world, each unit represents a single subtile.
|
* Position in SUBTILE space in a world, each unit represents a single subtile.
|
||||||
@@ -67,10 +68,16 @@ typedef struct worldpos_s {
|
|||||||
* @param pos Pointer to the world chunk position to modify.
|
* @param pos Pointer to the world chunk position to modify.
|
||||||
* @param amt The amount of subtiles to add (can be negative).
|
* @param amt The amount of subtiles to add (can be negative).
|
||||||
*/
|
*/
|
||||||
void worldChunkPosAdd(
|
void worldChunkPosAdd(worldchunkpos_t *pos, const worldsubtile_t amt);
|
||||||
worldchunkpos_t *pos,
|
|
||||||
const worldsubtile_t amt
|
/**
|
||||||
);
|
* Adds a number of subtiles to a world position, rolling over into tiles and
|
||||||
|
* chunks as necessary.
|
||||||
|
*
|
||||||
|
* @param pos Pointer to the world position to modify.
|
||||||
|
* @param amt The amount of subtiles to add (can be negative).
|
||||||
|
*/
|
||||||
|
void worldPosAddSubtile(worldpos_t *pos, const worldsubtile_t amt);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a world chunk position to a floating point number, given the tile
|
* Converts a world chunk position to a floating point number, given the tile
|
||||||
@@ -80,7 +87,14 @@ void worldChunkPosAdd(
|
|||||||
* @param tileSize The size of a tile in pixels.
|
* @param tileSize The size of a tile in pixels.
|
||||||
* @return The position as a floating point number.
|
* @return The position as a floating point number.
|
||||||
*/
|
*/
|
||||||
float_t worldChunkPosToF32(
|
float_t worldChunkPosToF32(const worldchunkpos_t pos, const uint8_t tileSize);
|
||||||
const worldchunkpos_t pos,
|
|
||||||
const uint8_t tileSize
|
/**
|
||||||
);
|
* Converts a world position to a floating point number, given the tile size
|
||||||
|
* in pixels.
|
||||||
|
*
|
||||||
|
* @param pos Pointer to the world position to convert.
|
||||||
|
* @param tileSize The size of a tile in pixels.
|
||||||
|
* @return The position as a floating point number.
|
||||||
|
*/
|
||||||
|
float_t worldPosToF32(const worldpos_t pos, const uint8_t tileSize);
|
@@ -11,9 +11,9 @@
|
|||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "rpg/entity/entity.h"
|
#include "rpg/entity/entity.h"
|
||||||
#include "display/screen.h"
|
#include "display/screen.h"
|
||||||
|
#include "rpg/rpgcamera.h"
|
||||||
|
|
||||||
#define TILE_WIDTH 8
|
#define TILE_SIZE 8
|
||||||
#define TILE_HEIGHT TILE_WIDTH
|
|
||||||
|
|
||||||
errorret_t sceneMapInit(scenedata_t *data) {
|
errorret_t sceneMapInit(scenedata_t *data) {
|
||||||
cameraInitPerspective(&data->sceneMap.camera);
|
cameraInitPerspective(&data->sceneMap.camera);
|
||||||
@@ -31,6 +31,12 @@ void sceneMapRender(scenedata_t *data) {
|
|||||||
data->sceneMap.camera.perspective.fov / 2.0f
|
data->sceneMap.camera.perspective.fov / 2.0f
|
||||||
) * ((float_t)SCREEN.height / 2.0f);
|
) * ((float_t)SCREEN.height / 2.0f);
|
||||||
|
|
||||||
|
for(uint8_t i = 0; i < WORLD_DIMENSIONS; i++) {
|
||||||
|
data->sceneMap.camera.lookat.target[i] = worldPosToF32(
|
||||||
|
RPG_CAMERA.position[i], TILE_SIZE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
glm_vec3_copy((vec3){
|
glm_vec3_copy((vec3){
|
||||||
data->sceneMap.camera.lookat.target[0],
|
data->sceneMap.camera.lookat.target[0],
|
||||||
data->sceneMap.camera.lookat.target[1] + camOffset,
|
data->sceneMap.camera.lookat.target[1] + camOffset,
|
||||||
@@ -55,15 +61,15 @@ void sceneMapRenderEntity(const entity_t *entity) {
|
|||||||
|
|
||||||
if(entity->type == ENTITY_TYPE_NULL) return;
|
if(entity->type == ENTITY_TYPE_NULL) return;
|
||||||
|
|
||||||
float_t x = worldChunkPosToF32(entity->position[0], TILE_WIDTH);
|
float_t x = worldPosToF32(entity->position[0], TILE_SIZE);
|
||||||
float_t y = worldChunkPosToF32(entity->position[1], TILE_HEIGHT);
|
float_t y = worldPosToF32(entity->position[1], TILE_SIZE);
|
||||||
x -= TILE_WIDTH * 0.5f;
|
x -= TILE_SIZE * 0.5f;
|
||||||
y -= TILE_HEIGHT * 0.5f;
|
y -= TILE_SIZE * 0.5f;
|
||||||
|
|
||||||
spriteBatchPush(
|
spriteBatchPush(
|
||||||
NULL,
|
NULL,
|
||||||
x, y,
|
x, y,
|
||||||
x + TILE_WIDTH, y + TILE_HEIGHT,
|
x + TILE_SIZE, y + TILE_SIZE,
|
||||||
COLOR_RED,
|
COLOR_RED,
|
||||||
0.0f, 0.0f,
|
0.0f, 0.0f,
|
||||||
1.0f, 1.0f
|
1.0f, 1.0f
|
||||||
|
Reference in New Issue
Block a user