185 lines
4.5 KiB
C++
185 lines
4.5 KiB
C++
|
/*
|
||
|
|
||
|
Game World simulation management
|
||
|
Entity types
|
||
|
|
||
|
*/
|
||
|
|
||
|
// TOP
|
||
|
|
||
|
// TODO(allen): Check more carefully if this id is safe to use!
|
||
|
inline u16
|
||
|
get_next_entity_id(u16 counter){
|
||
|
u16 next;
|
||
|
switch(counter){
|
||
|
case max_u16: case 0: next = 1; break;
|
||
|
default: next = counter+1; break;
|
||
|
}
|
||
|
return(next);
|
||
|
}
|
||
|
|
||
|
#define freed_slot max_u16
|
||
|
|
||
|
static Entity*
|
||
|
add_entity(World *world){
|
||
|
Entity *entity = 0;
|
||
|
u16 entity_index = 0;
|
||
|
|
||
|
if (world->count < ArrayCount(world->entities)){
|
||
|
entity_index = world->count++;
|
||
|
entity = &world->entities[entity_index];
|
||
|
memset(entity, 0, sizeof(*entity));
|
||
|
|
||
|
entity->entity_id = world->next_id;
|
||
|
world->next_id = get_next_entity_id(world->next_id);
|
||
|
|
||
|
{
|
||
|
Entity_Hash *table = world->hash_slots;
|
||
|
u16 max = ArrayCount(world->hash_slots);
|
||
|
u16 entity_id = entity->entity_id;
|
||
|
u16 hash = entity_id % max;
|
||
|
u16 hash_slot = hash;
|
||
|
|
||
|
while (table[hash_slot].entity_id != 0 &&
|
||
|
table[hash_slot].entity_id != freed_slot){
|
||
|
++hash_slot;
|
||
|
if (hash_slot == max) hash_slot = 0;
|
||
|
Assert(hash_slot != hash);
|
||
|
}
|
||
|
|
||
|
table[hash_slot].entity_id = entity_id;
|
||
|
table[hash_slot].entity_index = entity_index;
|
||
|
entity->hash_slot = hash_slot;
|
||
|
}
|
||
|
|
||
|
entity->seed = random_next_u32(&world->entity_seed_generator);
|
||
|
}
|
||
|
|
||
|
return(entity);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
update_entity_slot(World *world, u16 entity_id, u16 new_entity_index){
|
||
|
Entity_Hash *table = world->hash_slots;
|
||
|
u16 max = ArrayCount(world->hash_slots);
|
||
|
u16 hash = entity_id % max;
|
||
|
u16 hash_slot = hash;
|
||
|
|
||
|
while (table[hash_slot].entity_id != entity_id){
|
||
|
++hash_slot;
|
||
|
if (hash_slot == max) hash_slot = 0;
|
||
|
Assert(hash_slot != hash);
|
||
|
}
|
||
|
|
||
|
table[hash_slot].entity_index = new_entity_index;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
kill_entity(World *world, u16 entity_id){
|
||
|
Entity_Hash *table = world->hash_slots;
|
||
|
u16 max = ArrayCount(world->hash_slots);
|
||
|
u16 hash = entity_id % max;
|
||
|
u16 hash_slot = hash;
|
||
|
|
||
|
while (table[hash_slot].entity_id != entity_id){
|
||
|
++hash_slot;
|
||
|
if (hash_slot == max) hash_slot = 0;
|
||
|
Assert(hash_slot != hash);
|
||
|
}
|
||
|
|
||
|
table[hash_slot].entity_id = freed_slot;
|
||
|
|
||
|
{
|
||
|
Entity *entities = world->entities;
|
||
|
u16 entity_index = table[hash_slot].entity_index;
|
||
|
u16 new_entity_count = world->count-1;
|
||
|
|
||
|
world->count = new_entity_count;
|
||
|
if (entity_index < new_entity_count){
|
||
|
entities[entity_index] = entities[new_entity_count];
|
||
|
update_entity_slot(world, entities[entity_index].entity_id, entity_index);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
world_begin_simulation(World *world){
|
||
|
world->kill_count = 0;
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
world_end_simulation(World *world){
|
||
|
Entity *entities = world->entities;
|
||
|
u16 kill_count = world->kill_count;
|
||
|
u16 *kill_list = world->kill_list;
|
||
|
u16 kill_index = 0;
|
||
|
|
||
|
for (u16 kill_i = 0;
|
||
|
kill_i < kill_count;
|
||
|
++kill_i){
|
||
|
kill_index = kill_list[kill_i];
|
||
|
kill_entity(world, entities[kill_index].entity_id);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
inline void
|
||
|
add_to_kill_list(World *world, Entity *entity){
|
||
|
u16 slot_index = (u16)(entity - world->entities);
|
||
|
Assert(world->kill_count < ArrayCount(world->kill_list));
|
||
|
world->kill_list[world->kill_count++] = slot_index;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static Entity*
|
||
|
add_player(World *world){
|
||
|
Entity *result = add_entity(world);
|
||
|
if (result){
|
||
|
result->type = ET_Player;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
static Entity*
|
||
|
add_asteroid(World *world, i32 lane){
|
||
|
Entity *result = add_entity(world);
|
||
|
if (result){
|
||
|
result->type = ET_Obstacle;
|
||
|
result->x = 25.f;
|
||
|
result->speed = 0.f;
|
||
|
result->lane = lane;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
static Entity*
|
||
|
add_asteroid_spawner(World *world, f32 second_per_spawn){
|
||
|
Entity *result = add_entity(world);
|
||
|
if (result){
|
||
|
result->type = ET_Obstacle_Spawner;
|
||
|
result->second_per_spawn = second_per_spawn;
|
||
|
}
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
static Entity*
|
||
|
get_player(World *world){
|
||
|
Entity *result = 0;
|
||
|
|
||
|
Entity *entity = world->entities;
|
||
|
u32 count = world->count;
|
||
|
for (u32 i = 0;
|
||
|
i < count;
|
||
|
++i, ++entity){
|
||
|
if (entity->type == ET_Player){
|
||
|
result = entity;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(result);
|
||
|
}
|
||
|
|
||
|
// BOTTOM
|
||
|
|