Body-part now follows it's parent. You can also eat food. Shortcut in the main-menu to play default singleplayer, press P.
This commit is contained in:
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "session/game_session.h"
|
#include "session/game_session.h"
|
||||||
|
|
||||||
|
#include "shared/wang_hash.h"
|
||||||
|
|
||||||
#define GRID_CELL_SIZE 8
|
#define GRID_CELL_SIZE 8
|
||||||
#define ENTITY_PRESENTATION_Y_OFFSET -2
|
#define ENTITY_PRESENTATION_Y_OFFSET -2
|
||||||
|
|
||||||
@@ -84,6 +86,10 @@ static void state_tick(Presentation_State *state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t floor_texture_variant(uint32_t x, uint32_t y, uint32_t seed, uint32_t num_variants) {
|
||||||
|
return (wang_hash(x * 73856093u ^ y * 19349663u ^ seed)) % num_variants;
|
||||||
|
}
|
||||||
|
|
||||||
static void state_render(Presentation_State *state) {
|
static void state_render(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;
|
||||||
@@ -108,7 +114,7 @@ static void state_render(Presentation_State *state) {
|
|||||||
uint32_t pres_x = x * GRID_CELL_SIZE;
|
uint32_t pres_x = x * GRID_CELL_SIZE;
|
||||||
uint32_t pres_y = y * GRID_CELL_SIZE;
|
uint32_t pres_y = y * GRID_CELL_SIZE;
|
||||||
|
|
||||||
uint32_t random_floor_index = i; // TODO: SS - Get a deterministic random value based on seed.
|
uint32_t random_floor_index = floor_texture_variant(x, y, world->seed, 4);
|
||||||
|
|
||||||
DrawTextureRec(
|
DrawTextureRec(
|
||||||
ctx->texture_grass,
|
ctx->texture_grass,
|
||||||
@@ -116,7 +122,7 @@ static void state_render(Presentation_State *state) {
|
|||||||
(Vector2) { pres_x, pres_y },
|
(Vector2) { pres_x, pres_y },
|
||||||
WHITE
|
WHITE
|
||||||
);
|
);
|
||||||
DrawRectangleLines(pres_x, pres_y, GRID_CELL_SIZE, GRID_CELL_SIZE, (Color) { 0, 0, 0, 8 });
|
DrawRectangleLines(pres_x, pres_y, GRID_CELL_SIZE, GRID_CELL_SIZE, (Color) { 0, 0, 0, 2 }); // TODO: SS - Let the user customize the alpha locally.
|
||||||
}
|
}
|
||||||
|
|
||||||
for(uint32_t i = 0; i < grid_total_size; i++) {
|
for(uint32_t i = 0; i < grid_total_size; i++) {
|
||||||
@@ -159,6 +165,30 @@ static void state_render(Presentation_State *state) {
|
|||||||
(Color) { 0, 0, 0, 32 }
|
(Color) { 0, 0, 0, 32 }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
float rotation = 0.0f;
|
||||||
|
switch(entity->move_direction){
|
||||||
|
case Entity_Movement_Direction_None: {
|
||||||
|
rotation = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Movement_Direction_Up: {
|
||||||
|
rotation = -90.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Movement_Direction_Down: {
|
||||||
|
rotation = 90.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Movement_Direction_Right: {
|
||||||
|
rotation = 0.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Entity_Movement_Direction_Left: {
|
||||||
|
rotation = 180.0f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DrawTexturePro(
|
DrawTexturePro(
|
||||||
*texture,
|
*texture,
|
||||||
(Rectangle) { // Source.
|
(Rectangle) { // Source.
|
||||||
@@ -171,7 +201,7 @@ static void state_render(Presentation_State *state) {
|
|||||||
GRID_CELL_SIZE
|
GRID_CELL_SIZE
|
||||||
},
|
},
|
||||||
origin, // Origin.
|
origin, // Origin.
|
||||||
0, // Rotation.
|
rotation, // Rotation.
|
||||||
tint // Tint.
|
tint // Tint.
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,23 @@ static void state_enter(Presentation_State *state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void state_tick(Presentation_State *state) {
|
static void state_tick(Presentation_State *state) {
|
||||||
(void)state;
|
Presentation_State_Main_Menu_Context *ctx = (Presentation_State_Main_Menu_Context *)state->context;
|
||||||
|
|
||||||
|
{ // DEBUG
|
||||||
|
if(IsKeyPressed(KEY_P)) {
|
||||||
|
ctx->is_singleplayer = true;
|
||||||
|
ctx->mode = Main_Menu_Mode_Game_Setup;
|
||||||
|
game_session_init_default_settings(ctx->is_singleplayer, &ctx->session_settings);
|
||||||
|
|
||||||
|
game_session_create(
|
||||||
|
ctx->is_singleplayer,
|
||||||
|
!ctx->is_singleplayer,
|
||||||
|
ctx->session_settings
|
||||||
|
);
|
||||||
|
|
||||||
|
presentation_state_machine_go_to(&presentation_state_ingame);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void state_render(Presentation_State *state) {
|
static void state_render(Presentation_State *state) {
|
||||||
|
|||||||
@@ -25,12 +25,17 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
bool active;
|
bool active;
|
||||||
|
|
||||||
|
// TODO: SS - Maybe add an ID here.
|
||||||
|
|
||||||
Entity_Type type;
|
Entity_Type type;
|
||||||
|
|
||||||
uint16_t x;
|
uint16_t x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
|
|
||||||
Entity_Movement_Direction move_direction;
|
Entity_Movement_Direction move_direction;
|
||||||
|
Entity_Movement_Direction prev_move_direction;
|
||||||
|
|
||||||
|
Entity_ID child;
|
||||||
|
|
||||||
// TODO: SS - Color/tint?
|
// TODO: SS - Color/tint?
|
||||||
} Entity;
|
} Entity;
|
||||||
|
|||||||
@@ -66,10 +66,8 @@ bool game_world_create_entity(Game_World *world, Entity_Type type, uint16_t x, u
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Entity_ID id = 0;
|
Entity_ID id = 0;
|
||||||
bool got_id = squeue_pop(&world->entity_id_queue, (void *)&id);
|
if(!squeue_pop(&world->entity_id_queue, (void *)&id)) {
|
||||||
if(!got_id) {
|
|
||||||
printf("No free entity ids.\n");
|
printf("No free entity ids.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -77,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,
|
.active = true,
|
||||||
.type = type,
|
.type = type,
|
||||||
|
.child = INVALID_ENTITY_ID
|
||||||
};
|
};
|
||||||
|
|
||||||
Grid_Cell *cell = grid_get_cell(&world->grid, x, y); // TEMP: SS - Hardcoded coordinates. // TODO: SS - Find good coordinate.
|
Grid_Cell *cell = grid_get_cell(&world->grid, x, y); // TEMP: SS - Hardcoded coordinates. // TODO: SS - Find good coordinate.
|
||||||
|
|||||||
34
src/shared/random.h
Normal file
34
src/shared/random.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef RANDOM_H
|
||||||
|
#define RANDOM_H
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t seed;
|
||||||
|
uint32_t state;
|
||||||
|
} Random_Generator;
|
||||||
|
|
||||||
|
static inline void random_init(Random_Generator *random_generator, uint32_t seed) {
|
||||||
|
if(seed == 0) {
|
||||||
|
seed = 1;
|
||||||
|
}
|
||||||
|
random_generator->seed = seed;
|
||||||
|
random_generator->state = random_generator->seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t random_next_u32(Random_Generator *random_generator) {
|
||||||
|
uint32_t x = random_generator->state;
|
||||||
|
|
||||||
|
x ^= x << 13;
|
||||||
|
x ^= x >> 17;
|
||||||
|
x ^= x << 5;
|
||||||
|
|
||||||
|
random_generator->state = x;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t random_u64_range(Random_Generator *random_generator, uint32_t min, uint32_t max) {
|
||||||
|
return min + (random_next_u32(rng) % (max - min + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
13
src/shared/wang_hash.h
Normal file
13
src/shared/wang_hash.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef WANG_HASH_H
|
||||||
|
#define WANG_HASH_H
|
||||||
|
|
||||||
|
static inline uint32_t wang_hash(uint32_t v) {
|
||||||
|
v = (v ^ 61) ^ (v >> 16);
|
||||||
|
v = v + (v << 3);
|
||||||
|
v = v ^ (v >> 4);
|
||||||
|
v = v * 0x27d4eb2d;
|
||||||
|
v = v ^ (v >> 15);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -181,7 +181,34 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch(entity->type) {
|
||||||
|
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 entities.
|
{ // Move entities.
|
||||||
|
// Entity *entity_to_follow = entity;
|
||||||
|
// if(entity->parent != INVALID_ENTITY_ID) {
|
||||||
|
// entity_to_follow = game_world_try_get_entity_by_id(gw, entity->parent);
|
||||||
|
// assert(entity_to_follow != NULL);
|
||||||
|
|
||||||
|
// entity->move_direction = entity_to_follow->prev_move_direction;
|
||||||
|
// }
|
||||||
|
|
||||||
int16_t dx = 0;
|
int16_t dx = 0;
|
||||||
int16_t dy = 0;
|
int16_t dy = 0;
|
||||||
|
|
||||||
@@ -207,11 +234,14 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entity->prev_move_direction = entity->move_direction;
|
||||||
|
|
||||||
if(dx != 0 || dy != 0) {
|
if(dx != 0 || dy != 0) {
|
||||||
// Try moving.
|
// Try moving.
|
||||||
|
|
||||||
// Figure out what cell we're on and what cell we want to go to.
|
// 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);
|
Grid_Cell *current_cell = grid_get_cell(&gw->grid, entity->x, entity->y);
|
||||||
|
Grid_Cell *start_cell = current_cell;
|
||||||
assert(current_cell != NULL);
|
assert(current_cell != NULL);
|
||||||
Grid_Cell *target_cell = grid_get_cell(&gw->grid, entity->x + dx, entity->y + dy);
|
Grid_Cell *target_cell = grid_get_cell(&gw->grid, entity->x + dx, entity->y + dy);
|
||||||
|
|
||||||
@@ -227,9 +257,14 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
|
|
||||||
if(target_cell == NULL) {
|
if(target_cell == NULL) {
|
||||||
// Target cell does not exist.
|
// Target cell does not exist.
|
||||||
// TODO: SS - Die.
|
// TODO: SS - Check the session's settings.
|
||||||
|
// Maybe each session could decide whether the snake should "loop-around" or not.
|
||||||
|
// If the snake shouldn't loop around, die.
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
bool should_move_to_target_cell = false;
|
||||||
|
bool snake_should_grow = false;
|
||||||
|
|
||||||
if(target_cell->entity != NULL) {
|
if(target_cell->entity != NULL) {
|
||||||
// Target cell is occupied.
|
// Target cell is occupied.
|
||||||
|
|
||||||
@@ -244,14 +279,49 @@ void simulation_world_tick(Simulation_World *simulation_world) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Entity_Type_Food: {
|
case Entity_Type_Food: {
|
||||||
// TODO: SS - Eat!
|
// Eat!
|
||||||
|
assert(grid_try_remove_entity_from_cell(target_cell));
|
||||||
|
|
||||||
|
snake_should_grow = true;
|
||||||
|
should_move_to_target_cell = true;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Target cell is unoccupied and free to enter.
|
// Target cell is unoccupied and free to enter.
|
||||||
grid_move_entity_from_cell_to_cell(current_cell, target_cell);
|
should_move_to_target_cell = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(should_move_to_target_cell) {
|
||||||
|
{ // Move snake recursively.
|
||||||
|
Entity *e = entity;
|
||||||
|
Grid_Cell *t = target_cell;
|
||||||
|
while(e != NULL) {
|
||||||
|
Grid_Cell *a = grid_get_cell(&gw->grid, e->x, e->y);
|
||||||
|
assert(a != NULL);
|
||||||
|
|
||||||
|
grid_move_entity_from_cell_to_cell(a, t);
|
||||||
|
|
||||||
|
e = game_world_try_get_entity_by_id(gw, e->child);
|
||||||
|
t = a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// // TODO: SS - Recurse through this entity's children and move them too.
|
||||||
|
// if(entity->child != INVALID_ENTITY_ID) {
|
||||||
|
// printf("TODO: SS - MOVE CHILDREN TOO!\n");
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
if(snake_should_grow) {
|
||||||
|
// TODO: SS - Spawn the entity and make it a child of the snake's last child.
|
||||||
|
Entity_ID child_entity = INVALID_ENTITY_ID;
|
||||||
|
assert(game_world_create_entity(gw, Entity_Type_Snake_Body, start_cell->x, start_cell->y, &child_entity));
|
||||||
|
|
||||||
|
assert(entity->child == INVALID_ENTITY_ID);
|
||||||
|
entity->child = child_entity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user