Pico-8 Top-Down Adventure Game Tutorial
This is a writeup of the tutorial published on YouTube by Dylan Bennett. The original work is all by Dylan Bennett and not by me.
Please go here for the original pages:
You can view the whole playlist here.
Chapter 1 - The Map
Draw nine sprites:
grass, fancy grass and rock
water, fancy water and water rock
road, fancy road and wall
Toggle sprite flag 0 on rock, the three water tiles and wall.
Prepare two tabs of code.
Game Loop
Create the main game loop.
Map Code
Create code that draws the map in a new tab, map code tab.
Chapter 2 - The Player
Draw a sprite for the player.
Add a new code tab for the player code tab.
-- player code function make_player() p={} p.x=1 p.y=1 p.sprite=1 p.keys=0 end function draw_player() spr(p.sprite,p.x*8,p.y*8) end
Call these functions from the game loop tab.
Chapter 3 - Movement
Create a sound effect for bumping into an obstacle.
Add two functions is_tile and can_move to the map code tab.
function is_tile(tile_type,x,y) tile=mget(x,y) has_flag=fget(tile,tile_type) return has_flag end function can_move(x,y) return not is_tile(wall, x, y) end
Add a function for moving the player to the player code tab.
Note: to get the arrow characters, use shift+L, shift+R, shift+U, shift+D.
function move_player() newx=p.x newy=p.y if (btnp(⬅️)) newx-=1 if (btnp(➡️)) newx+=1 if (btnp(⬆️)) newy-=1 if (btnp(⬇️)) newy+=1 if can_move(newx,newy) then p.x=mid(0,newx,127) p.y=mid(0,newy,63) else sfx(0) end end
Call this function from function update in the game loop tab.
Chapter 4 - Camera
Have the camera follow the player around the map.
Add code to set the camera to the draw_map function in the map code tab.
divide the player's x and y coordinates by 16
round down
multiply by 16
take this mapx, mapy to a pixel coordinate by multiplying by 8
Chapter 5 - Keys
Draw a sprite for a key and a sprite for a chest. The key can be picked up and the chest can be opened. When the player interacts with these items they are replaced by the sprite to the right, so you will need to draw two additional sprites.
The key is replaced by grass and the chest is replaced by an open chest.
Make a sound effect for the pick-up key sound.
Add two functions, swap_tile and get_key, to the map code tab.
function swap_tile(x,y) tile=mget(x,y) mset(x,y,tile+1) end function get_key(x,y) p.keys+=1 swap_tile(x,y) sfx(1) end
Add a function, interact to the player code tab.
Now call this function from the mode_player function.
Chapter 6 - Inventory
When the player holds down the X key we'll show how many keys the player has in their inventory.
Create a new tab called inventory code and in in put a new function called show_inventory.
function show_inventory() invx=mapx*8+40 invy=mapy*8+8 rectfill(invx,invy,invx+48,invy+24,0) print("inventory",invx+7,invy+4,7) print("keys "..p.keys,invx+12,invy+14,9) end
- Then call this function from the _draw function.
-
You can use shift-x to get the ❎ button.
Chapter 7 - Doors
We'll add doors that they player can open with their keys. First draw a pair if sprites, one for a closed door and, next to it, one for an open door.
Add a sound effect for opening a door.
Add a function open_door to open the door to the map code tab.
This function gets called in the interact function.
Chater 8 - Animated Tiles
In this step we add animated tiles. Animated tiles bring the map to life. Here we'll use them to make a spike trap that the player has to navigate through.
Create a pair of sprites, one for the spikes up and one with the spikes down. The animation will have cause the two sprites to flip between each other.
The tile with spikes up should have two flags set, flag 3 (anim1, or step one of the animation) and flag 6 (lose), which will cause the player to lose if they step on them. The tile with spikes down should have one flag set, flag 4, (anim2, step 2 of the animation).
Add two variables to the map_setup function in the map code tab.
Add a new function unswap_tile to the map code tab. Note that this function is nearly the same as swap_tile and so you can use copy paste to write it.
Add a new tab, animation code. Add a new function toggle_tiles to this tab.
function toggle_tiles() for x=mapx,mapx+15 do for y=mapy,mapy+15 do if (is_tile(anim1,x,y)) then swap_tile(x,y) sfx(3) elseif (is_tile(anim2,x,y))then unswap_tile(x,y) sfx(3) end end end end
Add a new function called update_map to the map code tab.
Finally, call the update_map function from the _update function in the game loop tab.
Chapter 9 - Winning and Losing
add a new sprite that the player has to move over to win the game
add game_win and game_over to _init
add new tab win/lose code
add two new functions, check_win_lose, draw_win_lose
-- win/lose code function check_win_lose() if (is_tile(win,p.x,p.y)) then game_win=true game_over=true elseif (is_tile(lose,p.x,p.y)) then game_win=false game_over=true end end function draw_win_lose() camera() if (game_win) then print("★ you win! ★",37,64,7) else print("game over!",38,64,7) end end
change _update to only run if not game_over, and call check_win_lose
function _update() update_map() move_player() if (not game_over) then update_map() move_player() check_win_lose() end end
change _draw to only draw if not game_over else draw_win_lose
Chapter 10 - Trying Again
Add a way for the player to restart the game when they win or lose.
Add the following else condition to the _update function.
Add the following code to the draw_win_lose function
Finally add a comment with the name of the game to the start of the script and save an image for the cart by pressing F7.
Congratulations!