maps
mget
The mget()
function in PICO-8 is used to retrieve the sprite number of a tile on the map. It takes in two arguments, column and row, which represent the coordinates of the tile you want to retrieve.
mget( column, row )
mget | "map get" |
column | number of tiles from the left (8 pixels in 1 tile) |
row | number of tiles from the top (8 pixels in 1 tile) |
returns: | sprite number |
If you open the map editor, and hover your mouse over the map canvas, you can see the column and row number as x and y values in the bottom left corner.
Get Map-Drawn-Sprite near Code-Drawn-Sprite
Often times, you will be drawing sprites to the screen using pixel coordinates, but this function uses tiles instead of pixels. So to use this function alongside sprites that you draw on your screen using code instead of using the map, you will probably need to convert pixel coordinates over to tile coordinates and that can be as simple as by dividing by 8. Here's an example using a player that is at position (X,Y), and finding the map tile to the right of the player based on the player's pixel coordinates.
In this picture, we have the player that is standing at about (30,50) in terms of pixels. And the flower to the right of her is at map position (5,7) in terms of tiles. So here is how we can check what sprite the player is standing next to in code using mget()
.
player_column = player_x / 8
player_row = player_y / 8
sprite = mget( player_column + 1, player_row )
First we convert the player_x
into a map column by dividing by 8. Then we do the same with player_y
to get the map row. Finally, we create a variable named sprite
to get the sprite number that will be returned by mget
, after it checks the correct column and row. Notice that the code adds 1 to the column number so that mget
will actually look 1 tile to the right of the player and find the flower.
This is useful for finding certian things on the map near the player. For example, you might want to check for a door on the map or walls for collision.
Checking Sprite Flags on the Map
You will also probably want to use mget
alongside sprite flags. Sprite flags let you group sprites of a certain type together. So in the above image, you can see a pink flower and a blue flower. If we wanted to check if the player stands next to a flower, then we need to check the sprite numbers of both flowers. But if we used flags instead, then we can make both the blue and pink flowers have the same flag turned on.
Once you have flags turned on to group sprites used on your map, you can use fget( sprite_number )
to get the flag number. Notice that fget
takes a sprite number, which is exactly what mget
returns! So you will often see PICO-8 games that do two things at once:
flag = fget( mget( tilex,tiley ) )
These are two functions that are often used together and this might look strange to place one function as an argument of another function, but it's a great way to make your code more efficient. To demonstrate that, here is what that same code would look like if we wrote it out on multiple lines:
sprite_number = mget(tilex, tiley) flag = fget(sprite_number)
So we are saving the sprite number that mget returns in a variable, then immediately using that variable to pass to fget in order to get the flag. But if that's the only reason we get the sprite number, then it's a waste of setting a variable. However, it is easier to read and understand what the code is doing, so you'll see programmers writing it the second way for that reason.
1967
10 Apr 2023
mset
The mset()
function in PICO-8 is used to set the sprite for a tile on the map. It takes in three arguments: column, row, and a sprite number.
mset( column, row, sprite )
mset | "map set" |
column | number of tiles from the left (8 pixels in 1 tile) |
row | number of tiles from the top (8 pixels in 1 tile) |
sprite | sprite number |
If you open the map editor, and hover your mouse over the map canvas, you can see the column and row number as x and y values in the bottom left corner.
Changing Map Sprite from Player Interaction
Often times, you will be drawing sprites to the screen using pixel coordinates but, just like mget()
, this function uses tiles instead of pixels. So to use this function alongside sprites that you draw on your screen using code instead of using the map, you will probably need to convert pixel coordinates over to tile coordinates and that can be as simple as by dividing by 8.
In this example, we have a player drawn at (x,y) in pixels, standing next to a flower sprite that is drawn on the map.
Let's say we want to allow the player to pluck the flower. We can interact with the map by changing the flower sprite on the map to a flowerless sprite.
player_column = player_x / 8
player_row = player_y / 8
flower_column = 4
flower_row = 5
flower = 20 --sprite #
flowerless = 21 --sprite #
if player_column+1 == flower_column
and player_row == flower_row
and btnp(4) then
mset( flower_column, flower_row, flowerless )
flower_inventory+=1
end
This is useful for changing certain things on the map, when something happens. In the code above, we check if the player is standing next to the flower, and if they press button #4, then set the flower sprite to be flowerless and add a flower to the player's inventory count. This will change the sprite on the map and make the player look like they are able to pluck the flower, allowing sprites you draw over the map to interact with the map.
1444
10 Apr 2023
map
map( mx, my, [sx, sy,] [w, h,] [layers] )
mx | "map x" number of tiles from the left (8 pixels in 1 tile) |
my | "map y" number of tiles from the top (8 pixels in 1 tile) |
sx | (optional) "screen x" number of pixels from the left |
sy | (optional) "screen y" number of pixels from the top |
w | (optional) "width" number of tiles wide of the map to draw |
h | (optional) "height" number of tiles tall of the map to draw |
layers | (optional) a bitfield value referring to sprite flags to draw only the sprites with those flags |
It is possible to call map()
without any arguments at all. This will draw the map with all default values:
map()
map(0, 0, 0, 0, 16, 16, 0) --default values
Both of the above lines of code will draw the map from its top-left corner (0,0) to the screen's top-left corner (0,0) for the entire width and height of one screen (16,16) and without specifying a sprite flag (0) meaning draw all sprites from the map.
Map Coordinates to Screen Coordinates
It is important to notice and understand which arguments take map coordinates (in number of tiles) and which take screen coordinates (in number of pixels). Here are some examples to help understand how to control what part of the map is drawn to what part of the screen.
For most games, you will simply want to draw the map exactly as it appears in the map editor and so you can use the default map()
arguments. Here's how that works:
For these examples, we will use the demo game "Jelpi" made by zep, the creator of PICO-8.
Notice in the above image, when we hover the mouse over the top-left corner of the map editor, the X and Y coordinates at the bottom of the screen show as x:000 y:000
which means that tile's map coordinates are (0,0)
. Compare that to when we hover over this star tile, which shows x:020 y:008
which means the star tile's map coordinates are (20,8)
. Seen here:
Those map coordinates means that the star tile is located at 20 tiles to the right and 8 tiles down from the top-left corner of the map. If we draw the map to the screen using the default arguments like this:
function _draw()
cls()
map()
end
Then the full width and height of the screen will be drawn with same width and height of the map, starting from the top-left corner of the map, and drawing to the top-left corner of the screen. If we replace all of Jelpi's code with only with the above draw function, this is what we get:
One screen is only 16 tiles wide, so we do not even see the star tile because it is at map column 20, 4 tiles farther to the right. Now lets use the map function to draw a more specific part of the map to the screen. Let's draw the pink bricks with the star instead. First find the map coordinates of the top-left corner of what you want to draw:
We will use this (18,7)
to be the arguments (mx,my)
. The next arguments are (sx,sy)
and we'll leave those at (0,0)
. Next we need to know how wide and tall the area on the map that we want to draw, so we'll find the bottom-right corner of what we want to draw:
However, the width and height arguments are not the map coordinates. So we must do the math or simply count to get the number of tiles wide and tall:
Now we have the arguments we need to draw only this part of the map to the screen:
function _draw()
cls()
map(18,7, 0,0, 5,4)
end
We have spaced out the arguments so it is easier to see the mx,my of (18,7)
, the sx,sy of (0,0)
, and the w,h of (5,4)
. And here is what we will see if we run this code in the Jelpi demo cart:
Now that we can control the part of the map that we draw, let's control the part of the screen that we draw it at. Remember that the sx and sy arguments are in pixels, not tiles.
To think with screen coordinates in pixels, remember that the top left is (0,0), the bottom-right is (127,127), and the center is (63,63). You might think I mean 128 and 64, but since we start counting from 0 instead of 1, that means the last visible pixel on the default screen is #127 and the center is #63.
(screen coordinates in pixels)
Knowing that, we can get an idea about where to place something using screen coordinates. Let's say we want to draw those pink blocks where we've drawn this blue rectangle:
That small blue square in the top-left corner is the pixel we need to use for the screen coordinates of where to start drawing our piece of the map. Since it is to the left of center, then it must be a little less than 63 X, so let's try 40 X. And since it is lower than center, then it must be a little more than 63 Y, so let's try 70 Y. Putting all these arguments together and setting the screen coordinates of sx,sy to be (40,70), the code will become:
function _draw()
cls()
map(18,7, 40,70, 5,4)
end
And here is what that will look like:
Map Layers Argument
The last argument in the map() function allows you to select exactly which sprites from the map to draw to the screen. You may want to do this in order to creates layers of the map, paralax scrolling, or perhaps a game mechanic where you can toggle which tiles on the map are visible.
It's a little tricky because you don't just pass flag indexes into this argument. Instead, you pass a layer index which refers to one or more flag indexes. To demonstrate this, we have set up one sprite for each flag that displays the flag color and index on the sprite and we have turned on only that one flag to the corresponding sprite.
Sprite Editor
Map Editor
With that prepared, we drew these sprites on the map in larger blocks. Now, when we draw this colorful map to the screen, and turn on specific layers, we will clearly see which flagged sprites are drawn using which layer index value. Let's first explain what we mean by the difference between a flag index and a layer index.
The flag index is straight forward and we are already displaying it in each of the sprites. The layer index for each flag begins at 1, and ends at 128. This is because there are 256 different combinations of these 8 flags. So you can pass any number from 0 to 256 to the layers argument, and you will draw one unique combination of sprite flags to the screen.
For example:
layers = 0 --default, all sprites
function _draw()
cls()
map(0,0, 0,0, 16,16, layers)
end
But if we change layers
to 1, that matches the layer index of flag #0, and so only sprites with the first flag are drawn:
layers = 1
function _draw()
cls()
map(0,0, 0,0, 16,16, layers)
end
Next, if we change layers
to 2, that matches the layer index of flag #1, and so only sprites with flag #1 are drawn:
layers = 2
function _draw()
cls()
map(0,0, 0,0, 16,16, layers)
end
However, here is where it gets tricky and where it also starts to make sense. If we change layers
to 3, that no longer matches any layer index of a specific flag, but layer indexes 1 and 2 do add up to equal 3:
layers = 3
function _draw()
cls()
map(0,0, 0,0, 16,16, layers)
end
And so we have found our first layer index that creates a combination of multiple sprite flags. This pattern continues so that when the layers
argument matches a layer index of one flag, then only that flag is drawn, otherwise the layers
argument is a combination of layer indexes that add up to the layers
value.
layers = 4
layers = 5
layers = 6
layers = 7
layers = 8
layers = 9
Here are some more random numbers between 0 and 256. If you add each of the flag's layer index, you will always get the value we set in the layers
argument.
layers = 85
layers = 145
layers = 127
layers = 128
layers = 200
layers = 255
Notice that when the layers
argument is 255, it looks the same as the default of 0, but it will not draw sprites that do not have flags. If we increase the value by just one more to 256, then it will not draw any sprites at all, whether those sprites have flags or not.
layers = 256
Now that you understand how the layers
argument works to add up the layer indexes of each flag, you don't have to actually figure out the layers value for just the right combination of flags. Instead, you can simply pass the sum of layer indexes.
So you can make it easier on yourself like this:
flag_0=1
flag_1=2
flag_2=4
flag_3=8
flag_4=16
flag_5=32
flag_6=64
flag_7=128
layers = flag_4 + flag_6
function _draw()
cls()
map(0,0,0,0,16,16,layers)
end
3324
12 Apr 2023
tline
TLINE(X0, Y0, X1, Y1, MX, MY, [MDX, MDY], [LAYERS])
x0 | number of pixels for the x coordinate of starting the line |
y0 | number of pixels for the y coordinate of starting the line |
x1 | number of pixels for the x coordinate of ending the line |
y1 | number of pixels for the y coordinate of ending the line |
mx | "map x" number of tiles on the map from the left (8 pixels in 1 tile) |
my | "map y" number of tiles on the map from the top (8 pixels in 1 tile) |
layers | (optional) a bitfield value referring to sprite flags to draw only the sprites with those flags |
The TLINE() function draws a line on the screen using colors sampled from a map. You specify the starting point (X0,Y0) and the ending point (X1,Y1) of the line, and the function will use colors from the map to draw the line.
You can also specify the location on the map (MX, MY) to sample colors from, and an optional offset (MDX, MDY) to adjust the sampling location after each pixel is drawn. Additionally, you can specify the layers of sprites to be drawn along with the line.
(More explanation and examples to come)
1404
11 Apr 2023
In game development, a map is a virtual representation of a game world or level that the player can navigate through. It typically consists of a grid or other layout that includes various objects, obstacles, enemies, power-ups, and other game elements. Maps can be 2D or 3D, and can range in size from a single screen to a vast open world.
A map editor is a tool used to create, modify, and manage game maps. It allows game developers to design and customize the layout of game levels, including the placement of game objects, to create the overall design.
Here is an example of a 2D map, used in a side scrolling platformer, from the demo cart "jelpi.p8".
Jelpi Map Editor
Jelpi Gameplay
Here is an advanced technique of taking a 2D map from the map editor and rendering it to make it look 3D in PICO-8. This is also from a demo cart named "cast.p8". This is not a built-in feature of PICO-8, but it is possible using code with a technique called "ray casting".
Cast Map Editor
Cast Gameplay
Overall, map editors are an important part of game development, as they allow developers to create and iterate on game maps quickly and efficiently, while also giving them the freedom to be creative and experiment with different designs.
Game maps can be created using the map editor, or pure code, or a mix of both.
Using a map editor can be a good option if you're just getting started with game development and want to focus on creating maps quickly and easily. With most games, you'll want to use the map editor, but also draw what appears as background using code. The map tends to be good for static objects, while it is easier to update and draw moving or animated objects on top of the map in code.
Using pure code to create a map can be more complex, but also offers more flexibility and control over the map generation process. You can write code that generates maps based on certain rules or algorithms. For example, you could write a script that generates a maze-like map by randomly placing walls and corridors, or a script that generates a terrain map by applying various noise algorithms to a heightmap. Some of the more complex games in PICO-8 don't use the map editor in a traditional way, and instead use the map's data storage space to fit more in their game.
1121
15 Sep 2023