collision:
Map and Flags
If your game uses the map as anything more than a background, then you'll want some form of map collision. Map collision, in its simplest form, is checking the tile on the map and finding out what type of sprite is drawn there. You can keep it as simple as that or make it as complex as you need by saving information on your sprites to know how they should interact with your game objects.
No Collision
PICO-8 Collision Function
function map_collision( tile_x, tile_y, flag )
return fget( mget(tile_x,tile_y), flag )
end
Storing Pixel Coordinates
First, you'll probably need an easy way to store the coordinates of an game object that will be moving around over the map. We can do that with a table that stores X and Y variables specific to that object. This would be the pixel coordinates of where the object is on the screen, between 0 and 127.
It would be created like this:
--create an object table
obj = { x=10, y=20 }
Now that we have a table with coordinates X
and Y
, we can get the value out of the table with obj.x
. (See Table Shorthand)
--get value out of object table
print( obj.x ) --prints 10

Map Tile Coordinates

Tile Coordinates are displayed in bottom left of map editor.
The map does not use pixel coordinates. Instead, it uses tile coordinates. Each tile is 8x8 pixels. So on a screen of 128x128 pixels, there are only 16x16 tiles. To convert from pixels to tiles, you just divide by 8.
tile_x = obj.x / 8
To make sure that we don't get a fraction, we will want to round down after dividing. We can do that two ways:
--option 1: floor function
tile_x = flr( obj.x/8 )
--option 2: floor division
tile_x = obj.x\8
The floor function will round any number down to its nearest integer (whole number). If you want to floor after dividing like we do here, then we can use a backslash "\", which is a special operator for dividing AND rounding down.
So understanding the difference between pixel coordinates (which most game objects are saved in) and tile coordinates (which the map is saved in) is necessary when we want to compare an object's screen placement with the map's sprites.
--pixels to tiles
tile_x = obj.x\8
tile_y = obj.y\8
If you play with the demo at the top of this page and click "Show Measurements" button, you will see how the point at the mouse cursor, has X and Y pixel coordinates, and we convert that to "Map Tile" coordinates.
That's how we get tile coordinates to use in this map collision function...

Getting Sprite from the Map
The next step is to look at those map tile coordinates and find out what sprite is currently drawn there. PICO-8 has a built in function to do this named mget()
, which stands for "map get".
sprite = mget( tile_x, tile_y )
The sprite
variable will store the sprite number that mget
returns. Make sure to use tile coordinates for this function, not pixel coordinates.
At this point you could simply compare sprite
with a specific sprite number that you want to look for. And that is the simplest form of map collision you could use in your game. For example, if you only use 1 sprite for all the walls in your game, then you just check for that one wall's sprite number.

wall = 1 --sprite number
tile_x = obj.x\8
tile_y = obj.y\8
sprite = mget( tile_x, tile_y )
if sprite==wall then
--cannot move here
end
However, for more visually interesting games, you'll want many variations of the same sprites that you can group together as types, for example: walls, plants, rocks, signs, doors, etc. Those would be too many sprite numbers to check them one by one, so instead, grouping them all as "solid" is a better idea. We can group sprites like this by turning on sprite flags....

Using Sprite Flags
Here is an example where we draw a bomb sprite and add a sprite flag to it in the sprite editor. Read more about how to use sprite flags under this guide page.
Now that we are using a flag, we can find out what flag a sprite has from another built-in function named fget
. It is common to use mget()
and fget()
together, since mget()
will find what sprite is on the map, and provide the sprite number, which fget()
will use to find out if it has the certain flag you are looking out for.
bomb = 0 --flag number
sprite = mget( tile_x, tile_y )
is_bomb = fget( sprite, bomb )
The is_bomb
variable will be true or false if the sprite has the bomb
flag number because fget
compares the two and returns true if they are equal.
By using a flag, we can draw many more bomb sprites or other hazards, and simply give them all the same flag, then the game's collision will treat all those sprites placed on the map the same way.
The sprite flags have no meaning by themselves. They are just numbers, so it is up to you to designate meanings to those numbers and group sprites any way you'd like, for example:
Flag # | Arbitrary Meaning |
---|---|
0 | Sprites that are solid. (all walls) |
1 | Sprites that are collectable. (all items) |
2 | Sprites that are dangerous. (all hazards) |

