diff --git a/code/game/header/world/blocks.h b/code/game/header/world/blocks.h index 227fc39..6964068 100644 --- a/code/game/header/world/blocks.h +++ b/code/game/header/world/blocks.h @@ -19,6 +19,7 @@ char blocks_get_symbol(uint8_t id); uint32_t blocks_get_flags(uint8_t id); uint32_t blocks_get_biome(uint8_t id); uint32_t blocks_get_kind(uint8_t id); +float blocks_get_drag(uint8_t id); // NOTE(zaklaus): viewer-related functions void *blocks_get_img(uint8_t id); diff --git a/code/game/source/entity.c b/code/game/source/entity.c index 2a22108..1a6abbc 100644 --- a/code/game/source/entity.c +++ b/code/game/source/entity.c @@ -28,8 +28,8 @@ uint64_t entity_spawn(char *name) { pos->x=rand() % world_dim(); pos->y=rand() % world_dim(); #else - pos->x=35; - pos->y=33; + pos->x=350; + pos->y=88; #endif diff --git a/code/game/source/main.c b/code/game/source/main.c index a81ec2c..1873f80 100644 --- a/code/game/source/main.c +++ b/code/game/source/main.c @@ -49,7 +49,7 @@ int main(int argc, char** argv) { uint16_t num_viewers = zpl_opts_integer(&opts, "viewer-count", 1); uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE); uint16_t world_size = zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE); - uint32_t npc_count = zpl_opts_integer(&opts, "npc-count", 1000); + uint32_t npc_count = zpl_opts_integer(&opts, "npc-count", 10000); if (zpl_opts_has_arg(&opts, "random-seed")) { zpl_random rnd={0}; diff --git a/code/game/source/world/blocks.c b/code/game/source/world/blocks.c index 8f4c84b..682fd3f 100644 --- a/code/game/source/world/blocks.c +++ b/code/game/source/world/blocks.c @@ -23,6 +23,7 @@ typedef struct { uint32_t kind; uint32_t biome; char symbol; + float drag; // NOTE(zaklaus): viewer data Texture2D img; @@ -77,6 +78,10 @@ uint32_t blocks_get_kind(uint8_t id) { return blocks[id].kind; } +float blocks_get_drag(uint8_t id) { + return blocks[id].drag; +} + void *blocks_get_img(uint8_t id) { return (void*)&blocks[id].img; } diff --git a/code/game/source/world/blocks_list.c b/code/game/source/world/blocks_list.c index 79e3c22..6bc356b 100644 --- a/code/game/source/world/blocks_list.c +++ b/code/game/source/world/blocks_list.c @@ -1,10 +1,10 @@ #include "world/blocks.h" static block blocks[] = { - {.name = "base-ground", .flags = 0, .kind = BLOCK_KIND_GROUND, .biome = 0, .symbol = '.'}, - {.name = "base-dirt", .flags = 0, .kind = BLOCK_KIND_DIRT, .biome = 0, .symbol = ','}, - {.name = "base-wall", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_WALL, .biome = 0, .symbol = '#'}, - {.name = "base-hill", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL, .biome = 0, .symbol = '^'}, - {.name = "base-hill-snow", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL_SNOW, .biome = 0, .symbol = '*'}, - {.name = "base-water", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~'}, + {.name = "base-ground", .flags = 0, .kind = BLOCK_KIND_GROUND, .biome = 0, .symbol = '.', .drag = 1.0f}, + {.name = "base-dirt", .flags = 0, .kind = BLOCK_KIND_DIRT, .biome = 0, .symbol = ',', .drag = 4.0f }, + {.name = "base-wall", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_WALL, .biome = 0, .symbol = '#', .drag = 1.0f }, + {.name = "base-hill", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL, .biome = 0, .symbol = '^', .drag = 1.0f }, + {.name = "base-hill-snow", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL_SNOW, .biome = 0, .symbol = '*', .drag = 1.0f }, + {.name = "base-water", .flags = 0, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~', .drag = 0.11f }, }; diff --git a/code/game/source/world/world.c b/code/game/source/world/world.c index ffc5fb9..6f55d81 100644 --- a/code/game/source/world/world.c +++ b/code/game/source/world/world.c @@ -155,11 +155,10 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) { world.block_mapping[i] = zpl_malloc(sizeof(uint8_t)*zpl_square(chunk_size)); chunk->id = i; - for (int y = 0; y < world.chunk_size; y += 1) { - for (int x = 0; x < world.chunk_size; x += 1) { - int chk = world.chunk_size * i; - int chk_x = chk % world.dim; - int chk_y = chk / world.dim; + for (int y = 0; y < chunk_size; y += 1) { + for (int x = 0; x < chunk_size; x += 1) { + int chk_x = chunk->x * chunk_size; + int chk_y = chunk->y * chunk_size; uint8_t *c = &world.block_mapping[i][(y*chunk_size)+x]; *c = world.data[(chk_y+y)*world.dim + (chk_x+x)]; } diff --git a/code/game/source/world/worldgen/worldgen_test.c b/code/game/source/world/worldgen/worldgen_test.c index 5949bad..f824eff 100644 --- a/code/game/source/world/worldgen/worldgen_test.c +++ b/code/game/source/world/worldgen/worldgen_test.c @@ -10,8 +10,8 @@ #define WORLD_BLOCK_OBSERVER(name) uint8_t name(uint8_t id, uint32_t block_idx) typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc); -#define WORLD_PERLIN_FREQ 9.34157f -#define WORLD_PERLIN_OCTAVES 4 +#define WORLD_PERLIN_FREQ 100 +#define WORLD_PERLIN_OCTAVES 1 static world_data *world; @@ -83,7 +83,7 @@ static uint8_t world_perlin_cond(uint32_t block_idx, double chance) { uint32_t x = block_idx % world->dim; uint32_t y = block_idx / world->dim; - return perlin_fbm(world->seed, x+rand()%world->dim, y+rand()%world->dim, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance; + return perlin_fbm(world->seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance; } #if 1 @@ -138,11 +138,11 @@ int32_t worldgen_test(world_data *wld) { // ground world_fill_rect(grnd_id, 1, 1, world->dim-2, world->dim-2, NULL); - world_fill_rect(dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise50); + world_fill_rect(dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise33); // water #if 1 - for (int i=0; idim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); } #endif diff --git a/code/modules/modules/physics.h b/code/modules/modules/physics.h index 4342f66..f9b4c2f 100644 --- a/code/modules/modules/physics.h +++ b/code/modules/modules/physics.h @@ -14,6 +14,7 @@ typedef struct { ECS_DECLARE_ENTITY(MoveWalk); ECS_DECLARE_ENTITY(UpdateTrackerPos); ECS_DECLARE_ENTITY(IntegratePositions); + ECS_DECLARE_ENTITY(PushOutOverlappingEntities); } Physics; #define PhysicsImportHandles(handles)\ @@ -24,5 +25,6 @@ ECS_IMPORT_COMPONENT(handles, Velocity);\ ECS_IMPORT_ENTITY(handles, MoveWalk);\ ECS_IMPORT_ENTITY(handles, UpdateTrackerPos);\ ECS_IMPORT_ENTITY(handles, IntegratePositions);\ +ECS_IMPORT_ENTITY(handles, PushOutOverlappingEntities);\ void PhysicsImport(ecs_world_t *ecs); diff --git a/code/modules/source/controllers.c b/code/modules/source/controllers.c index 3631d78..1e0a8b7 100644 --- a/code/modules/source/controllers.c +++ b/code/modules/source/controllers.c @@ -21,7 +21,7 @@ void MovementImpulse(ecs_iter_t *it) { } #define DEMO_NPC_CHANGEDIR_FACTOR 0.1 -#define DEMO_NPC_MOVE_SPEED 1000 +#define DEMO_NPC_MOVE_SPEED 1500 void DemoNPCMoveAround(ecs_iter_t *it) { Velocity *v = ecs_column(it, Velocity, 1); @@ -47,8 +47,8 @@ void ControllersImport(ecs_world_t *ecs) { ECS_TAG(ecs, EcsBuilder); ECS_TAG(ecs, EcsDemoNPC); - ECS_SYSTEM(ecs, MovementImpulse, EcsOnUpdate, Input, physics.Velocity); - ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnUpdate, physics.Velocity, EcsDemoNPC); + ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, Input, physics.Velocity); + ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, physics.Velocity, EcsDemoNPC); ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor); ECS_TYPE(ecs, Player, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Walking, EcsActor, EcsPlayer); diff --git a/code/modules/source/physics.c b/code/modules/source/physics.c index 317755f..2975038 100644 --- a/code/modules/source/physics.c +++ b/code/modules/source/physics.c @@ -11,11 +11,14 @@ #define PHY_CORRECTION(x) ((zpl_max(0.0f, (WORLD_BLOCK_SIZE/2.0f) - zpl_abs(x))*zpl_sign(x)))*(WORLD_BLOCK_SIZE/2.0f) void MoveWalk(ecs_iter_t *it) { - Velocity *v = ecs_column(it, Velocity, 1); + Position *p = ecs_column(it, Position, 1); + Velocity *v = ecs_column(it, Velocity, 2); for (int i = 0; i < it->count; i++) { - v[i].x = zpl_lerp(v[i].x, 0.0f, PHY_WALK_DRAG); - v[i].y = zpl_lerp(v[i].y, 0.0f, PHY_WALK_DRAG); + world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y); + float drag = blocks_get_drag(lookup.block_id); + v[i].x = zpl_lerp(v[i].x, 0.0f, PHY_WALK_DRAG*drag); + v[i].y = zpl_lerp(v[i].y, 0.0f, PHY_WALK_DRAG*drag); } } @@ -58,6 +61,64 @@ void IntegratePositions(ecs_iter_t *it) { } } +#define PHY_PUSHOUT_DIST ((64.0f*WORLD_BLOCK_SIZE)) + +void PushOutOverlappingEntities(ecs_iter_t *it) { + Position *p = ecs_column(it, Position, 1); + + for (int i = 0; i <= it->count; i++) { +#if 1 + // NOTE(zaklaus): slow path. iterate over all the entities in the table. + for (int k = 0; k <= it->count; k++) { + if (i == k) continue; +#else + // TODO(zaklaus): use a shared internal buffer instead !!! + static int64_t ents[UINT32_MAX]; + size_t ents_count = UINT32_MAX; + librg_world_fetch_chunk(world_tracker(), librg_chunk_from_realpos(world_tracker(), p[i].x, p[i].y, 0), ents, &ents_count); + + // NOTE(zaklaus): iterate over all entities inside this chunk + for (size_t j = 0; j < ents_count; j++) { + ecs_entity_t e = ents[j]; + + if (e == it->entities[i]) + continue; + + // NOTE(zaklaus): reverse lookup + int k = 0; + for (; k <= it->count; k++) { + if (k == it->count) { + k = -1; + break; + } + if (it->entities[k] == e) { + break; + } + } + + if (k == -1) + continue; +#endif + + float dx = p[i].x - p[k].x; + float dy = p[i].y - p[k].y; + float dist = zpl_sqrt(dx*dx + dy*dy); + if (dist < PHY_PUSHOUT_DIST) { + p[i].x = zpl_sign(dx); + p[i].y = zpl_sign(dy); +#if 0 + p[k].x += zpl_sign(dx); + p[k].y += zpl_sign(dy); +#endif + } + } + } + } + +#if 0 +} +#endif + void UpdateTrackerPos(ecs_iter_t *it) { Position *p = ecs_column(it, Position, 1); @@ -76,8 +137,9 @@ void PhysicsImport(ecs_world_t *ecs) { ECS_META(ecs, Velocity); - ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, Velocity); + ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, general.Position, Velocity); ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, general.Position, Velocity); + //ECS_SYSTEM(ecs, PushOutOverlappingEntities, EcsOnValidate, general.Position, Velocity); ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, general.Position); ECS_SET_TYPE(Movement); @@ -87,4 +149,5 @@ void PhysicsImport(ecs_world_t *ecs) { ECS_SET_ENTITY(MoveWalk); ECS_SET_ENTITY(UpdateTrackerPos); ECS_SET_ENTITY(IntegratePositions); + ECS_SET_ENTITY(PushOutOverlappingEntities); }