Maze complete v1

This commit is contained in:
Carlos Sanchez 2024-08-23 23:33:15 -04:00
parent 52daa83f2f
commit 0fdfc7e4c2
4 changed files with 124 additions and 19 deletions

12
ecs2.h
View File

@ -59,6 +59,16 @@ typedef int ecs_eid;
ecs_cid _realcomps = ECS_SELFFLAG | _comps; \ ecs_cid _realcomps = ECS_SELFFLAG | _comps; \
return (_ecs->entities[_eid] & _realcomps) == _realcomps; \ return (_ecs->entities[_eid] & _realcomps) == _realcomps; \
} \ } \
/* fill given list with eids of entities that match. careful with size */ \
static int name##_query(name *_ecs, ecs_cid _comps, ecs_eid *out) { \
int count = 0; \
for (int i = 0; i < ECS_MAXENTITIES; i++) { \
if (name##_match(_ecs, i, _comps)) { \
out[count++] = i; \
} \
} \
return count; \
} \
/* Calculate the eid from a double ecs pointer. Useful to get eid in sys */ \ /* Calculate the eid from a double ecs pointer. Useful to get eid in sys */ \
static ecs_eid name##_eid(name **_ecs) { \ static ecs_eid name##_eid(name **_ecs) { \
return (ecs_eid)(_ecs - (*_ecs)->c_##name); \ return (ecs_eid)(_ecs - (*_ecs)->c_##name); \
@ -68,6 +78,8 @@ typedef int ecs_eid;
// Create an ECS component within an ECS struct // Create an ECS component within an ECS struct
#define ECS_COMPONENT(type) type c_##type[ECS_MAXENTITIES]; #define ECS_COMPONENT(type) type c_##type[ECS_MAXENTITIES];
#define ECS_GETCOMPONENT(_ecs, eid, type) (_ecs)->c_##type[eid]
// Define the CIDs necessary to access a component (each component MUST // Define the CIDs necessary to access a component (each component MUST
// have a unique id and I can't do that inside a macro without requiring // have a unique id and I can't do that inside a macro without requiring
// extensions) // extensions)

@ -1 +1 @@
Subproject commit 917dfe41aa118cefe36779c9bba7957160cc52e4 Subproject commit b6347c5360b84079a50d943d4b1fe8e0edd946b8

112
maze.c
View File

@ -48,7 +48,7 @@
#define PRINTMAZE #define PRINTMAZE
// Max amount of flip polys to generate in maze. actual amount can be lower, // Max amount of flip polys to generate in maze. actual amount can be lower,
// but there will always at least be 1 // but there will always at least be 1
#define MAXFLIPPOLYS 17 #define MAXFLIPPOLYS 6
// Min space between flip polys // Min space between flip polys
#define FLIPPOLYBUFFER 3 #define FLIPPOLYBUFFER 3
@ -58,6 +58,8 @@
#define MAZEVISIT 4 #define MAZEVISIT 4
#define MAZEFLIP 8 #define MAZEFLIP 8
#define MAZETYPEFLIP 1
// When you rightshift these values, you "turn right". // When you rightshift these values, you "turn right".
// NOTE: north in this case is "towards the screen" because it moves in the // NOTE: north in this case is "towards the screen" because it moves in the
// positive direction. In this case, it's actually wound in the opposite // positive direction. In this case, it's actually wound in the opposite
@ -84,7 +86,7 @@ const char POLYNAMES[NUMPOLYS][20] = {"tetrahedron"};
float ditherstart = -1; float ditherstart = -1;
float ditherend = 8; float ditherend = 8;
float fov = 90.0; float fov = 90.0;
float minlight = 0.25; float minlight = 0.15;
float speed = 1.0; float speed = 1.0;
int fps = 45; int fps = 45;
uint16_t sky = 0xF000; uint16_t sky = 0xF000;
@ -276,7 +278,13 @@ void create_flippoly(struct vec2i mazepos, haloo3d_easyinstancer *ins,
(mazepos.y + 0.5) * world->state->cellsize); (mazepos.y + 0.5) * world->state->cellsize);
ecs_eid id = mecs_newentity(ecs, 0); ecs_eid id = mecs_newentity(ecs, 0);
mallocordie(poly->lighting, sizeof(struct vec3)); mallocordie(poly->lighting, sizeof(struct vec3));
// vec3(poly->lighting->v, 0, 0, -1); //-MPI / 4, -1);
vec3(poly->lighting->v, 0, -MPI / 4, -1); vec3(poly->lighting->v, 0, -MPI / 4, -1);
ECS_SETCOMPONENT(ecs, id, ecs_placement){
.pos = {.x = (mazepos.x + 0.5) * world->state->cellsize,
.y = 0.35,
.z = (mazepos.y + 0.5) * world->state->cellsize},
.rot = {.x = 0, .y = MPI * 0.3}};
ECS_SETCOMPONENT(ecs, id, ecs_syncgrow){.obj = poly, ECS_SETCOMPONENT(ecs, id, ecs_syncgrow){.obj = poly,
.scale = &world->scaleto, .scale = &world->scaleto,
.basescale = poly->scale.x, .basescale = poly->scale.x,
@ -285,6 +293,11 @@ void create_flippoly(struct vec2i mazepos, haloo3d_easyinstancer *ins,
.render = ins->render, .render = ins->render,
.ws = world->state, .ws = world->state,
.diefunc = kill_flippoly}; .diefunc = kill_flippoly};
ECS_SETCOMPONENT(ecs, id, ecs_autorotate){
.dest = {.x = MPI * 60 * 60 * 24, .y = 0}, .timer = fps * 60 * 60 * 24};
ECS_SETCOMPONENT(ecs, id, ecs_object) poly;
ECS_SETCOMPONENT(ecs, id, ecs_mazeentity){.type = MAZETYPEFLIP,
.mpos = mazepos};
} }
// Generate walls AND create paintings. Kind of doing too much // Generate walls AND create paintings. Kind of doing too much
@ -394,8 +407,13 @@ void sys_camera(ecs_camera *cam, ecs_placement *p) {
(*cam)->pitch = p->rot.y; (*cam)->pitch = p->rot.y;
} }
// do we do anything with the lookvec? idk... void sys_object(ecs_object *obj, ecs_placement *p) {
void sys_object(ecs_object *obj, ecs_placement *p) { (*obj)->pos = p->pos; } (*obj)->pos = p->pos;
YAWP2VEC(p->rot.x, p->rot.y, (*obj)->lookvec.v);
// eprintf("OBJ: %f %f %f (%f %f %f)\n", (*obj)->pos.x, (*obj)->pos.y,
// (*obj)->pos.z, (*obj)->lookvec.x, (*obj)->lookvec.y,
// (*obj)->lookvec.z);
}
void sys_dieoninit(ecs_dieoninit *die, mecs **ecs) { void sys_dieoninit(ecs_dieoninit *die, mecs **ecs) {
if (die->ws->state == WSTATE_INIT) { if (die->ws->state == WSTATE_INIT) {
@ -425,6 +443,9 @@ void sys_world(ecs_world *w, mecs **ecs) {
for (int i = 0; i < MAXFLIPPOLYS; i++) { for (int i = 0; i < MAXFLIPPOLYS; i++) {
struct vec2i m = {.x = rand() % w->state->size, struct vec2i m = {.x = rand() % w->state->size,
.y = rand() % w->state->size}; .y = rand() % w->state->size};
if (m.x == w->state->start.x && m.y == w->state->start.y) {
continue;
}
for (int yc = m.y - FLIPPOLYBUFFER; yc < m.y + FLIPPOLYBUFFER; yc++) { for (int yc = m.y - FLIPPOLYBUFFER; yc < m.y + FLIPPOLYBUFFER; yc++) {
if (yc < 0 || yc >= w->state->size) if (yc < 0 || yc >= w->state->size)
continue; continue;
@ -473,11 +494,7 @@ void sys_world(ecs_world *w, mecs **ecs) {
} }
} }
enum { enum { SAI_INIT, SAI_READY, SAI_GAMEPLAY, SAI_FLIP, SAI_HOLD };
SAI_INIT,
SAI_READY,
SAI_GAMEPLAY,
};
int smartai_mazeend(ecs_smartai *smartai) { int smartai_mazeend(ecs_smartai *smartai) {
if (smartai->mpos.x == smartai->ws->end.x && if (smartai->mpos.x == smartai->ws->end.x &&
@ -491,7 +508,7 @@ int smartai_mazeend(ecs_smartai *smartai) {
} }
void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav, void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav,
ecs_autorotate *arot) { ecs_autorotate *arot, mecs **ecs, ecs_camera *cam) {
const int actiontime = fps / (2 * speed); const int actiontime = fps / (2 * speed);
const int rotdelaytime = actiontime / 2; // 2 * actiontime / 5; const int rotdelaytime = actiontime / 2; // 2 * actiontime / 5;
switch (smartai->state) { switch (smartai->state) {
@ -499,6 +516,9 @@ void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav,
// Here, we wait until the world state is spinup, in which // Here, we wait until the world state is spinup, in which
// case we can spawn and face // case we can spawn and face
if (smartai->ws->state == WSTATE_SPINUP) { if (smartai->ws->state == WSTATE_SPINUP) {
// Reset up vector (even though I like starting upside down, it's a
// bit jarring)
vec3((*cam)->up.v, 0, 1, 0);
smartai->mpos = smartai->ws->start; smartai->mpos = smartai->ws->start;
smartai->dir = smartai->dir =
maze_longesthallway(smartai->ws->maze, smartai->ws->size, maze_longesthallway(smartai->ws->maze, smartai->ws->size,
@ -551,6 +571,31 @@ void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav,
if (smartai_mazeend(smartai)) { if (smartai_mazeend(smartai)) {
return; return;
} }
int mazeind = smartai->mpos.x + smartai->mpos.y * smartai->ws->size;
// I'm being SUPER lazy and we don't do proper collision detection with
// ecs, we just detect the tile and assign objects to tiles
// clang-format off
if (smartai->ws->maze[mazeind] & MAZEFLIP) {
ecs_eid eids[ECS_MAXENTITIES];
int count = mecs_query(*ecs, ecs_mazeentity_fl | ecs_placement_fl, eids);
eprintf("CHECKING MAZEFLIP (%d entities)\n", count);
for(int i = 0; i < count; i++) {
ecs_mazeentity * mze = &ECS_GETCOMPONENT(*ecs, eids[i], ecs_mazeentity);
if(mze->mpos.x == smartai->mpos.x && mze->mpos.y == smartai->mpos.y) {
eprintf("FLIPPING WORLD\n");
smartai->state = SAI_FLIP;
smartai->timer = 0;
// To be SUPER lazy, we just remove the flag and move the object
// somewhere else
ecs_placement * pl = &ECS_GETCOMPONENT(*ecs, eids[i], ecs_placement);
pl->pos.y = -10000;
smartai->ws->maze[mazeind] &= ~MAZEFLIP;
smartai->upsidedown = !smartai->upsidedown;
return;
}
}
}
// clang-format on
// Player can only move forward if there's nothing in front of them // Player can only move forward if there's nothing in front of them
if (maze_connected(smartai->ws->maze, smartai->mpos.x, smartai->mpos.y, if (maze_connected(smartai->ws->maze, smartai->mpos.x, smartai->mpos.y,
smartai->ws->size, smartai->dir)) { smartai->ws->size, smartai->dir)) {
@ -592,7 +637,41 @@ void sys_smartai(ecs_smartai *smartai, ecs_placement *p, ecs_autonav *anav,
} }
} }
} }
break;
case SAI_FLIP:
smartai->timer++;
mfloat_t towards = smartai->upsidedown ? -1 : 1;
if (smartai->timer >= actiontime) {
eprintf("FLIP COMPLETE\n");
smartai->timer = actiontime / 8;
smartai->state = SAI_HOLD;
vec3((*cam)->up.v, 0, towards, 0);
} else {
mfloat_t angle = MPI * smartai->timer / actiontime;
mfloat_t y = towards * -cos(angle);
mfloat_t x = towards * -sin(angle);
switch (smartai->dir) {
case DIRNORTH:
vec3((*cam)->up.v, -x, y, 0);
break;
case DIRSOUTH:
vec3((*cam)->up.v, x, y, 0);
break;
case DIREAST:
vec3((*cam)->up.v, 0, y, x);
break;
case DIRWEST:
vec3((*cam)->up.v, 0, y, -x);
break;
}
}
break;
case SAI_HOLD:
smartai->timer--;
if (smartai->timer <= 0) {
eprintf("HOLD COMPLETE\n");
smartai->state = SAI_GAMEPLAY;
}
break; break;
} }
} }
@ -684,8 +763,8 @@ ECS_SYSTEM2(mecs, sys_autonav, ecs_autonav, ecs_placement);
ECS_SYSTEM2(mecs, sys_autorotate, ecs_autorotate, ecs_placement); ECS_SYSTEM2(mecs, sys_autorotate, ecs_autorotate, ecs_placement);
ECS_SYSTEM2(mecs, sys_camera, ecs_camera, ecs_placement); ECS_SYSTEM2(mecs, sys_camera, ecs_camera, ecs_placement);
ECS_SYSTEM2(mecs, sys_object, ecs_object, ecs_placement); ECS_SYSTEM2(mecs, sys_object, ecs_object, ecs_placement);
ECS_SYSTEM4(mecs, sys_smartai, ecs_smartai, ecs_placement, ecs_autonav, ECS_SYSTEM6(mecs, sys_smartai, ecs_smartai, ecs_placement, ecs_autonav,
ecs_autorotate); ecs_autorotate, mecs, ecs_camera);
ECS_SYSTEM3(mecs, sys_mouseai, ecs_mouseai, ecs_placement, ecs_autonav); ECS_SYSTEM3(mecs, sys_mouseai, ecs_mouseai, ecs_placement, ecs_autonav);
void init_floortexture(haloo3d_fb *floort) { void init_floortexture(haloo3d_fb *floort) {
@ -1045,12 +1124,13 @@ int main() { // int argc, char **argv) {
.ws = &wstate, .ws = &wstate,
.rotchange = 0, .rotchange = 0,
.timer = 0, .timer = 0,
.upsidedown = 0,
.startmarker = starti}; .startmarker = starti};
ecs_eid mouseid = mecs_newentity(&ecs, 0); ecs_eid mouseid = mecs_newentity(&ecs, 0);
eprintf("Mouse eid: %d\n", mouseid); eprintf("Mouse eid: %d\n", mouseid);
ECS_SETCOMPONENT(&ecs, mouseid, ECS_SETCOMPONENT(&ecs, mouseid, ecs_placement){.pos = mousei->pos,
ecs_placement){.pos = mousei->pos}; // we don't use rot .rot = {.x = 0, .y = 0}};
ECS_SETCOMPONENT(&ecs, mouseid, ecs_autonav){.timer = 0}; ECS_SETCOMPONENT(&ecs, mouseid, ecs_autonav){.timer = 0};
ECS_SETCOMPONENT(&ecs, mouseid, ecs_object) mousei; ECS_SETCOMPONENT(&ecs, mouseid, ecs_object) mousei;
ECS_SETCOMPONENT(&ecs, mouseid, ecs_mouseai){.state = SAI_INIT, ECS_SETCOMPONENT(&ecs, mouseid, ecs_mouseai){.state = SAI_INIT,
@ -1111,6 +1191,8 @@ int main() { // int argc, char **argv) {
sys_autonav_run(&ecs, i); sys_autonav_run(&ecs, i);
sys_autorotate_run(&ecs, i); sys_autorotate_run(&ecs, i);
sys_camera_run(&ecs, i); sys_camera_run(&ecs, i);
// NOTE: must run object BEFORE billboard so that billboard
// overrides the rotation from object (we want this)
sys_object_run(&ecs, i); sys_object_run(&ecs, i);
sys_billboard_run(&ecs, i); sys_billboard_run(&ecs, i);
sys_dieoninit_run(&ecs, i); sys_dieoninit_run(&ecs, i);

View File

@ -76,13 +76,14 @@ typedef struct {
// State for tracking a smart ai moving through the maze. // State for tracking a smart ai moving through the maze.
typedef struct { typedef struct {
uint8_t state; int32_t timer;
uint8_t dir;
uint32_t timer;
mfloat_t rotchange; mfloat_t rotchange;
struct vec2i mpos; struct vec2i mpos;
worldstate *ws; worldstate *ws;
haloo3d_obj_instance *startmarker; haloo3d_obj_instance *startmarker;
uint8_t state;
uint8_t dir;
uint8_t upsidedown;
} ecs_smartai; } ecs_smartai;
typedef struct { typedef struct {
@ -101,6 +102,14 @@ typedef struct {
void (*diefunc)(haloo3d_obj_instance *); void (*diefunc)(haloo3d_obj_instance *);
} ecs_dieoninit; } ecs_dieoninit;
// A component which indicates where in a maze an entity is.
// This is tile-based and so entities can't overlap (here at least),
// but just in case, there's an entity type too
typedef struct {
struct vec2i mpos;
uint8_t type;
} ecs_mazeentity;
// Setup ECS system for our game // Setup ECS system for our game
ECS_START(mecs) ECS_START(mecs)
ECS_COMPONENT(ecs_world); ECS_COMPONENT(ecs_world);
@ -114,6 +123,7 @@ ECS_COMPONENT(ecs_billboard);
ECS_COMPONENT(ecs_dieoninit); ECS_COMPONENT(ecs_dieoninit);
ECS_COMPONENT(ecs_mouseai); ECS_COMPONENT(ecs_mouseai);
ECS_COMPONENT(ecs_object); ECS_COMPONENT(ecs_object);
ECS_COMPONENT(ecs_mazeentity);
ECS_END(mecs) ECS_END(mecs)
// And then a copy of the components here... that sucksssss // And then a copy of the components here... that sucksssss
@ -129,5 +139,6 @@ ECS_CID(ecs_billboard, 8);
ECS_CID(ecs_dieoninit, 9); ECS_CID(ecs_dieoninit, 9);
ECS_CID(ecs_mouseai, 10); ECS_CID(ecs_mouseai, 10);
ECS_CID(ecs_object, 11); ECS_CID(ecs_object, 11);
ECS_CID(ecs_mazeentity, 12);
#endif #endif