Understanding an Expanded Version
Now that you know how map tile coordinates and sprite flags work, we just need to compare what flags the tiles on the map have with the type of sprite we are looking for.
Step 1: get the sprite number at a certain location on the map, using tile coordinates.
Step 2: get the flag(s) of that sprite, using the sprite number.
Step 3: compare the flag(s) of the sprite to the flag you are looking for.
We can put all that together into an expanded function like this:
--expanded example
function map_collision( tile_x, tile_y, flag )
--get sprite number from map
local sprite = mget( tile_x, tile_y )
--get flags of that sprite number
local tile_flag = fget( sprite )
--compare sprite flag with target flag
if tile_flag == flag then
return true
else
return false
end
end
This function has parameters (tile_x,tile_y,flag)
and it is expecting those to be numbers. However, by expanding out each step of the function, we've actually changed how it will work a little. If you use the function above, you'll need to change what flag number you are looking for. Instead of just 0-7 flags, this will return a unique number between 0 and 256, which is how you could create many many flag meanings by using a combination of the 8 sprite flags.
Read more about how to use multiple sprite flags under this guide page.
The logical steps of the function remain the same, and from this example, it is easier to understand what shortcuts we use to condense the function down to just one line.
You can call this function in two ways to catch the returned true or false result:
--catch result in a variable
is_colliding = map_collision( obj.x\8, obj.y\8, 0 )
if is_colliding then
print("collided!")
end
--directly inside an if statement
if map_collision( obj.x\8, obj.y\8, 0 ) then
print("collided!")
end
If you don't know why we use obj.x\8, obj.y\8
, read the above section: "Understanding the Map".
Understanding the Simplified Version
We can simplify and condense the expanded version down to a single line:
--simplified version
function map_collision( tile_x, tile_y, flag )
return fget( mget(tile_x,tile_y), flag )
end
This works the exact same way because all 3 steps of the function are happening in this one line. Read the line from inside out to follow the steps of the logic and to understand how this line gets resolved.
Step 1: mget(tile_x,tile_y)
This function will return the sprite number at those coordinates on the map. Instead of saving that to a variable, it is immediately being passed to fget()
as argument 1, which is where fget expects to get a sprite number. This is why you'll often see mget
inside of fget
working together like this.
Step 2: fget( [sprite_number], flag )
This function will take the sprite number from mget
and get what flags that sprite has. Since we also provide a flag as the second argument, the fget
function will also compare the sprites flag with the flag number we pass to it.
Step 3: return [true or false]
The fget
function will resolve to true or false since it is already doing the comparison of flags for us. So we can just return
the result of the comparison immediately in a single step and it does the same thing as the expanded "if true then return true, if false then return false" redundant logic. The fget
function compares the flags, and our map_collision
function simply return the result.
This is as simple and useful as we could make it, but we also wanted to provide you with a potentially more useful version of this map collision function which you can customize even further...
Understanding an Abstracted Version
We can customize this map collision function to be easier to use in our games, depending on how we are going to use. For example, if your game uses object tables for your player, items, and enemies that move on top of the map, and you know that you will want them all to interact with solid walls on the map, then you could realize that you will be doing a lot of converting from pixel coordinates to tile coordinates in order to pass the tile_x and tile_y arguments to the map_collision function, like this:
tile_x = player.x\8
tile_y = player.y\8
if map_collision( tile_x, tile_y, 0 ) then
--player hit a wall
end
You would have to do that for each player, item, and enemy in your game before you could use the simplified map_collision
function above. That's why we wanted to provide an example of how you could make it a little easier on yourself if your game uses a lot of object tables.
In this version, you simply pass an object table and let the collision function convert the coordinates for you:
--abstracted version
function map_collision( obj, flag )
local x,y = obj.x\8, obj.y\8
return fget( mget(x,y), flag )
end
Map Collision can be used in many creative ways. Classic games such as Link's Awakening is a good example where the character is mostly walking on top of a map, and where each map sprite has a designation like sprite flags to determine how Link interacts with those spaces on the map.
If we were to recreate this scene in PICO-8, Link's sprite is the only object table, able to move around on top of everything else that is drawn on the map. But thanks to flagging the different sprites on the map, it will feel like Link is actually in the space, not just drawn on top of it. The floor tiles are walkable, the wall tiles are not, and the doorways trigger a scene change to the next room. All of those interactions are done with just map collision!
Flag # | Arbitrary Meaning |
---|---|
0 | (red) Sprites that are solid. |
1 | (blue) Sprites that are floors. |
2 | (green) Sprites that are doors. |
Another example could be side-scrolling platformers such as Kirby's Dreamland. This could use the map but you may be surprised that it is for the midground not the background. The background could be made as separate layer(s) of the map to create the parallax scrolling effect, but those layers would not need map collision. Otherwise, the background sky is drawn and animated in code.
The midground however is where the main map is being used, where it designates which sprites are ground and platforms and which are passable. Kirby would be an object table, as well as the enemies and items being thrown, and they get drawn on top of the map and interact with the certain map sprites that are flagged as solid ground.
Flag # | Arbitrary Meaning |
---|---|
0 | (red) Sprites that are solid ground/platforms. |
1 | (blue) Sprites that are passable. |

48
21 Apr 2025