Simulation now (sort of) respects the match-state

This commit is contained in:
2025-12-11 18:01:26 +01:00
parent 1d414cc392
commit 80cdeb5baf
4 changed files with 182 additions and 123 deletions

View File

@@ -210,6 +210,8 @@ static void state_render(Presentation_State *state) {
} }
} }
// TODO: SS - Switch on 'sim_world->match_state'.
{ // TEMP: SS - Render match state. { // TEMP: SS - Render match state.
char buf[512]; char buf[512];
snprintf(&buf[0], sizeof(buf), "Match-state: %i. Tick: %lu.", sim_world->match_state, sim_world->tick); snprintf(&buf[0], sizeof(buf), "Match-state: %i. Tick: %lu.", sim_world->match_state, sim_world->tick);

View File

@@ -196,9 +196,14 @@ bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_in
assert(player != NULL); assert(player != NULL);
if(simulation_input_equal(player->most_recent_input, input)) { 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; 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)) { if(!squeue_push(&player->input_queue, (void *)&input)) {
return false; return false;
} }

View File

@@ -46,17 +46,17 @@ void simulation_world_tick(Simulation_World *simulation_world) {
assert(simulation_world != NULL); assert(simulation_world != NULL);
// printf("TICK: %lu.\n", simulation_world->tick); // printf("TICK: %lu.\n", simulation_world->tick);
for(uint16_t i = 0; i < simulation_world->command_count; i++) { for(uint16_t i = 0; i < simulation_world->command_count; i++) {
Simulation_Command *cmd = &simulation_world->commands[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]; Simulation_Player *player = &simulation_world->players[cmd->player_id];
assert(player != NULL); assert(player != NULL);
switch(cmd->type) { switch(cmd->type) {
case Simulation_Command_Type_Add_Player: { case Simulation_Command_Type_Add_Player: {
printf("Simulation_Command_Type_Add_Player\n"); // printf("Simulation_Command_Type_Add_Player\n");
assert(!player->active); assert(!player->active);
player->active = true; player->active = true;
@@ -76,7 +76,7 @@ void simulation_world_tick(Simulation_World *simulation_world) {
break; break;
} }
case Simulation_Command_Type_Remove_Player: { case Simulation_Command_Type_Remove_Player: {
printf("Simulation_Command_Type_Remove_Player\n"); // printf("Simulation_Command_Type_Remove_Player\n");
assert(player->active); assert(player->active);
player->active = false; player->active = false;
@@ -85,7 +85,7 @@ void simulation_world_tick(Simulation_World *simulation_world) {
break; break;
} }
case Simulation_Command_Type_Set_Player_Input: { 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); assert(player->active);
player->input = cmd->player_input; player->input = cmd->player_input;
@@ -95,145 +95,180 @@ void simulation_world_tick(Simulation_World *simulation_world) {
} }
simulation_world->command_count = 0; simulation_world->command_count = 0;
switch(simulation_world->match_state) {
Game_World *gw = simulation_world->game_world; case Simulation_Match_State_Waiting_To_Start: {
bool is_singleplayer = simulation_world->max_players == 1;
// Loop over all players in the simulation.
for(uint16_t i = 0; i < simulation_world->max_players; i++) { if(is_singleplayer) {
Simulation_Player *player = &simulation_world->players[i]; simulation_world->match_state = Simulation_Match_State_Counting_Down;
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;
} }
case Entity_Movement_Direction_Right: else {
case Entity_Movement_Direction_Left: // Snakes can only go up/down if it's currently moving right/left. if(simulation_world_amount_of_active_players(simulation_world) > 1) {
{ simulation_world->match_state = Simulation_Match_State_Counting_Down;
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;
} }
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! :) // printf("* Input for player %i - up: %i, down: %i, right: %i, left: %i.\n",
// i,
for(uint16_t i = 0; i < gw->max_entities; i++) { // player->input.up, player->input.down, player->input.right, player->input.left
Entity *entity = &gw->entities[i]; // );
if(!entity->active) {
continue; Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
} assert(player_entity != NULL);
printf("Ticking entity %i (x: %u, y: %u).\n", i, entity->x, entity->y); // Snakes can't go backwards. They have to turn.
{ // Move entities. switch(player_entity->move_direction) {
int16_t dx = 0; case Entity_Movement_Direction_None: {
int16_t dy = 0; break;
}
switch(entity->move_direction) { case Entity_Movement_Direction_Up:
case Entity_Movement_Direction_None: { case Entity_Movement_Direction_Down: // Snakes can only go right/left if it's currently moving up/down.
break; {
} if(player->input.right) {
case Entity_Movement_Direction_Up: { player_entity->move_direction = Entity_Movement_Direction_Right;
dy = -1; }
break; else if(player->input.left) {
} player_entity->move_direction = Entity_Movement_Direction_Left;
case Entity_Movement_Direction_Down: { }
dy = 1;
break; break;
} }
case Entity_Movement_Direction_Right: { case Entity_Movement_Direction_Right:
dx = 1; case Entity_Movement_Direction_Left: // Snakes can only go up/down if it's currently moving right/left.
break; {
} if(player->input.up) {
case Entity_Movement_Direction_Left: { player_entity->move_direction = Entity_Movement_Direction_Up;
dx = -1; }
break; else if(player->input.down) {
} player_entity->move_direction = Entity_Movement_Direction_Down;
} }
if(dx != 0 || dy != 0) { break;
// 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");
} }
} }
if(target_cell == NULL) { // Game-logic! :)
// Target cell does not exist.
// TODO: SS - Die. for(uint16_t i = 0; i < gw->max_entities; i++) {
} Entity *entity = &gw->entities[i];
else { if(!entity->active) {
if(target_cell->entity != NULL) { continue;
// Target cell is occupied. }
// Check what type of entity it is and determine what should happen. { // Move entities.
switch(target_cell->entity->type) { int16_t dx = 0;
case Entity_Type_Snake_Head: { int16_t dy = 0;
// TODO: SS - Die.
switch(entity->move_direction) {
case Entity_Movement_Direction_None: {
break; break;
} }
case Entity_Type_Snake_Body: { case Entity_Movement_Direction_Up: {
// TODO: SS - Die. dy = -1;
break; break;
} }
case Entity_Type_Food: { case Entity_Movement_Direction_Down: {
// TODO: SS - Eat! dy = 1;
break;
}
case Entity_Movement_Direction_Right: {
dx = 1;
break;
}
case Entity_Movement_Direction_Left: {
dx = -1;
break; break;
} }
} }
}
else { if(dx != 0 || dy != 0) {
// Target cell is unoccupied and free to enter. // Try moving.
grid_move_entity_from_cell_to_cell(current_cell, target_cell);
// 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) { 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; simulation_world->command_count += 1;
return true; 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;
} }

View File

@@ -36,4 +36,6 @@ void simulation_world_tick(Simulation_World *simulation_world);
bool simulation_world_enqueue_command(Simulation_World *simulation_world, Simulation_Command command); 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 #endif