/* 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