code: many improvements and fixes

Changelog:
- fixed world repetition bug caused by wrong indexing 🎉
- wall collisions
- tile-based drag movement multiplier
- various optimizations
- raised default NPC count to 10k
isolation_bkp/dynres
Dominik Madarász 2021-07-26 21:06:49 +02:00
parent 99a65431d8
commit d0ff81b570
10 changed files with 96 additions and 26 deletions

View File

@ -19,6 +19,7 @@ char blocks_get_symbol(uint8_t id);
uint32_t blocks_get_flags(uint8_t id); uint32_t blocks_get_flags(uint8_t id);
uint32_t blocks_get_biome(uint8_t id); uint32_t blocks_get_biome(uint8_t id);
uint32_t blocks_get_kind(uint8_t id); uint32_t blocks_get_kind(uint8_t id);
float blocks_get_drag(uint8_t id);
// NOTE(zaklaus): viewer-related functions // NOTE(zaklaus): viewer-related functions
void *blocks_get_img(uint8_t id); void *blocks_get_img(uint8_t id);

View File

@ -28,8 +28,8 @@ uint64_t entity_spawn(char *name) {
pos->x=rand() % world_dim(); pos->x=rand() % world_dim();
pos->y=rand() % world_dim(); pos->y=rand() % world_dim();
#else #else
pos->x=35; pos->x=350;
pos->y=33; pos->y=88;
#endif #endif

View File

@ -49,7 +49,7 @@ int main(int argc, char** argv) {
uint16_t num_viewers = zpl_opts_integer(&opts, "viewer-count", 1); 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 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); 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")) { if (zpl_opts_has_arg(&opts, "random-seed")) {
zpl_random rnd={0}; zpl_random rnd={0};

View File

@ -23,6 +23,7 @@ typedef struct {
uint32_t kind; uint32_t kind;
uint32_t biome; uint32_t biome;
char symbol; char symbol;
float drag;
// NOTE(zaklaus): viewer data // NOTE(zaklaus): viewer data
Texture2D img; Texture2D img;
@ -77,6 +78,10 @@ uint32_t blocks_get_kind(uint8_t id) {
return blocks[id].kind; return blocks[id].kind;
} }
float blocks_get_drag(uint8_t id) {
return blocks[id].drag;
}
void *blocks_get_img(uint8_t id) { void *blocks_get_img(uint8_t id) {
return (void*)&blocks[id].img; return (void*)&blocks[id].img;
} }

View File

@ -1,10 +1,10 @@
#include "world/blocks.h" #include "world/blocks.h"
static block blocks[] = { static block blocks[] = {
{.name = "base-ground", .flags = 0, .kind = BLOCK_KIND_GROUND, .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 = ','}, {.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 = '#'}, {.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 = '^'}, {.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 = '*'}, {.name = "base-hill-snow", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_HILL_SNOW, .biome = 0, .symbol = '*', .drag = 1.0f },
{.name = "base-water", .flags = BLOCK_FLAG_COLLISION, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~'}, {.name = "base-water", .flags = 0, .kind = BLOCK_KIND_WATER, .biome = 0, .symbol = '~', .drag = 0.11f },
}; };

View File

@ -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)); world.block_mapping[i] = zpl_malloc(sizeof(uint8_t)*zpl_square(chunk_size));
chunk->id = i; chunk->id = i;
for (int y = 0; y < world.chunk_size; y += 1) { for (int y = 0; y < chunk_size; y += 1) {
for (int x = 0; x < world.chunk_size; x += 1) { for (int x = 0; x < chunk_size; x += 1) {
int chk = world.chunk_size * i; int chk_x = chunk->x * chunk_size;
int chk_x = chk % world.dim; int chk_y = chunk->y * chunk_size;
int chk_y = chk / world.dim;
uint8_t *c = &world.block_mapping[i][(y*chunk_size)+x]; uint8_t *c = &world.block_mapping[i][(y*chunk_size)+x];
*c = world.data[(chk_y+y)*world.dim + (chk_x+x)]; *c = world.data[(chk_y+y)*world.dim + (chk_x+x)];
} }

View File

@ -10,8 +10,8 @@
#define WORLD_BLOCK_OBSERVER(name) uint8_t name(uint8_t id, uint32_t block_idx) #define WORLD_BLOCK_OBSERVER(name) uint8_t name(uint8_t id, uint32_t block_idx)
typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc); typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc);
#define WORLD_PERLIN_FREQ 9.34157f #define WORLD_PERLIN_FREQ 100
#define WORLD_PERLIN_OCTAVES 4 #define WORLD_PERLIN_OCTAVES 1
static world_data *world; 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 x = block_idx % world->dim;
uint32_t y = 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 #if 1
@ -138,11 +138,11 @@ int32_t worldgen_test(world_data *wld) {
// ground // ground
world_fill_rect(grnd_id, 1, 1, world->dim-2, world->dim-2, NULL); 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 // water
#if 1 #if 1
for (int i=0; i<RAND_RANGE(8, 22); i++) { for (int i=0; i<RAND_RANGE(58, 92); i++) {
world_fill_rect_anchor(watr_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80); world_fill_rect_anchor(watr_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), 4+RAND_RANGE(0,3), 4+RAND_RANGE(0,3), 0.5f, 0.5f, shaper_noise80);
} }
#endif #endif

