Input is more responsive. Fixed bug with creating session-players.
This commit is contained in:
@@ -62,8 +62,20 @@ static void state_enter(Presentation_State *state) {
|
|||||||
static void state_tick(Presentation_State *state) {
|
static void state_tick(Presentation_State *state) {
|
||||||
Presentation_State_Ingame_Context *ctx = (Presentation_State_Ingame_Context *)state->context;
|
Presentation_State_Ingame_Context *ctx = (Presentation_State_Ingame_Context *)state->context;
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
|
|
||||||
|
Game_Session *session = g_current_session;
|
||||||
|
|
||||||
game_session_tick(g_current_session);
|
{ // Push local input to queue.
|
||||||
|
game_session_enqueue_player_input(session, session->local_player_index, (Simulation_Game_Input) {
|
||||||
|
.up = IsKeyDown(KEY_UP) || IsKeyDown(KEY_W),
|
||||||
|
.down = IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S),
|
||||||
|
.right = IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D),
|
||||||
|
.left = IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
double delta_time = GetFrameTime();
|
||||||
|
game_session_update(session, delta_time);
|
||||||
|
|
||||||
{ // TEMP: SS
|
{ // TEMP: SS
|
||||||
if(IsKeyPressed(KEY_ESCAPE)) {
|
if(IsKeyPressed(KEY_ESCAPE)) {
|
||||||
@@ -204,7 +216,6 @@ static void state_render(Presentation_State *state) {
|
|||||||
|
|
||||||
DrawText(buf, 32, 32, 12, RED);
|
DrawText(buf, 32, 32, 12, RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
EndMode2D();
|
EndMode2D();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "raylib.h"
|
#include "shared/squeue.h"
|
||||||
|
|
||||||
|
#define INPUT_QUEUE_CAPACITY 8
|
||||||
|
|
||||||
Game_Session *g_current_session = NULL;
|
Game_Session *g_current_session = NULL;
|
||||||
|
|
||||||
@@ -28,11 +30,23 @@ void game_session_create(bool is_singleplayer, bool is_host, Game_Session_Settin
|
|||||||
session->players = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
session->players = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
||||||
session->players_prev = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
session->players_prev = (Game_Session_Player *)calloc(session->settings.max_players, sizeof(Game_Session_Player));
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||||
|
assert(squeue_init(
|
||||||
|
&session->players[i].input_queue,
|
||||||
|
INPUT_QUEUE_CAPACITY,
|
||||||
|
sizeof(Simulation_Game_Input)
|
||||||
|
));
|
||||||
|
|
||||||
|
// Intentionally not initializing players_prev's input_queue.
|
||||||
|
}
|
||||||
|
|
||||||
{ // TEMP
|
{ // TEMP
|
||||||
session->local_player_index = 0;
|
session->local_player_index = 0;
|
||||||
assert(game_session_create_player(session, &session->local_player_index));
|
assert(game_session_create_player(session, &session->local_player_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session->simulation_accumulator = 0.0f;
|
||||||
|
|
||||||
g_current_session = session;
|
g_current_session = session;
|
||||||
|
|
||||||
printf("New Game_Session created.\n");
|
printf("New Game_Session created.\n");
|
||||||
@@ -47,6 +61,12 @@ void game_session_destroy() {
|
|||||||
|
|
||||||
simulation_destroy_world(&session->simulation_world);
|
simulation_destroy_world(&session->simulation_world);
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||||
|
squeue_free(&session->players[i].input_queue);
|
||||||
|
|
||||||
|
// Intentionally not freeing players_prev's input_queue.
|
||||||
|
}
|
||||||
|
|
||||||
free(session->players);
|
free(session->players);
|
||||||
session->players = NULL;
|
session->players = NULL;
|
||||||
free(session->players_prev);
|
free(session->players_prev);
|
||||||
@@ -58,30 +78,23 @@ void game_session_destroy() {
|
|||||||
|
|
||||||
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings) {
|
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings) {
|
||||||
out_settings->seed = 1337; // TODO: SS - Randomize.
|
out_settings->seed = 1337; // TODO: SS - Randomize.
|
||||||
|
out_settings->tickrate = 10.0;
|
||||||
out_settings->level_width = 32;
|
out_settings->level_width = 32;
|
||||||
out_settings->level_height = 32;
|
out_settings->level_height = 32;
|
||||||
out_settings->max_players = is_singleplayer ? 1 : 8;
|
out_settings->max_players = is_singleplayer ? 1 : 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
void game_session_tick(Game_Session *session) {
|
static void game_session_tick(Game_Session *session) {
|
||||||
Game_Session_Player *local_session_player = game_session_get_local_player(session);
|
// Update input.
|
||||||
assert(local_session_player != NULL);
|
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
||||||
local_session_player->input = (Simulation_Game_Input) { // TODO: SS - Move this somewhere else, maybe.
|
Game_Session_Player *session_player = &session->players[i];
|
||||||
.up = IsKeyDown(KEY_UP) || IsKeyDown(KEY_W),
|
|
||||||
.down = IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S),
|
|
||||||
.right = IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D),
|
|
||||||
.left = IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)
|
|
||||||
};
|
|
||||||
|
|
||||||
{ // TODO: SS - Use delta-time to accumulate time. Tick the simulation in a constant tick-rate.
|
{ // Check if any players have joined/disconnected by comparing against the previous session_player.
|
||||||
// Update input.
|
|
||||||
for(uint16_t i = 0; i < session->settings.max_players; i++) {
|
|
||||||
Game_Session_Player *session_player_prev = &session->players_prev[i];
|
Game_Session_Player *session_player_prev = &session->players_prev[i];
|
||||||
Game_Session_Player *session_player = &session->players[i];
|
|
||||||
|
|
||||||
bool was_active = session_player_prev->active;
|
bool was_active = session_player_prev->active;
|
||||||
bool is_active = session_player->active;
|
bool is_active = session_player->active;
|
||||||
|
|
||||||
if (!was_active && is_active) {
|
if (!was_active && is_active) {
|
||||||
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
||||||
.type = Simulation_Command_Type_Add_Player,
|
.type = Simulation_Command_Type_Add_Player,
|
||||||
@@ -93,31 +106,57 @@ void game_session_tick(Game_Session *session) {
|
|||||||
.player_id = i
|
.player_id = i
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!session_player->active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if(!session_player->active) {
|
Simulation_Game_Input input = {0};
|
||||||
continue;
|
if(squeue_pop(&session_player->input_queue, &input)) {
|
||||||
}
|
// We got an input.
|
||||||
|
|
||||||
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
simulation_world_enqueue_command(&session->simulation_world, (Simulation_Command) {
|
||||||
.type = Simulation_Command_Type_Set_Player_Input,
|
.type = Simulation_Command_Type_Set_Player_Input,
|
||||||
.player_id = i,
|
.player_id = i,
|
||||||
.player_input = session_player->input,
|
.player_input = input,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tick.
|
|
||||||
simulation_world_tick(&session->simulation_world);
|
|
||||||
|
|
||||||
// Copy 'players' from session to 'players_prev'.
|
|
||||||
memcpy(session->players_prev, session->players, sizeof(Game_Session_Player) * session->settings.max_players);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tick.
|
||||||
|
simulation_world_tick(&session->simulation_world);
|
||||||
|
|
||||||
|
// Copy 'players' from session to 'players_prev'.
|
||||||
|
memcpy(session->players_prev, session->players, sizeof(Game_Session_Player) * session->settings.max_players);
|
||||||
|
}
|
||||||
|
|
||||||
|
void game_session_update(Game_Session *session, const double delta_time) {
|
||||||
|
session->simulation_accumulator += delta_time;
|
||||||
|
|
||||||
|
const double sim_dt = 1.0 / session->settings.tickrate;
|
||||||
|
|
||||||
|
while (session->simulation_accumulator >= sim_dt) {
|
||||||
|
game_session_tick(session);
|
||||||
|
session->simulation_accumulator -= sim_dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Game_Session_Player *game_session_get_player_from_id(Game_Session *session, uint16_t player_index) {
|
||||||
|
assert(session != NULL);
|
||||||
|
if(player_index >= session->settings.max_players) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &session->players[player_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
Game_Session_Player *game_session_get_local_player(Game_Session *session) {
|
Game_Session_Player *game_session_get_local_player(Game_Session *session) {
|
||||||
assert(session != NULL);
|
assert(session != NULL);
|
||||||
return &session->players[session->local_player_index];
|
return game_session_get_player_from_id(session, session->local_player_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index) {
|
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index) {
|
||||||
assert(session != NULL);
|
assert(session != NULL);
|
||||||
|
|
||||||
@@ -126,8 +165,10 @@ bool game_session_create_player(Game_Session *session, uint16_t *out_player_inde
|
|||||||
Game_Session_Player *session_player = &session->players[i];
|
Game_Session_Player *session_player = &session->players[i];
|
||||||
assert(session_player != NULL);
|
assert(session_player != NULL);
|
||||||
if(!session_player->active) {
|
if(!session_player->active) {
|
||||||
session_player->active = true;
|
|
||||||
found_index = i;
|
found_index = i;
|
||||||
|
|
||||||
|
session_player->active = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,4 +189,20 @@ void game_session_destroy_player(Game_Session *session, uint16_t player_index) {
|
|||||||
assert(player->active);
|
assert(player->active);
|
||||||
|
|
||||||
memset(player, 0, sizeof(Game_Session_Player));
|
memset(player, 0, sizeof(Game_Session_Player));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input) {
|
||||||
|
Game_Session_Player *player = game_session_get_player_from_id(session, player_index);
|
||||||
|
assert(player != NULL);
|
||||||
|
|
||||||
|
if(simulation_input_equal(player->most_recent_input, input)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!squeue_push(&player->input_queue, (void *)&input)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->most_recent_input = input;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "shared/squeue.h"
|
||||||
|
|
||||||
#include "simulation/simulation_world.h"
|
#include "simulation/simulation_world.h"
|
||||||
#include "simulation/input.h"
|
#include "simulation/input.h"
|
||||||
#include "simulation/player.h"
|
#include "simulation/player.h"
|
||||||
@@ -11,12 +13,15 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
Simulation_Game_Input input;
|
SQueue input_queue;
|
||||||
|
Simulation_Game_Input most_recent_input; // Exclusively used to make sure that the input-queue doesn't get filled with duplicated inputs.
|
||||||
} Game_Session_Player;
|
} Game_Session_Player;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t seed;
|
uint32_t seed;
|
||||||
|
|
||||||
|
double tickrate;
|
||||||
|
|
||||||
uint16_t level_width;
|
uint16_t level_width;
|
||||||
uint16_t level_height;
|
uint16_t level_height;
|
||||||
|
|
||||||
@@ -32,6 +37,7 @@ typedef struct {
|
|||||||
Game_Session_Settings settings;
|
Game_Session_Settings settings;
|
||||||
|
|
||||||
Simulation_World simulation_world;
|
Simulation_World simulation_world;
|
||||||
|
double simulation_accumulator;
|
||||||
|
|
||||||
Game_Session_Player *players;
|
Game_Session_Player *players;
|
||||||
Game_Session_Player *players_prev;
|
Game_Session_Player *players_prev;
|
||||||
@@ -47,11 +53,14 @@ void game_session_destroy();
|
|||||||
|
|
||||||
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings);
|
void game_session_init_default_settings(bool is_singleplayer, Game_Session_Settings *out_settings);
|
||||||
|
|
||||||
void game_session_tick(Game_Session *session);
|
void game_session_update(Game_Session *session, const double delta_time);
|
||||||
|
|
||||||
Game_Session_Player *game_session_get_local_player(Game_Session *session);
|
Game_Session_Player *game_session_get_local_player(Game_Session *session);
|
||||||
|
|
||||||
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index);
|
bool game_session_create_player(Game_Session *session, uint16_t *out_player_index);
|
||||||
void game_session_destroy_player(Game_Session *session, uint16_t player_index);
|
void game_session_destroy_player(Game_Session *session, uint16_t player_index);
|
||||||
|
|
||||||
|
bool game_session_enqueue_player_input(Game_Session *session, uint16_t player_index, Simulation_Game_Input input);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,10 +2,19 @@
|
|||||||
#define ENTITY_H
|
#define ENTITY_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef uint16_t Entity_ID;
|
typedef uint16_t Entity_ID;
|
||||||
|
|
||||||
#define INVALID_ENTITY_ID Entity_ID(65535)
|
#define INVALID_ENTITY_ID (Entity_ID)65535
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
Entity_Movement_Direction_None,
|
||||||
|
Entity_Movement_Direction_Up,
|
||||||
|
Entity_Movement_Direction_Down,
|
||||||
|
Entity_Movement_Direction_Right,
|
||||||
|
Entity_Movement_Direction_Left,
|
||||||
|
} Entity_Movement_Direction;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Entity_Type_Snake_Head,
|
Entity_Type_Snake_Head,
|
||||||
@@ -14,11 +23,15 @@ typedef enum {
|
|||||||
} Entity_Type;
|
} Entity_Type;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
bool active;
|
||||||
|
|
||||||
Entity_Type type;
|
Entity_Type type;
|
||||||
|
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
|
|
||||||
|
Entity_Movement_Direction move_direction;
|
||||||
|
|
||||||
// TODO: SS - Color/tint?
|
// TODO: SS - Color/tint?
|
||||||
} Entity;
|
} Entity;
|
||||||
|
|
||||||
|
|||||||
@@ -37,38 +37,6 @@ Game_World *game_world_create(uint32_t seed, uint16_t level_width, uint16_t leve
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// { // TODO: SS - Create the level.
|
|
||||||
// {
|
|
||||||
// Grid_Cell *cell = grid_get_cell(&w->grid, 5, 3);
|
|
||||||
// assert(cell != NULL);
|
|
||||||
// cell->entity.type = Entity_Type_Food;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// {
|
|
||||||
// Grid_Cell *cell = grid_get_cell(&w->grid, 11, 4);
|
|
||||||
// assert(cell != NULL);
|
|
||||||
// cell->entity.type = Entity_Type_Food;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// {
|
|
||||||
// Grid_Cell *cell = grid_get_cell(&w->grid, 15, 9);
|
|
||||||
// assert(cell != NULL);
|
|
||||||
// cell->entity.type = Entity_Type_Food;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// {
|
|
||||||
// Grid_Cell *cell = grid_get_cell(&w->grid, 24, 15);
|
|
||||||
// assert(cell != NULL);
|
|
||||||
// cell->entity.type = Entity_Type_Snake_Head;
|
|
||||||
// }
|
|
||||||
// {
|
|
||||||
// Grid_Cell *cell = grid_get_cell(&w->grid, 23, 15);
|
|
||||||
// assert(cell != NULL);
|
|
||||||
// cell->entity.type = Entity_Type_Snake_Body;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,6 +55,8 @@ void game_world_destroy(Game_World *world) {
|
|||||||
bool game_world_create_entity(Game_World *world, Entity_Type type, uint16_t x, uint16_t y, Entity_ID *out_entity_id) {
|
bool game_world_create_entity(Game_World *world, Entity_Type type, uint16_t x, uint16_t y, Entity_ID *out_entity_id) {
|
||||||
assert(world != NULL);
|
assert(world != NULL);
|
||||||
|
|
||||||
|
*out_entity_id = INVALID_ENTITY_ID;
|
||||||
|
|
||||||
if(x >= world->grid.width) {
|
if(x >= world->grid.width) {
|
||||||
printf("Failed to create entity; Invalid x-coordinate.\n");
|
printf("Failed to create entity; Invalid x-coordinate.\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -105,6 +75,7 @@ bool game_world_create_entity(Game_World *world, Entity_Type type, uint16_t x, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
world->entities[id] = (Entity) {
|
world->entities[id] = (Entity) {
|
||||||
|
.active = true,
|
||||||
.type = type,
|
.type = type,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -124,12 +95,13 @@ void game_world_destroy_entity(Game_World *world, Entity_ID entity_id) {
|
|||||||
entity_id
|
entity_id
|
||||||
);
|
);
|
||||||
assert(entity != NULL);
|
assert(entity != NULL);
|
||||||
|
entity->active = false;
|
||||||
|
|
||||||
Grid_Cell *cell = grid_get_cell(&world->grid, entity->x, entity->y);
|
Grid_Cell *cell = grid_get_cell(&world->grid, entity->x, entity->y);
|
||||||
assert(cell != NULL);
|
assert(cell != NULL);
|
||||||
assert(grid_try_remove_entity_from_cell(cell));
|
assert(grid_try_remove_entity_from_cell(cell));
|
||||||
|
|
||||||
squeue_push(&world->entity_id_queue, entity_id);
|
squeue_push(&world->entity_id_queue, (void *)&entity_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *game_world_try_get_entity_by_id(Game_World *world, Entity_ID id) {
|
Entity *game_world_try_get_entity_by_id(Game_World *world, Entity_ID id) {
|
||||||
|
|||||||
@@ -49,8 +49,12 @@ static bool to_grid_index(Grid *grid, uint16_t x, uint16_t y, uint16_t *out_grid
|
|||||||
assert(grid != NULL);
|
assert(grid != NULL);
|
||||||
assert(out_grid_index != NULL);
|
assert(out_grid_index != NULL);
|
||||||
|
|
||||||
if (!grid || !out_grid_index) return false;
|
if(!grid || !out_grid_index) {
|
||||||
if (x >= grid->width || y >= grid->height) return false;
|
return false;
|
||||||
|
}
|
||||||
|
if(x >= grid->width || y >= grid->height) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
*out_grid_index = y * grid->width + x;
|
*out_grid_index = y * grid->width + x;
|
||||||
return true;
|
return true;
|
||||||
@@ -58,7 +62,9 @@ static bool to_grid_index(Grid *grid, uint16_t x, uint16_t y, uint16_t *out_grid
|
|||||||
|
|
||||||
Grid_Cell *grid_get_cell(Grid *grid, uint16_t x, uint16_t y) {
|
Grid_Cell *grid_get_cell(Grid *grid, uint16_t x, uint16_t y) {
|
||||||
assert(grid != NULL);
|
assert(grid != NULL);
|
||||||
if(x >= grid->width || y >= grid->height) return NULL;
|
if(x >= grid->width || y >= grid->height) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t grid_index = 0;
|
uint16_t grid_index = 0;
|
||||||
if(!to_grid_index(grid, x, y, &grid_index)) {
|
if(!to_grid_index(grid, x, y, &grid_index)) {
|
||||||
@@ -98,4 +104,17 @@ bool grid_try_remove_entity_from_cell(Grid_Cell *cell) {
|
|||||||
cell->entity = NULL;
|
cell->entity = NULL;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void grid_move_entity_from_cell_to_cell(Grid_Cell *cell_a, Grid_Cell *cell_b) {
|
||||||
|
assert(cell_a != NULL);
|
||||||
|
assert(cell_b != NULL);
|
||||||
|
|
||||||
|
assert(cell_a->entity != NULL); // We expect cell A to have an Entity to move.
|
||||||
|
assert(cell_b->entity == NULL); // We expect cell B to NOT have an Entity.
|
||||||
|
|
||||||
|
Entity *entity_to_be_moved = cell_a->entity;
|
||||||
|
|
||||||
|
assert(grid_try_remove_entity_from_cell(cell_a));
|
||||||
|
assert(grid_try_add_entity_to_cell(cell_b, entity_to_be_moved));
|
||||||
}
|
}
|
||||||
@@ -28,4 +28,6 @@ Grid_Cell *grid_get_cell(Grid *grid, uint16_t x, uint16_t y);
|
|||||||
bool grid_try_add_entity_to_cell(Grid_Cell *cell, Entity *entity);
|
bool grid_try_add_entity_to_cell(Grid_Cell *cell, Entity *entity);
|
||||||
bool grid_try_remove_entity_from_cell(Grid_Cell *cell);
|
bool grid_try_remove_entity_from_cell(Grid_Cell *cell);
|
||||||
|
|
||||||
|
void grid_move_entity_from_cell_to_cell(Grid_Cell *cell_a, Grid_Cell *cell_b);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
#ifndef QUEUE_H
|
#ifndef SQUEUE_H
|
||||||
#define QUEUE_H
|
#define SQUEUE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
// FIFO.
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *buffer;
|
void *buffer;
|
||||||
uint16_t head;
|
uint16_t head;
|
||||||
|
|||||||
@@ -9,4 +9,21 @@ typedef struct {
|
|||||||
bool left;
|
bool left;
|
||||||
} Simulation_Game_Input;
|
} Simulation_Game_Input;
|
||||||
|
|
||||||
|
static inline bool simulation_input_equal(Simulation_Game_Input a, Simulation_Game_Input b) {
|
||||||
|
if(a.up != b.up) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(a.down != b.down) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(a.right != b.right) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(a.left != b.left) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -45,7 +45,7 @@ void simulation_destroy_world(Simulation_World *simulation_world) {
|
|||||||
void simulation_world_tick(Simulation_World *simulation_world) {
|
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];
|
||||||
@@ -60,14 +60,19 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
assert(!player->active);
|
assert(!player->active);
|
||||||
player->active = true;
|
player->active = true;
|
||||||
|
|
||||||
// TODO: SS - Create entity.
|
|
||||||
assert(game_world_create_entity(
|
assert(game_world_create_entity(
|
||||||
simulation_world->game_world,
|
simulation_world->game_world,
|
||||||
Entity_Type_Snake_Head,
|
Entity_Type_Snake_Head,
|
||||||
10, 15,
|
i+6, 15, // NOTE: SS - Hardcoded spawn-position.
|
||||||
&player->entity_id
|
&player->entity_id
|
||||||
));
|
));
|
||||||
|
|
||||||
|
Entity *player_entity = game_world_try_get_entity_by_id(simulation_world->game_world, player->entity_id);
|
||||||
|
|
||||||
|
// Set initial move-direction for player-entities.
|
||||||
|
// The initial direction should probably take the spawn-position in to account.
|
||||||
|
player_entity->move_direction = Entity_Movement_Direction_Up;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Simulation_Command_Type_Remove_Player: {
|
case Simulation_Command_Type_Remove_Player: {
|
||||||
@@ -89,6 +94,9 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
simulation_world->command_count = 0;
|
simulation_world->command_count = 0;
|
||||||
|
|
||||||
|
|
||||||
|
Game_World *gw = simulation_world->game_world;
|
||||||
|
|
||||||
// Loop over all players in the simulation.
|
// Loop over all players in the simulation.
|
||||||
for(uint16_t i = 0; i < simulation_world->max_players; i++) {
|
for(uint16_t i = 0; i < simulation_world->max_players; i++) {
|
||||||
@@ -102,14 +110,129 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
player->input.up, player->input.down, player->input.right, player->input.left
|
player->input.up, player->input.down, player->input.right, player->input.left
|
||||||
);
|
);
|
||||||
|
|
||||||
Entity *player_entity = game_world_try_get_entity_by_id(simulation_world->game_world, player->entity_id);
|
Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
|
||||||
assert(player_entity != NULL);
|
assert(player_entity != NULL);
|
||||||
|
|
||||||
printf("Entity %i ~ x: %u, y: %u.\n", player->entity_id, player_entity->x, player_entity->y);
|
// 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:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// printf("Entity %i ~ x: %u, y: %u. Move-dir: %i.\n", player->entity_id, player_entity->x, player_entity->y, player_entity->move_direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SS - Game-logic! :)
|
// 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
simulation_world->tick += 1;
|
simulation_world->tick += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user