Added Game_World_Player and dying/respawning.
This commit is contained in:
@@ -14,7 +14,6 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint16_t player_id;
|
uint16_t player_id;
|
||||||
SQueue input_queue;
|
SQueue input_queue;
|
||||||
Simulation_Game_Input prev_input; // TODO: SS - Remove this and just peek the queue?
|
|
||||||
} Locally_Controlled_Player;
|
} Locally_Controlled_Player;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -92,21 +92,15 @@ static void state_tick(Presentation_State *state) {
|
|||||||
.left = IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_A)
|
.left = IsKeyPressed(KEY_LEFT) || IsKeyPressed(KEY_A)
|
||||||
};
|
};
|
||||||
|
|
||||||
Locally_Controlled_Player *player = &instance->locally_controlled_players[0];
|
if(!simulation_input_empty(input)) {
|
||||||
|
|
||||||
if(!simulation_input_equal(input, player->prev_input)) {
|
|
||||||
game_instance_push_local_input(instance, 0, input);
|
game_instance_push_local_input(instance, 0, input);
|
||||||
player->prev_input = input;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(instance->amount_of_local_players > 1) {
|
else if(instance->amount_of_local_players > 1) {
|
||||||
for(uint8_t i = 0; i < instance->amount_of_local_players; i++) {
|
for(uint8_t i = 0; i < instance->amount_of_local_players; i++) {
|
||||||
Simulation_Game_Input input = gather_input_for_local_player(i);
|
Simulation_Game_Input input = gather_input_for_local_player(i);
|
||||||
Locally_Controlled_Player *player = &instance->locally_controlled_players[i];
|
if(!simulation_input_empty(input)) {
|
||||||
|
|
||||||
if(!simulation_input_equal(input, player->prev_input)) {
|
|
||||||
game_instance_push_local_input(instance, i, input);
|
game_instance_push_local_input(instance, i, input);
|
||||||
player->prev_input = input;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,12 +115,9 @@ static void state_tick(Presentation_State *state) {
|
|||||||
for(uint16_t i = 0; i < instance->amount_of_local_players; i++) {
|
for(uint16_t i = 0; i < instance->amount_of_local_players; i++) {
|
||||||
// Pop input from local-player's input_queue and set the player's input to it, if we have one.
|
// Pop input from local-player's input_queue and set the player's input to it, if we have one.
|
||||||
Simulation_Game_Input input = {0};
|
Simulation_Game_Input input = {0};
|
||||||
if(game_instance_pop_local_input(instance, i, &input)) {
|
game_instance_pop_local_input(instance, i, &input);
|
||||||
// TODO: SS - We should probably check if this input is invalid for the snake. (pressing "go right" when going left, for example.)
|
|
||||||
// If it is invalid, the next input in the queue should be tried.
|
|
||||||
game_session_set_player_input(session, i, input);
|
game_session_set_player_input(session, i, input);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
game_session_tick(session);
|
game_session_tick(session);
|
||||||
ctx->simulation_accumulator -= sim_dt;
|
ctx->simulation_accumulator -= sim_dt;
|
||||||
@@ -237,8 +228,8 @@ static void state_render(Presentation_State *state) {
|
|||||||
|
|
||||||
Color tint = (Color) { 255, 255, 255, 255 };
|
Color tint = (Color) { 255, 255, 255, 255 };
|
||||||
// Set the snake's tint based on player-index.
|
// Set the snake's tint based on player-index.
|
||||||
for(uint16_t i = 0; i < sim_world->max_players; i++) {
|
for(uint16_t i = 0; i < world->max_players; i++) {
|
||||||
Simulation_Player *player = &sim_world->players[i];
|
Game_World_Player *player = &world->players[i];
|
||||||
if(!player->active) {
|
if(!player->active) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ static void state_render(Presentation_State *state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 1), 128, BUTTON_HEIGHT }, "Cancel")) {
|
if (GuiButton((Rectangle){ 64, 64 + (BUTTON_HEIGHT * 1), 128, BUTTON_HEIGHT }, "Cancel")) {
|
||||||
ctx->mode = ctx->session_settings.max_players == 1 ? Main_Menu_Mode_Home : Main_Menu_Mode_Multiplayer;
|
ctx->mode = Main_Menu_Mode_Home;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ void game_session_init_default_settings(bool online, Game_Session_Settings *out_
|
|||||||
out_settings->seed = 1337; // TODO: SS - Randomize.
|
out_settings->seed = 1337; // TODO: SS - Randomize.
|
||||||
out_settings->online = online;
|
out_settings->online = online;
|
||||||
out_settings->tickrate = 10.0;
|
out_settings->tickrate = 10.0;
|
||||||
out_settings->level_width = 32;
|
out_settings->level_width = 64;
|
||||||
out_settings->level_height = 32;
|
out_settings->level_height = 48;
|
||||||
out_settings->max_players = online ? 8 : 2;
|
out_settings->max_players = online ? 8 : 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,23 @@
|
|||||||
#define MIN_LEVEL_WIDTH 8 // TODO: SS - Move these out of here.
|
#define MIN_LEVEL_WIDTH 8 // TODO: SS - Move these out of here.
|
||||||
#define MIN_LEVEL_HEIGHT 8
|
#define MIN_LEVEL_HEIGHT 8
|
||||||
|
|
||||||
Game_World *game_world_create(uint32_t seed, uint8_t amount_of_food_to_spawn_initially, uint16_t level_width, uint16_t level_height) {
|
Game_World *game_world_create(uint32_t seed, uint16_t max_players, uint16_t level_width, uint16_t level_height) {
|
||||||
assert(level_width >= MIN_LEVEL_WIDTH); // We should probably have failed earlier.
|
assert(level_width >= MIN_LEVEL_WIDTH); // We should probably have failed earlier.
|
||||||
assert(level_height >= MIN_LEVEL_HEIGHT);
|
assert(level_height >= MIN_LEVEL_HEIGHT);
|
||||||
|
|
||||||
Game_World *w = (Game_World *)calloc(1, sizeof(Game_World));
|
Game_World *w = (Game_World *)calloc(1, sizeof(Game_World));
|
||||||
assert(w != NULL);
|
assert(w != NULL);
|
||||||
|
|
||||||
w->seed = seed;
|
w->seed = seed;
|
||||||
random_init(&w->random_generator, w->seed);
|
random_init(&w->random_generator, w->seed);
|
||||||
|
|
||||||
|
w->max_players = max_players;
|
||||||
|
w->players = (Game_World_Player *)calloc(w->max_players, sizeof(Game_World_Player));
|
||||||
|
assert(w->players != NULL);
|
||||||
|
|
||||||
w->max_entities = level_width * level_height;
|
w->max_entities = level_width * level_height;
|
||||||
w->entities = (Entity *)calloc(w->max_entities, sizeof(Entity));
|
w->entities = (Entity *)calloc(w->max_entities, sizeof(Entity));
|
||||||
|
assert(w->entities != NULL);
|
||||||
|
|
||||||
// Set up entity-id queue.
|
// Set up entity-id queue.
|
||||||
assert(squeue_init(&w->entity_id_queue, w->max_entities, sizeof(Entity_ID)));
|
assert(squeue_init(&w->entity_id_queue, w->max_entities, sizeof(Entity_ID)));
|
||||||
@@ -28,8 +34,8 @@ Game_World *game_world_create(uint32_t seed, uint8_t amount_of_food_to_spawn_ini
|
|||||||
|
|
||||||
grid_initialize(&w->grid, level_width, level_height);
|
grid_initialize(&w->grid, level_width, level_height);
|
||||||
|
|
||||||
// Spawn initial food(s).
|
// Spawn initial food(s). One per player.
|
||||||
for(uint16_t i = 0; i < amount_of_food_to_spawn_initially; i++) {
|
for(uint16_t i = 0; i < w->max_players; i++) {
|
||||||
Entity_ID entity_food;
|
Entity_ID entity_food;
|
||||||
|
|
||||||
uint16_t x = 0;
|
uint16_t x = 0;
|
||||||
@@ -51,8 +57,15 @@ void game_world_destroy(Game_World *world) {
|
|||||||
assert(world != NULL);
|
assert(world != NULL);
|
||||||
|
|
||||||
world->seed = 0;
|
world->seed = 0;
|
||||||
|
|
||||||
|
world->max_players = 0;
|
||||||
|
free(world->players);
|
||||||
|
world->players = NULL;
|
||||||
|
|
||||||
world->max_entities = 0;
|
world->max_entities = 0;
|
||||||
free(world->entities);
|
free(world->entities);
|
||||||
|
world->entities = NULL;
|
||||||
|
|
||||||
grid_dispose(&world->grid);
|
grid_dispose(&world->grid);
|
||||||
squeue_free(&world->entity_id_queue);
|
squeue_free(&world->entity_id_queue);
|
||||||
|
|
||||||
@@ -122,6 +135,57 @@ void game_world_destroy_entity(Game_World *world, Entity_ID entity_id, bool dest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void kill_and_respawn_player(Game_World *world, Entity *entity) {
|
||||||
|
assert(world != NULL);
|
||||||
|
assert(entity != NULL);
|
||||||
|
|
||||||
|
// Loop over the players to find the owner of this entity.
|
||||||
|
Game_World_Player *owner_player = NULL;
|
||||||
|
for(uint16_t i = 0; i < world->max_players; i++) {
|
||||||
|
Game_World_Player *player = &world->players[i];
|
||||||
|
if(!player->active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(player->entity_id == entity->id) {
|
||||||
|
owner_player = player;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(owner_player != NULL);
|
||||||
|
|
||||||
|
game_world_destroy_entity(world, entity->id, true);
|
||||||
|
owner_player->entity_id = INVALID_ENTITY_ID;
|
||||||
|
|
||||||
|
{ // Respawn.
|
||||||
|
Entity_ID entity_snake_id;
|
||||||
|
|
||||||
|
uint16_t spawn_x = 0;
|
||||||
|
uint16_t spawn_y = 0;
|
||||||
|
assert(game_world_find_position_to_spawn(world, &spawn_x, &spawn_y));
|
||||||
|
|
||||||
|
assert(game_world_create_entity(
|
||||||
|
world,
|
||||||
|
Entity_Type_Snake_Head,
|
||||||
|
spawn_x, spawn_y,
|
||||||
|
&entity_snake_id
|
||||||
|
));
|
||||||
|
|
||||||
|
owner_player->entity_id = entity_snake_id;
|
||||||
|
|
||||||
|
Entity *player_entity = game_world_try_get_entity_by_id(
|
||||||
|
world,
|
||||||
|
owner_player->entity_id
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set initial move-direction for player-entities.
|
||||||
|
player_entity->move_direction = game_world_choose_initial_move_direction_based_on_coords(
|
||||||
|
world,
|
||||||
|
spawn_x, spawn_y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void game_world_tick(Game_World *world) {
|
void game_world_tick(Game_World *world) {
|
||||||
// Game-logic! :)
|
// Game-logic! :)
|
||||||
|
|
||||||
@@ -133,23 +197,6 @@ void game_world_tick(Game_World *world) {
|
|||||||
|
|
||||||
switch(entity->type) {
|
switch(entity->type) {
|
||||||
case Entity_Type_Snake_Head: {
|
case Entity_Type_Snake_Head: {
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Entity_Type_Snake_Body: {
|
|
||||||
// Skip.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case Entity_Type_Food: {
|
|
||||||
// Skip (for now).
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
printf("Unhandled entity-type %i.\n", entity->type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{ // Move entity
|
{ // Move entity
|
||||||
int16_t dx = 0;
|
int16_t dx = 0;
|
||||||
int16_t dy = 0;
|
int16_t dy = 0;
|
||||||
@@ -184,21 +231,19 @@ void game_world_tick(Game_World *world) {
|
|||||||
assert(current_cell != NULL);
|
assert(current_cell != NULL);
|
||||||
Grid_Cell *target_cell = grid_get_cell(&world->grid, entity->x + dx, entity->y + dy);
|
Grid_Cell *target_cell = grid_get_cell(&world->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) {
|
if(target_cell == NULL) {
|
||||||
// Target cell does not exist.
|
// Target cell does not exist.
|
||||||
|
|
||||||
// TODO: SS - Check the session's settings.
|
// TODO: SS - Check the session's settings.
|
||||||
// Maybe each session could decide whether the snake should "loop-around" or not.
|
// Maybe each session could decide whether the snake should "loop-around" or not.
|
||||||
// If the snake shouldn't loop around, die.
|
// If the snake shouldn't loop around, die. For now, we say that it's not okay to loop around.
|
||||||
|
bool should_loop_around = false;
|
||||||
|
if(should_loop_around) {
|
||||||
|
// TODO: SS - Implement looping around.
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
kill_and_respawn_player(world, entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
bool should_move_to_target_cell = false;
|
bool should_move_to_target_cell = false;
|
||||||
@@ -210,11 +255,11 @@ void game_world_tick(Game_World *world) {
|
|||||||
// Check what type of entity it is and determine what should happen.
|
// Check what type of entity it is and determine what should happen.
|
||||||
switch(target_cell->entity->type) {
|
switch(target_cell->entity->type) {
|
||||||
case Entity_Type_Snake_Head: {
|
case Entity_Type_Snake_Head: {
|
||||||
// TODO: SS - Die.
|
kill_and_respawn_player(world, entity);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Entity_Type_Snake_Body: {
|
case Entity_Type_Snake_Body: {
|
||||||
// TODO: SS - Die.
|
kill_and_respawn_player(world, entity);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Entity_Type_Food: {
|
case Entity_Type_Food: {
|
||||||
@@ -290,9 +335,57 @@ void game_world_tick(Game_World *world) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Type_Snake_Body: {
|
||||||
|
// Skip.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Type_Food: {
|
||||||
|
// Skip (for now).
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
printf("Unhandled entity-type %i.\n", entity->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool game_world_add_player(Game_World *world, Game_World_Player **out_gw_player) {
|
||||||
|
assert(world != NULL);
|
||||||
|
assert(out_gw_player != NULL);
|
||||||
|
|
||||||
|
for(uint16_t i = 0; i < world->max_players; i++) {
|
||||||
|
Game_World_Player *player = &world->players[i];
|
||||||
|
|
||||||
|
if(player->active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Found free player.
|
||||||
|
player->active = true;
|
||||||
|
*out_gw_player = player;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool game_world_remove_player(Game_World *world, Game_World_Player *player) {
|
||||||
|
assert(world != NULL);
|
||||||
|
assert(player != NULL);
|
||||||
|
|
||||||
|
game_world_destroy_entity(world, player->entity_id, true);
|
||||||
|
|
||||||
|
memset(player, 0, sizeof(Game_World_Player));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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) {
|
||||||
assert(world != NULL);
|
assert(world != NULL);
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,15 @@
|
|||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "shared/squeue.h"
|
#include "shared/squeue.h"
|
||||||
#include "shared/random.h"
|
#include "shared/random.h"
|
||||||
|
#include "game_world_player.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t seed;
|
uint32_t seed;
|
||||||
Random_Generator random_generator;
|
Random_Generator random_generator;
|
||||||
|
|
||||||
|
Game_World_Player *players;
|
||||||
|
uint16_t max_players;
|
||||||
|
|
||||||
SQueue entity_id_queue;
|
SQueue entity_id_queue;
|
||||||
Entity *entities;
|
Entity *entities;
|
||||||
uint16_t max_entities;
|
uint16_t max_entities;
|
||||||
@@ -19,7 +23,7 @@ typedef struct {
|
|||||||
|
|
||||||
} Game_World;
|
} Game_World;
|
||||||
|
|
||||||
Game_World *game_world_create(uint32_t seed, uint8_t amount_of_food_to_spawn_initially, uint16_t level_width, uint16_t level_height);
|
Game_World *game_world_create(uint32_t seed, uint16_t max_players, uint16_t level_width, uint16_t level_height);
|
||||||
void game_world_destroy(Game_World *world);
|
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);
|
||||||
@@ -27,7 +31,8 @@ void game_world_destroy_entity(Game_World *world, Entity_ID entity_id, bool dest
|
|||||||
|
|
||||||
void game_world_tick(Game_World *world);
|
void game_world_tick(Game_World *world);
|
||||||
|
|
||||||
// TODO: SS - "void game_world_spawn_player(Game_World *world, ..)"
|
bool game_world_add_player(Game_World *world, Game_World_Player **out_gw_player);
|
||||||
|
bool game_world_remove_player(Game_World *world, Game_World_Player *player);
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
|
|||||||
10
src/game/shared/game_world_player.h
Normal file
10
src/game/shared/game_world_player.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef GAME_WORLD_PLAYER_H
|
||||||
|
#define GAME_WORLD_PLAYER_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool active;
|
||||||
|
|
||||||
|
Entity_ID entity_id; // The entity that this player is controlling. Can be INVALID_ENTITY_ID.
|
||||||
|
} Game_World_Player;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -6,11 +6,11 @@ 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) {
|
static inline bool simulation_input_empty(Simulation_Game_Input input) {
|
||||||
if(a.right != b.right) {
|
if(input.right) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(a.left != b.left) {
|
if(input.left) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,10 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
Entity_ID entity_id;
|
Game_World_Player *game_world_player;
|
||||||
|
|
||||||
Simulation_Game_Input input;
|
Simulation_Game_Input input;
|
||||||
|
|
||||||
// score, name etc.
|
// score, name etc.
|
||||||
|
|
||||||
} Simulation_Player;
|
} Simulation_Player;
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ Simulation_World simulation_create_world(uint32_t seed, bool online, uint8_t max
|
|||||||
|
|
||||||
w.online = online;
|
w.online = online;
|
||||||
|
|
||||||
uint16_t amount_of_food_to_spawn_initially = max_players; // NOTE: SS - One per player. Might change and/or be customizable.
|
w.game_world = game_world_create(seed, max_players, width, height);
|
||||||
w.game_world = game_world_create(seed, amount_of_food_to_spawn_initially, width, height);
|
|
||||||
assert(w.game_world != NULL);
|
assert(w.game_world != NULL);
|
||||||
|
|
||||||
w.match_state = Simulation_Match_State_Waiting_To_Start;
|
w.match_state = Simulation_Match_State_Waiting_To_Start;
|
||||||
@@ -50,6 +49,9 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
|
|
||||||
// printf("TICK: %lu.\n", simulation_world->tick);
|
// printf("TICK: %lu.\n", simulation_world->tick);
|
||||||
|
|
||||||
|
Game_World *gw = simulation_world->game_world;
|
||||||
|
assert(gw != NULL);
|
||||||
|
|
||||||
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);
|
||||||
@@ -63,8 +65,9 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
assert(!player->active);
|
assert(!player->active);
|
||||||
player->active = true;
|
player->active = true;
|
||||||
|
|
||||||
Game_World *gw = simulation_world->game_world;
|
assert(game_world_add_player(gw, &player->game_world_player));
|
||||||
assert(gw != NULL);
|
|
||||||
|
Game_World_Player *gwp = player->game_world_player;
|
||||||
|
|
||||||
uint16_t spawn_x = 0;
|
uint16_t spawn_x = 0;
|
||||||
uint16_t spawn_y = 0;
|
uint16_t spawn_y = 0;
|
||||||
@@ -74,10 +77,10 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
gw,
|
gw,
|
||||||
Entity_Type_Snake_Head,
|
Entity_Type_Snake_Head,
|
||||||
spawn_x, spawn_y,
|
spawn_x, spawn_y,
|
||||||
&player->entity_id
|
&gwp->entity_id
|
||||||
));
|
));
|
||||||
|
|
||||||
Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
|
Entity *player_entity = game_world_try_get_entity_by_id(gw, gwp->entity_id);
|
||||||
|
|
||||||
// Set initial move-direction for player-entities.
|
// Set initial move-direction for player-entities.
|
||||||
player_entity->move_direction = game_world_choose_initial_move_direction_based_on_coords(
|
player_entity->move_direction = game_world_choose_initial_move_direction_based_on_coords(
|
||||||
@@ -92,8 +95,7 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
assert(player->active);
|
assert(player->active);
|
||||||
player->active = false;
|
player->active = false;
|
||||||
|
|
||||||
game_world_destroy_entity(simulation_world->game_world, player->entity_id, true);
|
assert(game_world_remove_player(gw, player->game_world_player));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Simulation_Command_Type_Set_Player_Input: {
|
case Simulation_Command_Type_Set_Player_Input: {
|
||||||
@@ -136,8 +138,14 @@ void simulation_world_tick(Simulation_World *simulation_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++) {
|
||||||
Simulation_Player *player = &simulation_world->players[i];
|
Simulation_Player *sim_player = &simulation_world->players[i];
|
||||||
if(!player->active) {
|
if(!sim_player->active) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Game_World_Player *gw_player = sim_player->game_world_player;
|
||||||
|
assert(gw_player != NULL);
|
||||||
|
if(!gw_player->active) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,13 +156,16 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
// player->input.right, player->input.left
|
// player->input.right, player->input.left
|
||||||
// );
|
// );
|
||||||
|
|
||||||
Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
|
Entity *player_entity = game_world_try_get_entity_by_id(gw, gw_player->entity_id);
|
||||||
assert(player_entity != NULL);
|
if(player_entity == NULL) {
|
||||||
|
// No entity to control. No entity to apply input on.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Snakes can't go backwards. They have to turn.
|
// Snakes can't go backwards. They have to turn.
|
||||||
|
|
||||||
// We only have input 'right' and 'up'.
|
// We only have input 'right' and 'up'.
|
||||||
Simulation_Game_Input input = player->input;
|
Simulation_Game_Input input = sim_player->input;
|
||||||
|
|
||||||
// Turn relative to the player's current move_direction.
|
// Turn relative to the player's current move_direction.
|
||||||
switch(player_entity->move_direction) {
|
switch(player_entity->move_direction) {
|
||||||
|
|||||||
@@ -6,12 +6,12 @@
|
|||||||
- Right now it's only considering the size of of the grid, but what if we want to have obstacles in the grid?
|
- Right now it's only considering the size of of the grid, but what if we want to have obstacles in the grid?
|
||||||
- We also don't take if two players spawn one cell from each other in to consideration.
|
- We also don't take if two players spawn one cell from each other in to consideration.
|
||||||
- Add player-death.
|
- Add player-death.
|
||||||
- [ ] Went out of bounds.
|
- [x] Went out of bounds.
|
||||||
- [ ] Hit other snake's head.
|
- [x] Hit other snake's head.
|
||||||
- [ ] Hit yours/other snake's body.
|
- [x] Hit yours/other snake's body.
|
||||||
- Spawn players at a random position.
|
- Spawn players at a random position.
|
||||||
- [x] When initially joining.
|
- [x] When initially joining.
|
||||||
- [ ] When dead and should respawn.
|
- [x] When dead and should respawn.
|
||||||
- [x] Spawn a new food when one was eaten.
|
- [x] Spawn a new food when one was eaten.
|
||||||
- [x] When a player disconnects, all children should recursively be destroyed too. Not just the head.
|
- [x] When a player disconnects, all children should recursively be destroyed too. Not just the head.
|
||||||
- [ ] Send networked input.
|
- [ ] Send networked input.
|
||||||
|
|||||||
Reference in New Issue
Block a user