diff --git a/ecs2.h b/ecs2.h index 78ad224..81d9f72 100644 --- a/ecs2.h +++ b/ecs2.h @@ -59,6 +59,16 @@ typedef int ecs_eid; ecs_cid _realcomps = ECS_SELFFLAG | _comps; \ 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 */ \ static ecs_eid name##_eid(name **_ecs) { \ return (ecs_eid)(_ecs - (*_ecs)->c_##name); \ @@ -68,6 +78,8 @@ typedef int ecs_eid; // Create an ECS component within an ECS struct #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 // have a unique id and I can't do that inside a macro without requiring // extensions) diff --git a/haloo3d b/haloo3d index 917dfe4..b6347c5 160000 --- a/haloo3d +++ b/haloo3d @@ -1 +1 @@ -Subproject commit 917dfe41aa118cefe36779c9bba7957160cc52e4 +Subproject commit b6347c5360b84079a50d943d4b1fe8e0edd946b8 diff --git a/maze.c b/maze.c index b266891..1060972 100644 --- a/maze.c +++ b/maze.c @@ -48,7 +48,7 @@ #define PRINTMAZE // Max amount of flip polys to generate in maze. actual amount can be lower, // but there will always at least be 1 -#define MAXFLIPPOLYS 17 +#define MAXFLIPPOLYS 6 // Min space between flip polys #define FLIPPOLYBUFFER 3 @@ -58,6 +58,8 @@ #define MAZEVISIT 4 #define MAZEFLIP 8 +#define MAZETYPEFLIP 1 + // When you rightshift these values, you "turn right". // 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 @@ -84,7 +86,7 @@ const char POLYNAMES[NUMPOLYS][20] = {"tetrahedron"}; float ditherstart = -1; float ditherend = 8; float fov = 90.0; -float minlight = 0.25; +float minlight = 0.15; float speed = 1.0; int fps = 45; uint16_t sky = 0xF000; @@ -276,7 +278,13 @@ void create_flippoly(struct vec2i mazepos, haloo3d_easyinstancer *ins, (mazepos.y + 0.5) * world->state->cellsize); ecs_eid id = mecs_newentity(ecs, 0); mallocordie(poly->lighting, sizeof(struct vec3)); + // vec3(poly->lighting->v, 0, 0, -1); //-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, .scale = &world->scaleto, .basescale = poly->scale.x, @@ -285,6 +293,11 @@ void create_flippoly(struct vec2i mazepos, haloo3d_easyinstancer *ins, .render = ins->render, .ws = world->state, .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 @@ -394,8 +407,13 @@ void sys_camera(ecs_camera *cam, ecs_placement *p) { (*cam)->pitch = p->rot.y; } -// do we do anything with the lookvec? idk... -void sys_object(ecs_object *obj, ecs_placement *p) { (*obj)->pos = p->pos; } +void sys_object(ecs_object *obj, ecs_placement *p) { + (*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) { 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++) { struct vec2i m = {.x = 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++) { if (yc < 0 || yc >= w->state->size) continue; @@ -473,11 +494,7 @@ void sys_world(ecs_world *w, mecs **ecs) { } } -enum { - SAI_INIT, - SAI_READY, - SAI_GAMEPLAY, -}; +enum { SAI_INIT, SAI_READY, SAI_GAMEPLAY, SAI_FLIP, SAI_HOLD }; int smartai_mazeend(ecs_smartai *smartai) { 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, - ecs_autorotate *arot) { + ecs_autorotate *arot, mecs **ecs, ecs_camera *cam) { const int actiontime = fps / (2 * speed); const int rotdelaytime = actiontime / 2; // 2 * actiontime / 5; 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 // case we can spawn and face 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->dir = 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)) { 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 if (maze_connected(smartai->ws->maze, smartai->mpos.x, smartai->mpos.y, 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; } } @@ -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_camera, ecs_camera, ecs_placement); ECS_SYSTEM2(mecs, sys_object, ecs_object, ecs_placement); -ECS_SYSTEM4(mecs, sys_smartai, ecs_smartai, ecs_placement, ecs_autonav, - ecs_autorotate); +ECS_SYSTEM6(mecs, sys_smartai, ecs_smartai, ecs_placement, ecs_autonav, + ecs_autorotate, mecs, ecs_camera); ECS_SYSTEM3(mecs, sys_mouseai, ecs_mouseai, ecs_placement, ecs_autonav); void init_floortexture(haloo3d_fb *floort) { @@ -1045,12 +1124,13 @@ int main() { // int argc, char **argv) { .ws = &wstate, .rotchange = 0, .timer = 0, + .upsidedown = 0, .startmarker = starti}; ecs_eid mouseid = mecs_newentity(&ecs, 0); eprintf("Mouse eid: %d\n", mouseid); - ECS_SETCOMPONENT(&ecs, mouseid, - ecs_placement){.pos = mousei->pos}; // we don't use rot + ECS_SETCOMPONENT(&ecs, mouseid, ecs_placement){.pos = mousei->pos, + .rot = {.x = 0, .y = 0}}; ECS_SETCOMPONENT(&ecs, mouseid, ecs_autonav){.timer = 0}; ECS_SETCOMPONENT(&ecs, mouseid, ecs_object) mousei; 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_autorotate_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_billboard_run(&ecs, i); sys_dieoninit_run(&ecs, i); diff --git a/maze_ecstypes.h b/maze_ecstypes.h index c506c53..cf6eab0 100644 --- a/maze_ecstypes.h +++ b/maze_ecstypes.h @@ -76,13 +76,14 @@ typedef struct { // State for tracking a smart ai moving through the maze. typedef struct { - uint8_t state; - uint8_t dir; - uint32_t timer; + int32_t timer; mfloat_t rotchange; struct vec2i mpos; worldstate *ws; haloo3d_obj_instance *startmarker; + uint8_t state; + uint8_t dir; + uint8_t upsidedown; } ecs_smartai; typedef struct { @@ -101,6 +102,14 @@ typedef struct { void (*diefunc)(haloo3d_obj_instance *); } 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 ECS_START(mecs) ECS_COMPONENT(ecs_world); @@ -114,6 +123,7 @@ ECS_COMPONENT(ecs_billboard); ECS_COMPONENT(ecs_dieoninit); ECS_COMPONENT(ecs_mouseai); ECS_COMPONENT(ecs_object); +ECS_COMPONENT(ecs_mazeentity); ECS_END(mecs) // 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_mouseai, 10); ECS_CID(ecs_object, 11); +ECS_CID(ecs_mazeentity, 12); #endif