-- This module assumes all objects and the player are 1x1 sprite in size. -- 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) -- -- 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. 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 facing_v = 1 facing_h = 0 -- this is a constant for looking up player sprites by facing player_lookup = { [0] = { [0] = 0xffff, -- error state [0xffff] = 122, -- left [1] = 123, -- right }, [0xffff] = { [0] = 120, -- up [0xffff] = 124, -- up-left [1] = 125, -- up-right }, [1] = { [0] = 121, -- down [0xffff] = 126, -- down-left [1] = 127, -- down-right }, } 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 if btnp"4" then interact() end 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 facing_h = 0xffff end if btnp"1" then new_pos_x += 1 -- move right new_ppos_x += 1 -- move right facing_h = 1 end if not (btnp"0" or btnp"1") then facing_h = 0 end if btnp"2" then new_pos_y -= 1 -- move up new_ppos_y -= 1 -- move up facing_v = 0xffff end if btnp"3" then new_pos_y += 1 -- move down new_ppos_y += 1 -- move down facing_v = 1 end if not (btnp"2" or btnp"3") then facing_v = 0 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 end end function draw_player() spr(player_lookup[facing_v][facing_h], 64, 64) -- todo: animate the character on move -- draw the player's HUD local interact_x, interact_y = can_interact() if interact_x and interact_y then spr(119, 0, 120) end -- 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 -- nil,nil if nothing to interact with 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 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 return faced_tile_x, faced_tile_y end return nil, nil end 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 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 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 end -- pos is camera position, meaning the map-relative player -- position is pos + {8, 8}. function legal_move(pos_x, pos_y) return not fget(mget(pos_x+8, pos_y+8), 0) end