diff --git a/debug.lua b/debug.lua index 92d5d32..b433591 100644 --- a/debug.lua +++ b/debug.lua @@ -40,7 +40,7 @@ function debug_print() end function debug_print_res() - clip(70, 0, 16, 24) + clip(70, 0, 32, 24) print(stat(0), 70, 0, 15) print(stat(1), 70, 8, 15) print(stat(9) .. " / " .. stat(8), 70, 16, 15) @@ -54,15 +54,15 @@ function debug_print_sfx() end function debug_print_map() - clip(24, 0, 32, 24) - print(camera_pos_x .. " " .. camera_pos_y, 24, 0, 15) - print(player_pos_x .. " " .. player_pos_y, 24, 8, 15) - print(get_biome_name(player_pos_x, player_pos_y), 24, 16, 15) + clip(24, 0, 32, 16) + print(player_x .. " " .. player_y, 24, 0, 15) + print(get_biome_name(player_x, player_y), 24, 8, 15) clip() end function debug_print_mod_buffer() clip(0, 0, 16, 128) + rectfill(0,0,16,128,0) for k,v in pairs(mod_buffer) do print(k .. ": " .. tostr(v)) end diff --git a/main.lua b/main.lua index 928abf1..8616ed4 100644 --- a/main.lua +++ b/main.lua @@ -1,38 +1,18 @@ function _init() init_sound"" init_world"" - init_player(32, 32) + init_player"" init_debug"" end function _update() handle_input"" --- handle_map_update"" end function _draw() cls"" - -- the screen is 128x128 pixels, so it fits 16x16 sprites - -- map(camera_pos_x, camera_pos_y, 0, 0, 16, 16) - draw_world_segment(player_pos_x, player_pos_y) + draw_world(player_x, player_y) draw_player"" debug_print"" end - --- decide whether we need to regenerate the map. --- if so, call generate_map appropriately and reset coordinates. -function handle_map_update() - if out_of_bounds(camera_pos_x, camera_pos_y) then - -- out_of_bounds() checks all screen bounds - -- we need to regenerate the map, so we generate a map chunk that - -- places the player in the middle of it. - generate_map(player_pos_x-32, player_pos_y-32) - camera_pos_x, camera_pos_y = 24, 24 - end -end - -function out_of_bounds(pos_x, pos_y) - return pos_x < 0 or pos_x > 48 or - pos_y < 0 or pos_y > 48 -end diff --git a/player.lua b/player.lua index a4a707c..920e6f8 100644 --- a/player.lua +++ b/player.lua @@ -2,24 +2,19 @@ -- Larger sprites will probably work for objects, but not for the player. -- -- exported variables: --- player_pos_[xy] # absolute position of the player on the 'world map' --- camera_pos_[xy] # Represents top-left position of the pico-8 camera on --- # the pico-8 map --- facing_[vh] # Current facing of the player. Values of --- # each element can be -1 (up or left), 0 (neutral), --- # or 1 (down or right) +-- player_[xy] # position of the player on the 'world map' +-- facing_[vh] # Current facing of the player. Values of +-- # each element can be -1 (up or left), 0 (neutral), +-- # or 1 (down or right) -- -- functions: --- init_player(x,y) # call this in _init(). Sets player starting position, --- # assumes the top-left of the pico-8 map is currently --- # world position 0,0 --- handle_input() # call in _update() to handle movement key presses. --- # Assumes any sprite with flag 0 set is an obstacle. --- draw_player() # call in _draw(). Draws the player sprite. +-- init_player() # call this in _init(). +-- handle_input() # call in _update() to handle movement key presses. +-- # Assumes any sprite with flag 0 set is an obstacle. +-- draw_player() # call in _draw(). Draws the player sprite. -function init_player(start_pos_x, start_pos_y) - player_pos_x, player_pos_y = start_pos_x, start_pos_y - camera_pos_x, camera_pos_y = start_pos_x-8, start_pos_y-8 +function init_player() + player_x, player_y = 0, 0 facing_v = 1 facing_h = 0 @@ -46,8 +41,7 @@ end function handle_input() - local new_pos_x, new_pos_y = camera_pos_x, camera_pos_y - local new_ppos_x, new_ppos_y = player_pos_x, player_pos_y + local new_x, new_y = player_x, player_y if btnp"4" then interact() @@ -55,13 +49,11 @@ function handle_input() if btnp"0" or btnp"1" or btnp"2" or btnp"3" then if btnp"0" then - new_pos_x -= 1 -- move left - new_ppos_x -= 1 + new_x -= 1 -- move left facing_h = 0xffff end if btnp"1" then - new_pos_x += 1 -- move right - new_ppos_x += 1 -- move right + new_x += 1 -- move right facing_h = 1 end if not (btnp"0" or btnp"1") then @@ -69,13 +61,11 @@ function handle_input() end if btnp"2" then - new_pos_y -= 1 -- move up - new_ppos_y -= 1 -- move up + new_y -= 1 -- move up facing_v = 0xffff end if btnp"3" then - new_pos_y += 1 -- move down - new_ppos_y += 1 -- move down + new_y += 1 -- move down facing_v = 1 end if not (btnp"2" or btnp"3") then @@ -83,9 +73,9 @@ function handle_input() end end - if legal_move(new_pos_x, new_pos_y) then - camera_pos_x, camera_pos_y = new_pos_x, new_pos_y - player_pos_x, player_pos_y = new_ppos_x, new_ppos_y + -- note that facing always changes, even if we can't move to the new location + if legal_move(new_x, new_y) then + player_x, player_y = new_x, new_y end end @@ -102,52 +92,48 @@ function draw_player() -- todo: introduce the concept of an inventory here end --- uses global variables instead of arguments --- returns x,y for the map-local coordinates of the interactable object +-- returns x,y as the coordinates of the interactable object -- nil,nil if nothing to interact with +-- NB: this function calls get_tile() from world.lua function can_interact() -- flag 1 represents an interactable (read: destructible) sprite. - -- need a map of destructible map objects, appropriate sfx, replacement - -- sprites. - local player_rel_x, player_rel_y = player_pos_x+8, player_pos_y+8 -- check the tile the player is standing on - if fget(mget(player_rel_x, player_rel_y), 1) then - return player_rel_x, player_rel_y + if fget(get_tile(player_x, player_y), 1) then + return player_x, player_y end -- check the tile the player is facing faced_tile_x, faced_tile_y = get_position_facing() - if fget(mget(faced_tile_x, faced_tile_y), 1) then + if fget(get_tile(faced_tile_x, faced_tile_y), 1) then return faced_tile_x, faced_tile_y end return nil, nil end +-- NB: this function calls get_tile() and references the +-- object_interaction_map from world.lua function interact() -- get the position to interact with local x, y = can_interact() if (x == nil or y == nil) return - local sprite = mget(x, y) + local sprite = get_tile(x, y) local data = object_interaction_map[sprite] -- todo: figure out playing sound effects, animation? - -- modify the rendered tile - mset(x, y, data.replacement) - - -- and write the change to the buffer + -- modify the tile by writing the change to the mod_buffer + -- (the rendered image will be updated by draw_world() write_map_change(data.replacement, x, y) end -- returns x,y representing the map-local position the player is facing. function get_position_facing() - return camera_pos_x+8+facing_h, camera_pos_y+8+facing_v + return player_x+facing_h, player_y+facing_v end --- pos is camera position, meaning the map-relative player --- position is pos + {8, 8}. +-- NB: this function calls get_tile() from world.lua function legal_move(pos_x, pos_y) - return not fget(mget(pos_x+8, pos_y+8), 0) + return not fget(get_tile(pos_x, pos_y), 0) end diff --git a/world.lua b/world.lua index 00851ee..421489f 100644 --- a/world.lua +++ b/world.lua @@ -85,15 +85,15 @@ function init_world() -- 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 + -- for checking against the number of allowed entries mod_buffer = {} + mod_queue = {} 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) +function draw_world(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) @@ -172,16 +172,25 @@ function get_mod_key(x, 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 +function write_map_change(new_sprite, x, y, perm) + if #mod_buffer >= 8192 then cull_mod_buffer() end + local key = get_mod_key(x, y) + mod_buffer[key] = new_sprite - mod_buffer[get_mod_key(global_x, global_y)] = new_sprite + -- the queue gives us a time-ordered list of items to delete. + -- anything that should persist is simply not added to the queue, + -- making it un-deletable. + -- obviously if we end up with a *very large number* of persistent + -- objects we can run into trouble, but this is functionally a design + -- limitation. + if not perm then + add(mod_queue, key) + end end function cull_mod_buffer() - -- we cull 10% of the mod buffer at a time - -- todo: implement this + -- we cull 512 entries at a time. + -- stub: implement me! end