From 80cdeb5bafa097fe249e67c2d11e0e33700730eb Mon Sep 17 00:00:00 2001 From: samstalhandske Date: Thu, 11 Dec 2025 18:01:26 +0100 Subject: [PATCH] Simulation now (sort of) respects the match-state --- src/presentation/states/state_ingame.c | 2 + src/session/game_session.c | 5 + src/simulation/simulation_world.c | 296 +++++++++++++++---------- src/simulation/simulation_world.h | 2 + 4 files changed, 182 insertions(+), 123 deletions(-) diff --git a/src/presentation/states/state_ingame.c b/src/presentation/states/state_ingame.c index 0310df6..751746a 100644 --- a/src/presentation/states/state_ingame.c +++ b/src/presentation/states/state_ingame.c @@ -210,6 +210,8 @@ static void state_render(Presentation_State *state) { } } + // TODO: SS - Switch on 'sim_world->match_state'. + { // TEMP: SS - Render match state. char buf[512]; snprintf(&buf[0], sizeof(buf), "Match-state: %i. Tick: %lu.", sim_world->match_state, sim_world->tick); diff --git a/src/session/game_session.c b/src/session/game_session.c index 74ac55d..4ce6872 100644 --- a/src/session/game_session.c +++ b/src/session/game_session.c @@ -196,9 +196,14 @@ bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_in assert(player != NULL); if(simulation_input_equal(player->most_recent_input, input)) { + // Ignore 'input' if it's equal to the most recent input. This way we avoid duplicates. return false; } + // TODO: SS - Check if 'input' is a valid "snake-move". + // Inputting right when going left will sadly be "okay" here which will make the game + // feel less responsive. + if(!squeue_push(&player->input_queue, (void *)&input)) { return false; } diff --git a/src/simulation/simulation_world.c b/src/simulation/simulation_world.c index 11f8b67..675d758 100644 --- a/src/simulation/simulation_world.c +++ b/src/simulation/simulation_world.c @@ -46,17 +46,17 @@ void simulation_world_tick(Simulation_World *simulation_world) { assert(simulation_world != NULL); // printf("TICK: %lu.\n", simulation_world->tick); - + for(uint16_t i = 0; i < simulation_world->command_count; i++) { Simulation_Command *cmd = &simulation_world->commands[i]; - printf("Command type: %i, player id: %i.\n", cmd->type, cmd->player_id); + // printf("Command type: %i, player id: %i.\n", cmd->type, cmd->player_id); Simulation_Player *player = &simulation_world->players[cmd->player_id]; assert(player != NULL); switch(cmd->type) { case Simulation_Command_Type_Add_Player: { - printf("Simulation_Command_Type_Add_Player\n"); + // printf("Simulation_Command_Type_Add_Player\n"); assert(!player->active); player->active = true; @@ -76,7 +76,7 @@ void simulation_world_tick(Simulation_World *simulation_world) { break; } case Simulation_Command_Type_Remove_Player: { - printf("Simulation_Command_Type_Remove_Player\n"); + // printf("Simulation_Command_Type_Remove_Player\n"); assert(player->active); player->active = false; @@ -85,7 +85,7 @@ void simulation_world_tick(Simulation_World *simulation_world) { break; } case Simulation_Command_Type_Set_Player_Input: { - printf("Simulation_Command_Type_Set_Player_Input\n"); + // printf("Simulation_Command_Type_Set_Player_Input\n"); assert(player->active); player->input = cmd->player_input; @@ -95,145 +95,180 @@ void simulation_world_tick(Simulation_World *simulation_world) { } simulation_world->command_count = 0; - - Game_World *gw = simulation_world->game_world; - - // Loop over all players in the simulation. - for(uint16_t i = 0; i < simulation_world->max_players; i++) { - Simulation_Player *player = &simulation_world->players[i]; - if(!player->active) { - continue; - } - - printf("* Input for player %i - up: %i, down: %i, right: %i, left: %i.\n", - i, - player->input.up, player->input.down, player->input.right, player->input.left - ); - - Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id); - assert(player_entity != NULL); - - // Snakes can't go backwards. They have to turn. - - switch(player_entity->move_direction) { - case Entity_Movement_Direction_Up: - case Entity_Movement_Direction_Down: // Snakes can only go right/left if it's currently moving up/down. - { - if(player->input.right) { - player_entity->move_direction = Entity_Movement_Direction_Right; - } - else if(player->input.left) { - player_entity->move_direction = Entity_Movement_Direction_Left; - } - - break; + switch(simulation_world->match_state) { + case Simulation_Match_State_Waiting_To_Start: { + bool is_singleplayer = simulation_world->max_players == 1; + + if(is_singleplayer) { + simulation_world->match_state = Simulation_Match_State_Counting_Down; } - case Entity_Movement_Direction_Right: - case Entity_Movement_Direction_Left: // Snakes can only go up/down if it's currently moving right/left. - { - if(player->input.up) { - player_entity->move_direction = Entity_Movement_Direction_Up; + else { + if(simulation_world_amount_of_active_players(simulation_world) > 1) { + simulation_world->match_state = Simulation_Match_State_Counting_Down; } - else if(player->input.down) { - player_entity->move_direction = Entity_Movement_Direction_Down; - } - - break; } + + break; } + case Simulation_Match_State_Counting_Down: { + if(simulation_world->tick > 50) { // TEMP: SS - Hardcoded number and condition to break out of this state. + simulation_world->match_state = Simulation_Match_State_Active; + } + + break; + } + case Simulation_Match_State_Active: { + if(simulation_world->tick > 500) { // TEMP: SS - Hardcoded number and condition to break out of this state. + simulation_world->match_state = Simulation_Match_State_Ended; + } + else { + + Game_World *gw = simulation_world->game_world; - // printf("Entity %i ~ x: %u, y: %u. Move-dir: %i.\n", player->entity_id, player_entity->x, player_entity->y, player_entity->move_direction); - } + // Loop over all players in the simulation. + for(uint16_t i = 0; i < simulation_world->max_players; i++) { + Simulation_Player *player = &simulation_world->players[i]; + if(!player->active) { + continue; + } - // TODO: SS - Game-logic! :) - - for(uint16_t i = 0; i < gw->max_entities; i++) { - Entity *entity = &gw->entities[i]; - if(!entity->active) { - continue; - } - - printf("Ticking entity %i (x: %u, y: %u).\n", i, entity->x, entity->y); - - { // Move entities. - int16_t dx = 0; - int16_t dy = 0; - - switch(entity->move_direction) { - case Entity_Movement_Direction_None: { - break; - } - case Entity_Movement_Direction_Up: { - dy = -1; - break; - } - case Entity_Movement_Direction_Down: { - dy = 1; - break; - } - case Entity_Movement_Direction_Right: { - dx = 1; - break; - } - case Entity_Movement_Direction_Left: { - dx = -1; - break; - } - } - - if(dx != 0 || dy != 0) { - // Try moving. - printf("Trying to move %i.\n", i); - - // Figure out what cell we're on and what cell we want to go to. - Grid_Cell *current_cell = grid_get_cell(&gw->grid, entity->x, entity->y); - assert(current_cell != NULL); - Grid_Cell *target_cell = grid_get_cell(&gw->grid, entity->x + dx, entity->y + dy); - - { // Debug-logging. - printf("Current cell = (x: %u, y: %u, entity: %p).\n", current_cell->x, current_cell->y, current_cell->entity); - if(target_cell != NULL) { - printf("Target cell = (x: %u, y: %u, entity: %p).\n", target_cell->x, target_cell->y, target_cell->entity); - } - else { - printf("Target cell = NULL!\n"); + // printf("* Input for player %i - up: %i, down: %i, right: %i, left: %i.\n", + // i, + // player->input.up, player->input.down, player->input.right, player->input.left + // ); + + Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id); + assert(player_entity != NULL); + + // Snakes can't go backwards. They have to turn. + + switch(player_entity->move_direction) { + case Entity_Movement_Direction_None: { + break; + } + case Entity_Movement_Direction_Up: + case Entity_Movement_Direction_Down: // Snakes can only go right/left if it's currently moving up/down. + { + if(player->input.right) { + player_entity->move_direction = Entity_Movement_Direction_Right; + } + else if(player->input.left) { + player_entity->move_direction = Entity_Movement_Direction_Left; + } + + break; + } + case Entity_Movement_Direction_Right: + case Entity_Movement_Direction_Left: // Snakes can only go up/down if it's currently moving right/left. + { + if(player->input.up) { + player_entity->move_direction = Entity_Movement_Direction_Up; + } + else if(player->input.down) { + player_entity->move_direction = Entity_Movement_Direction_Down; + } + + break; + } } } - - if(target_cell == NULL) { - // Target cell does not exist. - // TODO: SS - Die. - } - else { - if(target_cell->entity != NULL) { - // Target cell is occupied. - - // Check what type of entity it is and determine what should happen. - switch(target_cell->entity->type) { - case Entity_Type_Snake_Head: { - // TODO: SS - Die. + + // Game-logic! :) + + for(uint16_t i = 0; i < gw->max_entities; i++) { + Entity *entity = &gw->entities[i]; + if(!entity->active) { + continue; + } + + { // Move entities. + int16_t dx = 0; + int16_t dy = 0; + + switch(entity->move_direction) { + case Entity_Movement_Direction_None: { break; } - case Entity_Type_Snake_Body: { - // TODO: SS - Die. + case Entity_Movement_Direction_Up: { + dy = -1; break; } - case Entity_Type_Food: { - // TODO: SS - Eat! + case Entity_Movement_Direction_Down: { + dy = 1; + break; + } + case Entity_Movement_Direction_Right: { + dx = 1; + break; + } + case Entity_Movement_Direction_Left: { + dx = -1; break; } } - } - else { - // Target cell is unoccupied and free to enter. - grid_move_entity_from_cell_to_cell(current_cell, target_cell); + + if(dx != 0 || dy != 0) { + // Try moving. + + // Figure out what cell we're on and what cell we want to go to. + Grid_Cell *current_cell = grid_get_cell(&gw->grid, entity->x, entity->y); + assert(current_cell != NULL); + Grid_Cell *target_cell = grid_get_cell(&gw->grid, entity->x + dx, entity->y + dy); + + // { // Debug-logging. + // printf("Current cell = (x: %u, y: %u, entity: %p).\n", current_cell->x, current_cell->y, current_cell->entity); + // if(target_cell != NULL) { + // printf("Target cell = (x: %u, y: %u, entity: %p).\n", target_cell->x, target_cell->y, target_cell->entity); + // } + // else { + // printf("Target cell = NULL!\n"); + // } + // } + + if(target_cell == NULL) { + // Target cell does not exist. + // TODO: SS - Die. + } + else { + if(target_cell->entity != NULL) { + // Target cell is occupied. + + // Check what type of entity it is and determine what should happen. + switch(target_cell->entity->type) { + case Entity_Type_Snake_Head: { + // TODO: SS - Die. + break; + } + case Entity_Type_Snake_Body: { + // TODO: SS - Die. + break; + } + case Entity_Type_Food: { + // TODO: SS - Eat! + break; + } + } + } + else { + // Target cell is unoccupied and free to enter. + grid_move_entity_from_cell_to_cell(current_cell, target_cell); + } + } + } } } } + + break; + } + case Simulation_Match_State_Ended: { + printf("Match over!\n"); + + break; } } - simulation_world->tick += 1; + simulation_world->tick += 1; // TODO: SS - Stop ticking if match has ended. } bool simulation_world_enqueue_command(Simulation_World *simulation_world, Simulation_Command command) { @@ -247,4 +282,19 @@ bool simulation_world_enqueue_command(Simulation_World *simulation_world, Simula simulation_world->command_count += 1; return true; +} + +uint16_t simulation_world_amount_of_active_players(Simulation_World *simulation_world) { + assert(simulation_world != NULL); + + uint16_t count = 0; + + for(uint16_t i = 0; i < simulation_world->max_players; i++) { + Simulation_Player *player = &simulation_world->players[i]; + if(player->active) { + count += 1; + } + } + + return count; } \ No newline at end of file diff --git a/src/simulation/simulation_world.h b/src/simulation/simulation_world.h index c308aec..5054663 100644 --- a/src/simulation/simulation_world.h +++ b/src/simulation/simulation_world.h @@ -36,4 +36,6 @@ void simulation_world_tick(Simulation_World *simulation_world); bool simulation_world_enqueue_command(Simulation_World *simulation_world, Simulation_Command command); +uint16_t simulation_world_amount_of_active_players(Simulation_World *simulation_world); + #endif \ No newline at end of file