View File

@ -14,6 +14,7 @@ typedef struct {
ECS_DECLARE_ENTITY(MoveWalk); ECS_DECLARE_ENTITY(MoveWalk);
ECS_DECLARE_ENTITY(UpdateTrackerPos); ECS_DECLARE_ENTITY(UpdateTrackerPos);
ECS_DECLARE_ENTITY(IntegratePositions); ECS_DECLARE_ENTITY(IntegratePositions);
ECS_DECLARE_ENTITY(PushOutOverlappingEntities);
} Physics; } Physics;
#define PhysicsImportHandles(handles)\ #define PhysicsImportHandles(handles)\
@ -24,5 +25,6 @@ ECS_IMPORT_COMPONENT(handles, Velocity);\
ECS_IMPORT_ENTITY(handles, MoveWalk);\ ECS_IMPORT_ENTITY(handles, MoveWalk);\
ECS_IMPORT_ENTITY(handles, UpdateTrackerPos);\ ECS_IMPORT_ENTITY(handles, UpdateTrackerPos);\
ECS_IMPORT_ENTITY(handles, IntegratePositions);\ ECS_IMPORT_ENTITY(handles, IntegratePositions);\
ECS_IMPORT_ENTITY(handles, PushOutOverlappingEntities);\
void PhysicsImport(ecs_world_t *ecs); void PhysicsImport(ecs_world_t *ecs);

View File

@ -21,7 +21,7 @@ void MovementImpulse(ecs_iter_t *it) {
} }
#define DEMO_NPC_CHANGEDIR_FACTOR 0.1 #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) { void DemoNPCMoveAround(ecs_iter_t *it) {
Velocity *v = ecs_column(it, Velocity, 1); Velocity *v = ecs_column(it, Velocity, 1);
@ -47,8 +47,8 @@ void ControllersImport(ecs_world_t *ecs) {
ECS_TAG(ecs, EcsBuilder); ECS_TAG(ecs, EcsBuilder);
ECS_TAG(ecs, EcsDemoNPC); ECS_TAG(ecs, EcsDemoNPC);
ECS_SYSTEM(ecs, MovementImpulse, EcsOnUpdate, Input, physics.Velocity); ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, Input, physics.Velocity);
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnUpdate, physics.Velocity, EcsDemoNPC); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, physics.Velocity, EcsDemoNPC);
ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor); ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor);
ECS_TYPE(ecs, Player, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Walking, EcsActor, EcsPlayer); ECS_TYPE(ecs, Player, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Walking, EcsActor, EcsPlayer);

View File

@ -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) #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) { 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++) { for (int i = 0; i < it->count; i++) {
v[i].x = zpl_lerp(v[i].x, 0.0f, PHY_WALK_DRAG); world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y);
v[i].y = zpl_lerp(v[i].y, 0.0f, PHY_WALK_DRAG); 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) { void UpdateTrackerPos(ecs_iter_t *it) {
Position *p = ecs_column(it, Position, 1); Position *p = ecs_column(it, Position, 1);
@ -76,8 +137,9 @@ void PhysicsImport(ecs_world_t *ecs) {
ECS_META(ecs, Velocity); 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, IntegratePositions, EcsOnValidate, general.Position, Velocity);
//ECS_SYSTEM(ecs, PushOutOverlappingEntities, EcsOnValidate, general.Position, Velocity);
ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, general.Position); ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, general.Position);
ECS_SET_TYPE(Movement); ECS_SET_TYPE(Movement);
@ -87,4 +149,5 @@ void PhysicsImport(ecs_world_t *ecs) {
ECS_SET_ENTITY(MoveWalk); ECS_SET_ENTITY(MoveWalk);
ECS_SET_ENTITY(UpdateTrackerPos); ECS_SET_ENTITY(UpdateTrackerPos);
ECS_SET_ENTITY(IntegratePositions); ECS_SET_ENTITY(IntegratePositions);
ECS_SET_ENTITY(PushOutOverlappingEntities);
} }