Large refactor to avoid the need to use map() and camera() - the new approach just re-calculates the local world and allows us to scroll 'smoothly' forever.
This commit is contained in:
parent
2ca23a7b4e
commit
16bcbc8e00
4 changed files with 98 additions and 111 deletions
187
world.lua
Normal file
187
world.lua
Normal file
|
@ -0,0 +1,187 @@
|
|||
--- Procedural generation methods
|
||||
|
||||
function init_world()
|
||||
-- Metadata for different biomes
|
||||
-- tile_frequencies tuples are {frequency, sprite_index}, see index_map.md
|
||||
-- frequencies by convention add up to 1000, but this is arbitrary, the
|
||||
-- only concern is the space consumed by the resulting tables.
|
||||
biome_data = {
|
||||
meadow = {
|
||||
biome_frequency = 20,
|
||||
tile_frequencies = { {525, 2}, {200, 5}, {200, 6}, {55, 18}, {19, 3}, {1, 4} }
|
||||
},
|
||||
grassland = {
|
||||
biome_frequency = 55,
|
||||
tile_frequencies = { {500, 2}, {345, 18}, {4, 3}, {1, 4}, {100, 5}, {50, 6} }
|
||||
},
|
||||
forest = {
|
||||
biome_frequency = 20,
|
||||
tile_frequencies = { {600, 2}, {200, 4}, {50, 3}, {50, 5}, {40, 7}, {59, 6}, {1, 8} }
|
||||
},
|
||||
desert = {
|
||||
biome_frequency = 5,
|
||||
tile_frequencies = { {800, 9}, {109, 11}, {60, 13}, {30, 12}, {1, 10} },
|
||||
}
|
||||
}
|
||||
|
||||
-- Why is this hard-coded separately from the biome_data? glad you asked.
|
||||
-- Lua's pairs() function appears not to guarantee a consistent return order,
|
||||
-- and we want our world to be deterministically generated,
|
||||
-- so the biome_metadata array needs to have its entries appear consistently.
|
||||
biome_list = {"grassland", "meadow", "forest", "desert"}
|
||||
|
||||
-- this is the frequency list for the biomes themselves
|
||||
biome_metadata = {}
|
||||
|
||||
for i=1,#biome_list do
|
||||
local biome = biome_list[i]
|
||||
|
||||
-- add the biome's name N times to the biome metadata 'hat'
|
||||
for i=1,biome_data[biome].biome_frequency do
|
||||
add(biome_metadata, biome)
|
||||
end
|
||||
|
||||
build_biome(biome, biome_data[biome])
|
||||
end
|
||||
|
||||
-- the indices here are sprite numbers.
|
||||
object_interaction_map = {
|
||||
-- bush
|
||||
[3] = {
|
||||
replacement = 17,
|
||||
sfx = 13,
|
||||
drop = 68
|
||||
},
|
||||
|
||||
-- tree
|
||||
[4] = {
|
||||
replacement = 14,
|
||||
sfx = 11,
|
||||
drop = 64
|
||||
},
|
||||
|
||||
-- big mushroom
|
||||
[8] = {
|
||||
replacement = 16,
|
||||
sfx = 12,
|
||||
drop = 65
|
||||
},
|
||||
|
||||
-- cactus w/ flower
|
||||
[10] = {
|
||||
replacement = 15,
|
||||
sfx = 12,
|
||||
drop = 67
|
||||
},
|
||||
|
||||
-- cactus
|
||||
[13] = {
|
||||
replacement = 15,
|
||||
sfx = 12,
|
||||
drop = 66
|
||||
}
|
||||
}
|
||||
|
||||
-- initialize a ring buffer of changed positions. In use, this will be keyed
|
||||
-- using strings of the form mod_buffer["x:y"], using absolute world
|
||||
-- coordinates. this is to flatten the buffer so that #mod_cache is useful
|
||||
-- for checking against max_mod_entries.
|
||||
max_mod_entries = 4096
|
||||
mod_buffer = {}
|
||||
end
|
||||
|
||||
-- draw the sprites for this part of the world to the screen
|
||||
-- this calculates everything about the world fresh every frame,
|
||||
-- but pico-8 handles this just fine!
|
||||
function draw_world_segment(start_x, start_y)
|
||||
for x=0,15 do
|
||||
for y=0,15 do
|
||||
spr(get_tile(start_x-8+x, start_y-8+y), x*8, y*8)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- build the lookup table for a given biome, based on the biome_meta data for
|
||||
-- that string.
|
||||
function build_biome(biome_name, data)
|
||||
local meta_frequencies = data.tile_frequencies
|
||||
local tile_lookup = {}
|
||||
|
||||
for i=1,#meta_frequencies do
|
||||
local tuple = meta_frequencies[i]
|
||||
for j=1,tuple[1] do
|
||||
add(tile_lookup, tuple[2])
|
||||
end
|
||||
end
|
||||
|
||||
data.tile_lookup = tile_lookup
|
||||
end
|
||||
|
||||
-- generates a unique identifier for a position
|
||||
-- uses srand() and rand() to get an unpredictable value (is this too slow?)
|
||||
-- the two seed values are randomly chosen. Change them and change the world.
|
||||
function generate_uid(pos_x, pos_y)
|
||||
srand((pos_x + 2229) * (pos_y + 12295))
|
||||
return flr(rnd(0xffff))
|
||||
end
|
||||
|
||||
-- given an {x,y} position, calculates the aligned starting position for the
|
||||
-- biome that position is in.
|
||||
-- biomes are currently defined to be 128x128
|
||||
function calculate_biome_pos(pos_x, pos_y)
|
||||
return flr(pos_x / 128), flr(pos_y / 128)
|
||||
end
|
||||
|
||||
-- determines which biome a given world map position should be,
|
||||
-- returns the object out of the biome_data table
|
||||
function get_biome_name(pos_x, pos_y)
|
||||
local biome_pos_x, biome_pos_y = calculate_biome_pos(pos_x, pos_y)
|
||||
local uid = generate_uid(biome_pos_x, biome_pos_y)
|
||||
return biome_metadata[(uid % #biome_metadata) + 1]
|
||||
end
|
||||
|
||||
-- determine what sprite to render for a given position.
|
||||
-- pos_x and pos_y are global coordinates.
|
||||
function get_tile(pos_x, pos_y)
|
||||
-- lookup changes in the change buffer
|
||||
local modded_sprite = mod_buffer[get_mod_key(pos_x, pos_y)]
|
||||
if (modded_sprite) return modded_sprite
|
||||
|
||||
local biome_name = get_biome_name(pos_x, pos_y)
|
||||
local biome = biome_data[biome_name]
|
||||
local uid = generate_uid(pos_x, pos_y)
|
||||
|
||||
return biome.tile_lookup[(uid % #biome.tile_lookup) + 1]
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
--- mod buffer functions - these handle parts of the world map that have
|
||||
--- changed from their 'default' position
|
||||
---
|
||||
--- todo: the mod buffer eventually needs to be a bit more elaborate.
|
||||
--- we need to make it possible to cull only old and unimportant changes,
|
||||
--- so each entry needs a 'critical' flag and something to indicate order
|
||||
--- added. We could keep 2 buffers for the latter, one that's just keys
|
||||
--- in an array... expensive though.
|
||||
---
|
||||
|
||||
-- x and y are global coords
|
||||
function get_mod_key(x, y)
|
||||
return tostr(x) .. ":" .. tostr(y)
|
||||
end
|
||||
|
||||
-- x and y are map-local coords
|
||||
function write_map_change(new_sprite, x, y)
|
||||
local global_x, global_y = calculate_world_pos(x, y)
|
||||
if #mod_buffer >= max_mod_entries then
|
||||
cull_mod_buffer()
|
||||
end
|
||||
|
||||
mod_buffer[get_mod_key(global_x, global_y)] = new_sprite
|
||||
end
|
||||
|
||||
function cull_mod_buffer()
|
||||
-- we cull 10% of the mod buffer at a time
|
||||
-- todo: implement this
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue