improve worldgen + conveyor belts

isolation_bkp/dynres
Dominik Madarász 2021-11-02 18:09:54 +01:00
parent 2130d85edf
commit 1a5a550512
23 changed files with 128 additions and 35 deletions

BIN
art/belt.aseprite 100644

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

BIN
art/gen/belt_up.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

BIN
art/gen/tree.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 846 B

BIN
art/gen/wood.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

BIN
art/tree.aseprite 100644

Binary file not shown.

BIN
art/wood.aseprite 100644

Binary file not shown.

View File

@ -9,11 +9,14 @@
// 2) Add the asset to the asset list
#include "assets_list.c"
// 3) Assign a texture (if applicable)
#include "texgen.c"
// NOTE(zaklaus): Now that your asset is registered, we
// can use it in other systems
// NOTE(zaklaus): Register a block
#include "blocks_list.c"
#include "blocks/blocks_list.c"
// NOTE(zaklaus): Register an item
#include "items_list.c"

View File

@ -25,6 +25,13 @@ typedef enum {
ASSET_HILL,
ASSET_HILL_SNOW,
ASSET_HOLE,
ASSET_WOOD,
ASSET_TREE,
ASSET_BELT_LEFT,
ASSET_BELT_RIGHT,
ASSET_BELT_UP,
ASSET_BELT_DOWN,
MAX_ASSETS,
FORCE_ASSET_UINT16 = UINT16_MAX

View File

@ -21,4 +21,10 @@ static asset assets[] = {
ASSET_TEX(ASSET_HILL),
ASSET_TEX(ASSET_HILL_SNOW),
ASSET_TEX(ASSET_HOLE),
ASSET_TEX(ASSET_WOOD),
ASSET_TEX(ASSET_TREE),
ASSET_TEX(ASSET_BELT_LEFT),
ASSET_TEX(ASSET_BELT_RIGHT),
ASSET_TEX(ASSET_BELT_UP),
ASSET_TEX(ASSET_BELT_DOWN),
};

View File

@ -25,6 +25,12 @@ Texture2D texgen_build_sprite(asset_id id) {
case ASSET_HILL: return LoadImageEco("rock");
case ASSET_WATER: return LoadImageEco("water");
case ASSET_LAVA: return LoadImageEco("lava");
case ASSET_WOOD: return LoadImageEco("wood");
case ASSET_TREE: return LoadImageEco("tree");
case ASSET_BELT_LEFT: return LoadImageEco("belt_left");
case ASSET_BELT_RIGHT: return LoadImageEco("belt_right");
case ASSET_BELT_UP: return LoadImageEco("belt_up");
case ASSET_BELT_DOWN: return LoadImageEco("belt_down");
default: {
Image img = GenImageColor(1, 1, RAYWHITE);

View File

@ -38,6 +38,7 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p) {
item_desc *desc = &items[item_id];
if (it->quantity <= 0) return;
switch (item_get_usage(item_id)) {
case UKIND_HOLD: /* NOOP */ break;
case UKIND_PLACE:{
world_block_lookup l = world_block_from_realpos(p.x, p.y);
if (world_chunk_place_block(l.chunk_id, l.id, blocks_find(desc->place.kind)) )

View File

@ -6,6 +6,7 @@
#include "modules/components.h"
typedef enum {
UKIND_HOLD,
UKIND_PLACE,
UKIND_PLACE_ITEM,
UKIND_END_PLACE,

View File

@ -1,5 +1,12 @@
#include "items.h"
#define ITEM_HOLD(asset, qty)\
{\
.kind = asset,\
.usage = UKIND_HOLD,\
.max_quantity = qty,\
}
#define ITEM_BLOCK(asset, qty, build_asset)\
{\
.kind = asset,\
@ -19,4 +26,11 @@ static item_desc items[] = {
},
ITEM_BLOCK(ASSET_DEMO_ICEMAKER, 64, ASSET_WATER),
ITEM_SELF(ASSET_FENCE, 64),
ITEM_SELF(ASSET_WOOD, 64),
ITEM_HOLD(ASSET_TREE, 64),
ITEM_SELF(ASSET_BELT_LEFT, 999),
ITEM_SELF(ASSET_BELT_RIGHT, 999),
ITEM_SELF(ASSET_BELT_UP, 999),
ITEM_SELF(ASSET_BELT_DOWN, 999),
};

View File

@ -27,6 +27,9 @@ typedef struct {
float friction;
float bounce;
float velx;
float vely;
// NOTE(zaklaus): viewer data
uint16_t slot;
} block;
@ -74,6 +77,14 @@ float blocks_get_bounce(uint8_t id) {
return blocks[id].bounce;
}
float blocks_get_velx(uint8_t id) {
return blocks[id].velx;
}
float blocks_get_vely(uint8_t id) {
return blocks[id].vely;
}
void *blocks_get_img(uint8_t id) {
return assets_get_tex(blocks[id].slot);
}

View File

@ -18,6 +18,8 @@ uint32_t blocks_get_flags(uint8_t id);
float blocks_get_drag(uint8_t id);
float blocks_get_friction(uint8_t id);
float blocks_get_bounce(uint8_t id);
float blocks_get_velx(uint8_t id);
float blocks_get_vely(uint8_t id);
// NOTE(zaklaus): viewer-related functions
void *blocks_get_img(uint8_t id);

View File

@ -15,4 +15,11 @@ static block blocks[] = {
BLOCK(ASSET_WATER, 0, '~', .drag = 0.11f , .friction = 1.0f),
BLOCK(ASSET_LAVA, BLOCK_FLAG_HAZARD, '!', .drag = 6.2f , .friction = 4.0f),
BLOCK(ASSET_FENCE, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 1.0f),
BLOCK(ASSET_WOOD, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f),
BLOCK(ASSET_TREE, BLOCK_FLAG_COLLISION, '@', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f),
BLOCK(ASSET_BELT_LEFT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = -90.0f),
BLOCK(ASSET_BELT_RIGHT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = 90.0f),
BLOCK(ASSET_BELT_UP, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = -90.0f),
BLOCK(ASSET_BELT_DOWN, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = 90.0f),
};

View File

@ -174,8 +174,9 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) {
librg_event_set(world.tracker, LIBRG_WRITE_UPDATE, tracker_write_update);
world.data = zpl_malloc(sizeof(uint8_t)*world.size);
world.outer_data = zpl_malloc(sizeof(uint8_t)*world.size);
if (!world.data) {
if (!world.data || !world.outer_data) {
return WORLD_ERROR_OUTOFMEM;
}
@ -214,13 +215,15 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) {
*c = world.data[(chk_y+y)*world.dim + (chk_x+x)];
c = &world.outer_block_mapping[i][(y*chunk_size)+x];
*c = 0;
*c = world.outer_data[(chk_y+y)*world.dim + (chk_x+x)];
}
}
}
zpl_mfree(world.data);
zpl_mfree(world.outer_data);
world.data = NULL;
world.outer_data = NULL;
zpl_printf("[INFO] Created a new server world\n");

View File

@ -32,6 +32,7 @@ typedef WORLD_PKT_WRITER(world_pkt_writer_proc);
typedef struct {
bool is_paused;
uint8_t *data;
uint8_t *outer_data;
uint32_t seed;
uint32_t size;
uint16_t chunk_size;

View File

@ -12,7 +12,7 @@
#include "items.h"
#include "world/blocks_info.h"
#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 *data, uint8_t id, uint32_t block_idx)
typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc);
#define WORLD_PERLIN_FREQ 100
@ -41,7 +41,7 @@ uint8_t worldgen_biome_find(uint32_t biome, uint32_t kind) {
static world_data *world;
static void world_fill_rect(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
static void world_fill_rect(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
for (uint32_t cy=y; cy<y+h; cy++) {
for (uint32_t cx=x; cx<x+w; cx++) {
if (cx < 0 || cx >= world->dim) continue;
@ -49,19 +49,19 @@ static void world_fill_rect(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint
uint32_t i = (cy*world->dim) + cx;
if (proc) {
uint8_t new_id = (*proc)(id, i);
uint8_t new_id = (*proc)(data, id, i);
if (new_id != BLOCK_INVALID) {
id = new_id;
}
else continue;
}
world->data[i] = id;
data[i] = id;
}
}
}
static void world_fill_circle(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
static void world_fill_circle(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) {
for (uint32_t cy=y; cy<y+h; cy++) {
for (uint32_t cx=x; cx<x+w; cx++) {
if (cx < 0 || cx >= world->dim) continue;
@ -69,27 +69,27 @@ static void world_fill_circle(uint8_t id, uint32_t x, uint32_t y, uint32_t w, ui
uint32_t i = (cy*world->dim) + cx;
if (proc) {
uint8_t new_id = (*proc)(id, i);
uint8_t new_id = (*proc)(data, id, i);
if (new_id != BLOCK_INVALID) {
id = new_id;
}
else continue;
}
world->data[i] = id;
data[i] = id;
}
}
}
static void world_fill_rect_anchor(uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) {
static void world_fill_rect_anchor(uint8_t *data, uint8_t id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) {
uint32_t w2 = (uint32_t)floorf(w*ax);
uint32_t h2 = (uint32_t)floorf(h*ay);
world_fill_rect(id, x-w2, y-h2, w, h, proc);
world_fill_rect(data, id, x-w2, y-h2, w, h, proc);
}
static WORLD_BLOCK_OBSERVER(shaper) {
uint32_t kind = id;
uint32_t old_kind = world->data[block_idx];
uint32_t old_kind = data[block_idx];
if (kind == BLOCK_KIND_WALL && kind == old_kind) {
return worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_HILL);
@ -101,29 +101,38 @@ static WORLD_BLOCK_OBSERVER(shaper) {
return id;
}
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;
static uint8_t world_perlin_cond_offset(uint32_t block_idx, double chance, uint32_t ofx, uint32_t ofy) {
uint32_t x = block_idx % world->dim + ofx;
uint32_t y = block_idx / world->dim + ofy;
return perlin_fbm(world->seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance;
}
static uint8_t world_perlin_cond(uint32_t block_idx, double chance) {
return world_perlin_cond_offset(block_idx, chance, 0, 0);
}
#if 1
static WORLD_BLOCK_OBSERVER(shaper_noise80) {
return world_perlin_cond(block_idx, 0.80) ? shaper(id, block_idx) : BLOCK_INVALID;
return world_perlin_cond(block_idx, 0.80) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
static WORLD_BLOCK_OBSERVER(shaper_noise50) {
return world_perlin_cond(block_idx, 0.50) ? shaper(id, block_idx) : BLOCK_INVALID;
return world_perlin_cond(block_idx, 0.50) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
static WORLD_BLOCK_OBSERVER(shaper_noise33) {
return world_perlin_cond(block_idx, 0.33) ? shaper(id, block_idx) : BLOCK_INVALID;
return world_perlin_cond(block_idx, 0.33) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
static WORLD_BLOCK_OBSERVER(shaper_noise05) {
return world_perlin_cond(block_idx, 0.05) ? shaper(id, block_idx) : BLOCK_INVALID;
return world_perlin_cond(block_idx, 0.05) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
static WORLD_BLOCK_OBSERVER(shaper_noise05b) {
return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
#else
static WORLD_BLOCK_OBSERVER(shaper_noise80) {
return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID;
@ -145,6 +154,7 @@ static void world_fill_mountain(uint32_t x, uint32_t y) {
#endif
#define RAND_RANGE(x,y) (x + (int)rand()%(y-(x)))
#define RAND_RANGEF(x,y) ((float)RAND_RANGE(x,y))
int32_t worldgen_test(world_data *wld) {
// TODO(zaklaus): pass world as an arg instead
@ -157,32 +167,34 @@ int32_t worldgen_test(world_data *wld) {
uint8_t dirt_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_DIRT);
uint8_t watr_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_WATER);
uint8_t lava_id = worldgen_biome_find(BLOCK_BIOME_DEV, BLOCK_KIND_LAVA);
uint8_t tree_id = blocks_find(ASSET_TREE);
srand(world->seed);
// walls
world_fill_rect(wall_id, 0, 0, world->dim, world->dim, NULL);
world_fill_rect(world->data, wall_id, 0, 0, world->dim, world->dim, NULL);
// 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_noise05);
world_fill_rect(world->data, grnd_id, 1, 1, world->dim-2, world->dim-2, NULL);
world_fill_rect(world->data, dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05);
world_fill_rect(world->outer_data, tree_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05b);
// water
#if 1
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(world->data, 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
// ice rink
#if 0
world_fill_rect_anchor(watr_id, 450, 125, 10, 10, 0.0f, 0.0f, NULL);
world_fill_rect_anchor(world->data, watr_id, 450, 125, 10, 10, 0.0f, 0.0f, NULL);
#endif
// lava
#if 1
for (int i=0; i<RAND_RANGE(48, 62); i++) {
world_fill_rect_anchor(lava_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(world->data, lava_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
@ -191,7 +203,7 @@ int32_t worldgen_test(world_data *wld) {
#if 1
const uint32_t HILLS_SIZE = 21;
for (int i=0; i<RAND_RANGE(8, 124); i++) {
world_fill_rect_anchor(wall_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), RAND_RANGE(0,HILLS_SIZE), RAND_RANGE(0,HILLS_SIZE), 0.5f, 0.5f, shaper_noise50);
world_fill_rect_anchor(world->data, wall_id, RAND_RANGE(0, world->dim), RAND_RANGE(0, world->dim), RAND_RANGE(0,HILLS_SIZE), RAND_RANGE(0,HILLS_SIZE), 0.5f, 0.5f, shaper_noise50);
}
#endif
@ -201,8 +213,8 @@ int32_t worldgen_test(world_data *wld) {
uint64_t e = vehicle_spawn();
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
dest->x = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
#endif
@ -212,17 +224,34 @@ int32_t worldgen_test(world_data *wld) {
uint64_t e = item_spawn(ASSET_DEMO_ICEMAKER, 32);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
dest->x = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
for (int i=0; i<RAND_RANGE(328, 164); i++) {
uint64_t e = item_spawn(ASSET_FENCE, 64);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
dest->x = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGE(0, world->dim*WORLD_BLOCK_SIZE);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
for (int i=0; i<RAND_RANGE(328, 164); i++) {
uint64_t e = item_spawn(ASSET_WOOD, 64);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
for (int i=0; i<RAND_RANGE(328, 164); i++) {
uint64_t e = item_spawn(ASSET_BELT_LEFT, 999);
Position *dest = ecs_get_mut(world_ecs(), e, Position, NULL);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
}
#endif
return WORLD_ERROR_NONE;

View File

@ -142,8 +142,10 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y);
float drag = zpl_clamp(blocks_get_drag(lookup.block_id), 0.0f, 1.0f);
float friction = blocks_get_friction(lookup.block_id);
v[i].x = zpl_lerp(v[i].x, 0.0f, PHY_WALK_DRAG*drag*friction*safe_dt(it));
v[i].y = zpl_lerp(v[i].y, 0.0f, PHY_WALK_DRAG*drag*friction*safe_dt(it));
float velx = blocks_get_velx(lookup.block_id);
float vely = blocks_get_vely(lookup.block_id);
v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it));
v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it));
}
}