From ed2614fb302225253181d65f7d23f4598dadcc8e Mon Sep 17 00:00:00 2001 From: Carlos Sanchez Date: Mon, 19 Aug 2024 02:24:19 -0400 Subject: [PATCH] No player? --- ecs2.h | 14 ++++ maze.c | 220 +++++++++++++++++++++++++++++++++------------------------ 2 files changed, 140 insertions(+), 94 deletions(-) diff --git a/ecs2.h b/ecs2.h index 3e28c99..16dde7b 100644 --- a/ecs2.h +++ b/ecs2.h @@ -102,4 +102,18 @@ typedef int ecs_eid; } \ } +// Add a system function which automatically calls your given function with +// pre-pulled items from the entity component arrays. The new function is +// named the same as the old one, just with _run appeneded +#define ECS_SYSTEM5(ecsname, fname, type1, type2, type3, type4, type5) \ + void fname##_run(ecsname *_ecs, ecs_eid eid) { \ + ecs_cid _ecsflags = \ + type1##_fl | type2##_fl | type3##_fl | type4##_fl | type5##_fl; \ + if (ecsname##_match(_ecs, eid, _ecsflags)) { \ + fname(_ecs->c_##type1 + eid, _ecs->c_##type2 + eid, \ + _ecs->c_##type3 + eid, _ecs->c_##type4 + eid, \ + _ecs->c_##type5 + eid); \ + } \ + } + #endif diff --git a/maze.c b/maze.c index 74d543e..01316c0 100644 --- a/maze.c +++ b/maze.c @@ -80,6 +80,21 @@ struct vec2i dirtovec(uint8_t dir) { return result; } +mfloat_t dirtoyaw(uint8_t dir) { + switch (dir) { + case DIREAST: + return MPI_2; + case DIRWEST: + return -MPI_2; + case DIRNORTH: + return 0; + case DIRSOUTH: + return MPI; + default: + return 0; + } +} + int maze_visited(uint8_t *maze, int x, int y, int size) { return (maze[x + y * size] & MAZEVISIT) > 0; } @@ -327,6 +342,8 @@ void sys_camera(ecs_camera *cam, ecs_placement *p) { cam->camera->pos = p->pos; cam->camera->yaw = p->rot.x; cam->camera->pitch = p->rot.y; + // eprintf("CAM: %f %f POS: %f %f %f\n", cam->camera->yaw, cam->camera->pitch, + // cam->camera->pos.x, cam->camera->pos.y, cam->camera->pos.z); } void sys_world(ecs_world *w) { @@ -373,102 +390,117 @@ void sys_world(ecs_world *w) { } } -// // A general position within the maze, and a pointer to the maze itself. -// // Can be used to traverse the maze -// typedef struct { -// uint8_t *maze; -// struct vec2i pos; // tile position within maze -// int size; -// uint8_t dir; // facing dir (see DIREAST/DIRSOUTH/etc); -// } ecs_maze; +enum { + SAI_INIT, + SAI_READY, + SAI_GAMEPLAY, +}; -// // Use a timer and a destination to move simply through -// typedef struct { -// -// } ecs_mazemove; - -// State for tracking ai moving through the maze. +// State for tracking a smart ai moving through the maze. typedef struct { uint8_t state; - // uint8_t nextdir; + uint8_t rotstate; + uint8_t dir; uint32_t timer; + struct vec2i mpos; } ecs_smartai; -// typedef struct { -// uint8_t *maze; -// // What state the game is in, such as game initialize, animation, running, -// etc uint8_t state; -// } ecs_world; - -// everything in the maze is controlled by the CPU. As such, movement -// is as simple as "go here by this time". No need to complicate the -// components? -/* -static void sys_ecs_smartai(ecs_smartai *smartai, ecs_maze *maze, - ecs_moveto *mt, ecs_rotateto *rt) { - int actiontime = fps / 2; - // Some states are triggered based on the timer - if (smartai->timer > 0) { - smartai->timer--; - } - // The rotation is delayed to make it feel a bit more like the original - // maze, which I think determined rotation and direction upon entering - // a tile. I instead calculate that in the middle of the tile. It doesn't - // really line up like it does on the windows screensaver but it's - // close enough for me. - if (smartai->timer == 0) { - if (smartai->state == 1) { - eprintf("TURNING RIGHT\n"); - rt->dstrot.x = rt->dstrot.x + MPI_2; - rt->timer = actiontime; - maze->dir = TURNRIGHT(maze->dir); - smartai->state = 0; - } else if (smartai->state == 2) { - eprintf("TURNING LEFT\n"); - rt->dstrot.x = rt->dstrot.x - MPI_2; - rt->timer = actiontime; - maze->dir = TURNLEFT(maze->dir); - smartai->state = 0; +static void sys_smartai(ecs_smartai *smartai, ecs_worldstate *ws, + ecs_autonav *anav, ecs_autorotate *arot) { + const int actiontime = ws->state->fps / 2; + const int rotdelaytime = 2 * actiontime / 5; + switch (smartai->state) { + case SAI_INIT: + // Here, we wait until the world state is spinup, in which + // case we can spawn and face + if (ws->state->state == WSTATE_SPINUP) { + smartai->mpos = ws->state->start; + anav->dest.x = ws->state->cellsize * (ws->state->start.x + 0.5); + anav->dest.z = ws->state->cellsize * (ws->state->start.y + 0.5); + anav->timer = 0; + smartai->dir = maze_longesthallway( + ws->state->maze, MAZESIZE, ws->state->start.x, ws->state->start.y); + arot->dest.x = dirtoyaw(smartai->dir); + arot->timer = 0; + smartai->state = SAI_READY; + eprintf("PLAYER READY: %f %f (%f), waiting for spinup\n", anav->dest.x, + anav->dest.z, arot->dest.x); } - } - // Only decide to do things if you're not moving anymore. Movement is the most - // important thing - if (mt->timer == 0) { - eprintf("SMARTAI: %d TIMER: %d DIR: %d POS: (%f, %f)\n", smartai->state, - smartai->timer, maze->dir, mt->pos.x, mt->pos.z); - // Player can only move forward if there's nothing in front of them - if (maze_connected(maze->maze, maze->pos.x, maze->pos.y, maze->size, - maze->dir)) { - struct vec2i movement = dirtovec(maze->dir); - maze->pos.x += movement.x; - maze->pos.y += movement.y; - mt->timer = actiontime; - mt->dst.x += HSCALE * movement.x; - mt->dst.z += HSCALE * movement.y; - smartai->state = 0; + break; + case SAI_READY: + if (ws->state->state == WSTATE_GAMEPLAY) { + smartai->state = SAI_GAMEPLAY; + eprintf("PLAYER STARTING GAMEPLAY\n"); } - if (smartai->timer <= 0) { - // Ok we might be moving, we might not be. Let's go ahead and calculate - // rotation based on the FUTURE direction we want to turn. - uint8_t rightdir = TURNRIGHT(maze->dir); - uint8_t leftdir = TURNLEFT(maze->dir); - if (maze_connected(maze->maze, maze->pos.x, maze->pos.y, maze->size, - rightdir)) { - // Always choose right over left - smartai->state = 1; - smartai->timer = 2 * actiontime / 5; - eprintf("WILL TURN RIGHT TO: %d\n", rightdir); - } else if (!maze_connected(maze->maze, maze->pos.x, maze->pos.y, - maze->size, maze->dir)) { - // We only move left if the player can't move forward or right - smartai->state = 2; - smartai->timer = 2 * actiontime / 5; - eprintf("WILL TURN LEFT (stuck) TO: %d\n", leftdir); + break; + case SAI_GAMEPLAY: + // Normal gameplay: move through the maze, etc. + // Some states are triggered based on the timer + if (smartai->timer > 0) { + smartai->timer--; + } + // The rotation is delayed to make it feel a bit more like the original + // maze, which I think determined rotation and direction upon entering + // a tile. I instead calculate that in the middle of the tile. It doesn't + // really line up like it does on the windows screensaver but it's + // close enough for me. + if (smartai->timer == 0) { + if (smartai->rotstate == 1) { + eprintf("TURNING RIGHT\n"); + arot->dest.x += MPI_2; + arot->timer = actiontime; + smartai->dir = TURNRIGHT(smartai->dir); + smartai->rotstate = 0; + } else if (smartai->rotstate == 2) { + eprintf("TURNING LEFT\n"); + arot->dest.x -= MPI_2; + arot->timer = actiontime; + smartai->dir = TURNLEFT(smartai->dir); + smartai->rotstate = 0; } } + // Only decide to do things if you're not moving anymore. Movement is the + // most important thing + if (anav->timer == 0) { + eprintf("SMARTAI: %d TIMER: %d DIR: %d POS: (%f, %f)\n", + smartai->rotstate, smartai->timer, smartai->dir, anav->dest.x, + anav->dest.z); + // Player can only move forward if there's nothing in front of them + if (maze_connected(ws->state->maze, smartai->mpos.x, smartai->mpos.y, + MAZESIZE, smartai->dir)) { + struct vec2i movement = dirtovec(smartai->dir); + smartai->mpos.x += movement.x; + smartai->mpos.y += movement.y; + anav->timer = actiontime; + anav->dest.x += ws->state->cellsize * movement.x; + anav->dest.z += ws->state->cellsize * movement.y; + smartai->rotstate = 0; + } + // Figure out if a rotation should be scheduled + if (smartai->timer <= 0) { + // Ok we might be moving, we might not be. Let's go ahead and calculate + // rotation based on the FUTURE direction we want to turn. + uint8_t rightdir = TURNRIGHT(smartai->dir); + uint8_t leftdir = TURNLEFT(smartai->dir); + if (maze_connected(ws->state->maze, smartai->mpos.x, smartai->mpos.y, + MAZESIZE, rightdir)) { + // Always choose right over left + smartai->rotstate = 1; + smartai->timer = rotdelaytime; + eprintf("WILL TURN RIGHT TO: %d\n", rightdir); + } else if (!maze_connected(ws->state->maze, smartai->mpos.x, + smartai->mpos.y, MAZESIZE, smartai->dir)) { + // We only move left if the player can't move forward or right + smartai->rotstate = 2; + smartai->timer = rotdelaytime; + eprintf("WILL TURN LEFT (stuck) TO: %d\n", leftdir); + } + } + } + + break; } } -*/ // static void sys_ecs_world(ecs_world *world, ecs_maze *maze, ecs_moveto *mt, // ecs_rotateto *rt) {} @@ -481,9 +513,9 @@ ECS_COMPONENT(ecs_autonav); ECS_COMPONENT(ecs_autorotate); ECS_COMPONENT(ecs_placement); ECS_COMPONENT(ecs_camera); +ECS_COMPONENT(ecs_smartai); // ECS_COMPONENT(ecs_moveto); // ECS_COMPONENT(ecs_rotateto); -// ECS_COMPONENT(ecs_smartai); // ECS_COMPONENT(ecs_camera); // ECS_COMPONENT(ecs_maze); ECS_END(mecs) @@ -495,10 +527,10 @@ ECS_CID(ecs_autonav, 2); ECS_CID(ecs_autorotate, 3); ECS_CID(ecs_placement, 4); ECS_CID(ecs_camera, 5); +ECS_CID(ecs_smartai, 6); // ECS_CID(ecs_moveto, 0); // ECS_CID(ecs_rotateto, 1); -// ECS_CID(ecs_smartai, 2); // ECS_CID(ecs_camera, 3); // ECS_CID(ecs_maze, 4); @@ -506,6 +538,8 @@ ECS_SYSTEM1(mecs, sys_world, ecs_world); 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_SYSTEM4(mecs, sys_smartai, ecs_smartai, ecs_worldstate, ecs_autonav, + ecs_autorotate); // ECS_SYSTEM1(mecs, sys_ecs_moveto, ecs_moveto); // ECS_SYSTEM1(mecs, sys_ecs_rotateto, ecs_rotateto); // ECS_SYSTEM2(mecs, sys_ecs_moveto_camera, ecs_moveto, ecs_camera); @@ -656,9 +690,13 @@ int main() { // int argc, char **argv) { ecs_eid playerid = mecs_newentity(&ecs, 0); eprintf("Player eid: %d\n", playerid); ECS_SETCOMPONENT(&ecs, playerid, ecs_worldstate){.state = &wstate}; + ECS_SETCOMPONENT(&ecs, playerid, ecs_placement){.pos = render.camera.pos}; ECS_SETCOMPONENT(&ecs, playerid, ecs_camera){.camera = &render.camera}; - ECS_SETCOMPONENT(&ecs, playerid, ecs_autonav){.timer = 0}; + ECS_SETCOMPONENT(&ecs, playerid, ecs_autonav){.timer = 0, + .dest = render.camera.pos}; ECS_SETCOMPONENT(&ecs, playerid, ecs_autorotate){.timer = 0}; + ECS_SETCOMPONENT(&ecs, playerid, + ecs_smartai){.state = SAI_INIT, .rotstate = 0, .timer = 0}; // if (playerid == -1) { // dieerr("WHY IS PLAYERID -1???\n"); @@ -721,16 +759,10 @@ int main() { // int argc, char **argv) { for (int i = 0; i < ECS_MAXENTITIES; i++) { sys_world_run(&ecs, i); - + sys_smartai_run(&ecs, i); sys_autonav_run(&ecs, i); sys_autorotate_run(&ecs, i); sys_camera_run(&ecs, i); - // sys_ecs_world_run(&ecs, i); - // sys_ecs_smartai_run(&ecs, i); - // sys_ecs_moveto_run(&ecs, i); - // sys_ecs_rotateto_run(&ecs, i); - // sys_ecs_moveto_camera_run(&ecs, i); - // sys_ecs_rotateto_camera_run(&ecs, i); } totaldrawn = 0;