What You’ll Learn in This Hour:
Peculiarities of the 2D graphics inGodot
Making simple vector math operations
Using 2D cameras
Creating TileSets and TileMaps
Making a parallax background effect
Godot Engine has dedicated tools to work on 2D games. While many of the functions of the engine can be used the same way in 2D
and 3D, some of the topics don’t have a one-to-one comparison. The 2D graphics pipeline is one of these examples. In 3D, you have a
world to explore and position objects, but for 2D, you have only the screen plane to work with.
In this hour, you’ll learn to deal with 2D graphics and how Godot treats the screen plane. You’ll also see some of the specific tools for making
2D games, how they work, and how to use them.
Sprites and Draw Order
The basis of a 2D graphics engine is the Sprite. A Sprite is simply an image that can be drawn anywhere on the game screen. It can also be
scaled, rotated, and flipped, which allows for a great number of visual effects. Before we get deep into how Sprites are used, let’s first talk
about the Viewport, which is where they are drawn.
Viewport Coordinates
The Viewport is a bit different than the Main Viewport in the editor, because now we’re talking about how the game will look when it is running.
You can consider the Viewport as a Cartesian plane where the (0,0) position is the top left corner and the Yaxis goes downward, which is
depicted in Figure 3.1. The Viewport itself can be scaled and stretched in the final game if the user can resize the window, but the coordinate
system remains the same.
FIGURE 3.1
Godot 2D Coordinate System
Draw Order
Nodes are drawn in the tree order. This means that nodes higher in the hierarchy will be drawn first, and thus will be shown behind the bottom
nodes. This is the reverse order of layers, which are usually drawn in image editing software. Figure 3.2 shows a sample of the draw order. If
you want a node to be shown on top, it must be in the bottom of the tree. Note that the children of a node are drawn after it, but they appear
behind the next sibling of such a node.
FIGURE 3.2
Visual example of the draw order. Notice how the Scene Tree dock shows the nodes in the same order they are drawn.
TIP
Remote Transform
Remember that the position and scale of a node is affected by its parent. Sometimes you want that to happen but also want that node drawn
before other nodes above it in the tree. For this use, there’s the
RemoteTransform2D node. You can add it as a child of the node, which
applies the transform and targets the node you want to draw behind. Then you can leave the node higher in the tree and have it affected by
another node’s transform.
Note that you have some other options, such as setting the Z-index of the node (higher Z values are drawn on top) or enabling the Show
Behind Parent property. But the latter option is limited, and the Z value is less performant than the tree order.
Sprites
The Sprite node is very useful for 2D games. It is just a single texture that you can rotate, scale, and position anywhere in the viewport. This
node can be used for characters, props, HUDs, and any other thing that needs an image. Sprites are also great for spritesheet animations,
since you can select a region of the image to show.
Sprite Regions
While the engine documentation explains every property, we’ll see a couple of Sprites’ abilities. One of them is the Region property. It allows
you to show only a part of the texture in the game. This is very useful if you have a sheet image with many items and want to display a single
one without slicing the image.
111111111
22222222In the bottom panel, you can find a Texture Region editor (see Figure 3.3). This tool can be used to visually slice the image and select exactly
the portion you want to show. Note that this tool is only available when a Sprite node is selected.
FIGURE 3.3
Texture Region editor tool.
Frames
If you are making a spritesheet animation, selecting individual regions for each frame can soon become tedious. Godot has a tool to help in
this task: the frames property of Sprite. You can set Vframes to the number of rows the spritesheet has and similarly the Hframes to the
number of columns. Then you set the Frame property to the current frame of the sheet, remembering that it starts with zero. The number of
frames is equal to the number of rows times the number of columns. The frames go from left to right and top to bottom (the same order as
reading a text).
Vectors and Transforms
Let’s take a pause from the engine tools and talk a bit about the theory and math of 2D graphics. While this may seem scary and difficult, this
knowledge will make your game developer life much easier. By using vector math, you can avoid using trigonometry and angle calculations,
and also use the built-in engine functions.
Vector
As stated before, the Viewport can be seen as a Cartesian plane. A Vector is usually described as an (x, y) pair that represents the horizontal
and vertical distance from the axes, respectively (see Figure 3.4). The starting point (0, 0) is where the axes cross each other and is called the
origin.
FIGURE 3.4
A vector in 2D space. The “m” represents the magnitude, which is the length of the vector. The “d” is the angle of the horizontal axis, which is a
visual way to represent direction.
While vectors are used as a position, they can also be seen as a combination of direction and magnitude. If you imagine a vector as an
arrow from the origin to the position it specifies, the direction is where the arrow is pointing and the magnitude is the length of the arrow.
To calculate the magnitude, you can use the Pythagorean Theorem. The length of the vector is the hypotenuse, while the x and y components
are the sides. Thus,
. However, Godot engine already provides a helper function to get the length of a vector: var m =
vector.length().
Vector Operations
There are a few possible mathematical operations with vectors that are very useful to use in games. You can add, subtract, and multiply a
vector with a scalar (that is, a regular number). There are also two vector-specific operations: dot product and cross product (see Figure 3.5).
FIGURE 3.5
Vector operations described visually with graphs.
Addition is done component by component. (1, 2) + (3, 4) = (4, 6). Visually, addition is the same as starting the second vector in the end
of the first one instead of the origin. If you see that as movement, it is the same as moving from the origin to the end of the first vector and
then moving the distance of the second in its direction.
Subtraction is done like addition. (1, 2) − (3, 4) = (−2, −2). It is the same as a vector going from the second one to the first. This is useful
for getting the distance between vectors.
Multiplication with a scalar is the same as multiplying the scalar for each of the vector components. 3 × (1, 2) = (3, 6). The resulting
vector keeps the same direction but has the length multiplied by the other number. It’s called a “scalar” because it scales the vector.
Dot product is a kind of multiplication of vectors, and is defined as the sum of the products of the vector components. (1, 2) · (3, 4) = 1 ×
3+2 × 4 = 11. The result is a scalar, which is equal to the magnitude of both vectors multiplied by the cosine of the angle between them,
or mathematically speaking: a · b = ||a|| ||b|| cos θ. This can be used to get the angle between the vectors, thoughGodot has helper
functions for that too. It is also useful to know on what side of the vector things are.
Cross product is the other type of vector multiplication, and is only defined for three and seven dimensions, so it is not useful for 2D.
The cross product of two vectors result in another vector, which is perpendicular to both. This will be better explained in the chapter about
3D graphics.
Unit vectors
A unit vector is a vector with magnitude of 1. These are very useful when used as direction only, since each can be multiplied by a scalar to
change the magnitude. It is also useful to calculate the dot product of unit vectors, because the result value is always in the [−1, 1] interval and it
has a special meaning: if the vectors are parallel, the dot product is 1; if they are perpendicular, the dot product is 0; and if they have opposite
direction, the dot product is −1.
The process of getting a unit vector from a regular vector is called normalization, and can be achieved by dividing each component by the
111111111
22222222vector magnitude. Godot also has a helper function for that: var unit = vector.normalized().
Transforms
Another mathematical knowledge that is useful for games is how matrices can be used to transform objects. Each node resides in its local
space and is affected by the transforms of its ancestor to determine its position in the global space. You can see that easily inGodot by adding
a Sprite in the tree and another one as its child. Move the parent in the scene, then select the child and see its Position property in the
Inspector dock: (0, 0). You can visually see that it is moving in the scene, but that’s because the node is being affected by its parent transform.
The transform is a mix of translation (or position), rotation, and scale (see Listing 3.1). The translation is the distance between the origins of the
global and local space. The rotation and scale could be represented as an angle and a vector, but it is described as two vectors: one
describes the horizontal position (where the X axis of the node’s local space is located), and the other represents the vertical axis. The three
vectors are joined in a 3 × 2 matrix:
The first two rows are how the X and Yaxis of the local space is transformed, and the last line is the translation. Godot has a Transform class to
help you with those functions.
LISTING3.1 Transformoperations
Click here to view code image
var transform = Transform2D()
var x = transform.x # X axis vector
var y = transform.y # Y axis vector
var o = transform.o # Origin translation vector
The Power of Transforms
The main use of matrices is to store transform operations. If you multiply one transform matrix by another, the result is a matrix that combines
both operations (see Listing 3.2). Note that order matters and while mathematically the last transform is applied first, Godot works in the
reverse order. By default, a Transform is defined with the identity matrix
. This means that no transform is made and the object keeps
its default position, rotation, and scale.
For instance, you can get a simple scale matrix that will change the rota
tion of the node and combine it with another that changes the scale.
LISTING3.2 Combining transforms
Click here to view code image
var rotate_matrix = Transform2D().rotated(deg2rad(90)) # rotate 90 degrees
var scale_matrix = Transform2D().scaled(Vector2(2, 2)) # scale twice in each axis
var translate_matrix = Transform2D().translated
var combined_matrix = translate_matrix rotate_matrix scale_matrix # combine the transforms in order
$my_node.transform = combined # apply the transform to a node
NOTE
Inverse Transform Matrices
Another interesting possibility made available by matrices is the ability to invert the transform. If you apply the inverse matrix, it is the same as
reverting all the transformation. You can, for example, make a node ignore its ancestors’ transform.
Note that the inverse transform only works if the matrix is orthonormalized (i.e., the vectors are normalized and orthogonal to each other);
otherwise, you need to get the affine inverse to correctly apply the inverse transform. Godot provides both as helper functions.
Cameras
It is not uncommon for a game to have levels bigger than the window. In an RPG, the player usually has a large world to explore. That’s where
Cameras come in. Instead of moving the whole world to fit the viewport, you can simply add a Camera and make it follow the player.
The
Camera2D is like every other node: you place it in the Scene Tree wherever you want it to be. It is commonly placed as a child of the
character’s root node so it follows the player around. The node itself is very simple. Here is a breakdown of its major properties:
Offset: This changes the camera center. Instead of moving the camera’s position, you can set the offset to make the camera scroll. It is
very useful for making animations, such as a shake effect, and it’s easily reset to the original place.
Anchor Mode: This sets whether the follow node should be on center and respect margins (Drag Center) or if it remains fixed on the
top left corner (Fixed Top Left).
Rotating: This designates whether the Camera should rotate with the parent. If it rotates, you’ll see the world rotating instead of the
target node.
Current: This sets the active camera. There can be only one current camera per viewport.
Zoom: This changes the zoom of the view. Larger numbers make things seem further away.
111111111
22222222Limits: This limits how far the camera can go. It’s useful for not letting the camera out of the level boundaries.
Drag Margins: You can make the camera stay still if the parent is moving only inside the drag margins. It’s also possible to enable
individually for the horizontal or vertical axis.
Smoothing: If enabled, the camera will have smooth transitions of speed instead of abruptly moving and stopping. You can also set the
smoothing when reaching the camera’s limits.
NOTE
Split Screens
Cameras are very useful when implementing split-screen games. You can have a camera for each player and make them render in different
Viewport nodes. This feature is better explained in the chapter about Viewports.
TileMaps
Another common feature in 2D games is the TileMap. It allows you to make a set of tiles and use them to create the screens of your game. Not
only does this reduce the amount of art you need, it also helps you quickly create large and varied levels. Godot has the
TileMap node
specifically for this purpose.
Making a TileSet
Before creating your game stages with TileMaps, you need first to create a
TileSet resource. Godot has a way for you to transform your
source images into a resource that the engine can understand and use. You can either use a single image for your whole TileSet or split each
tile into its individual file.
TRY IT YOURSELF
Create your TileSet
Grab your favorite tile set image(s) and learn how to make your own TileSet resource by following these steps:
1. Copy your tile set image(s) to the project.
2. Create a new scene and add a
Node2D as the root.
3. Save the scene as “tileset-source.tscn”.
4. Add a
Sprite as a child of the root and rename it to m
a
tch your tile.
5. Set the Sprite’s texture as the image for your first tile.
6. If needed, set the Region property to match your tile.
7. If you need physics collisions, add a
StaticBody2D as a child of the Sprite. You’ll also need a
CollisionShape2D, as
seen in the chapter about physics.
8. Repeat steps 4 to 7 until all the tiles are added.
9. Save the scene.
10. Click on the menu Scene –> Convert To –> TileSet.
11. Save the file as “tileset.res”. This is your TileSet resource!
TIP
Grid and Snapping
While you don’t need to set the position of the Sprites in the scene to create the TileSet, it is nice to have all of them visible. In this task, you
may find it difficult to position the tiles next to each other. This is where the grid and snapping functions can help.
In the toolbar on the main viewport, you’ll see the Edit menu. There, you can enable the Use Snap and Show Grid options. The grid will likely
not match your tile size by default, but you can configure it in the same menu by clicking on the Configure Snap option. Then you can set the
Grid Step option to the same size as your tiles. It’ll be much easier to organize your tile set in the scene.
Using TileMaps
Now that you have a TileSet resource ready, let’s use it to make a game stage. Using a TileMap is very simple; you just need to add a
TileMap node to the scene and set its
TileSet property to the file you just created. You can do that by dragging from the FileSystem to the
Inspector dock. You also need to set the Cell Size property to match the size of your tiles.
Once you select the TileMap node on your scene, the editor will change to show the palette of tiles in the left of the Main Viewport and show a
grid to help you position your tiles. The process of composing a stage is simply selecting the tile you want on the list and clicking on the scene
where you want it to appear. If you right-click on a place in the map, the tile is cleared.
There are a few contextual items on the toolbar for TileMap creation. Here’s a breakdown of them:
Tile position: The first item shows the current position of the mouse in tile coordinates. It also shows the name of the tile placed in the
111111111
22222222position. This is useful if you need mathematical precision when placing the tiles.
TileMap: This menu has a few functions to edit the map. The next bullets will cover the items of this menu.
Bucket: This option works similar to painting programs by filling an enclosed area with the same tile.
Pick Tile: It’s the same as the eyedropper function of painting programs. It allows you to select the tile under the cursor to become the
active tile for painting.
Select: This allows you to select a portion of the map.
Duplicate selection: This makes a copy of the selection and lets you place it elsewhere in the map.
Erase selection: This deletes the currently selected tiles.
Transpose: This changes the rows of the tile into columns and vice versa. Visually, it’s the same as rotating 90[dg] to the left and
mirroring the image.
Mirror X: Mirrors the tile in the horizontal axis.
Mirror Y: Mirrors the tile in the vertical axis.
Rotate Buttons: Rotate the tile by 0[dg], 90[dg], 180[dg], and 270[dg], respectively.
TIP
Third-party TileSet and TileMap Tools
There are several third-party tools to make TileSets and TileMaps, such as the Tiled Map Editor. While Godot does not support those out of
the box, you can find plugins in the Asset Library. There are also plugins to split your tile set image automatically into a TileSet resource.
Other Projections
Orthogonal TileMaps are the most common type, so it is Godot’s default mode. But it is also possible to make isometric and hexagonal maps.
For the Isometric mode, you need to change the TileMap mode from Square to Isometric. The editor will automatically change to show the
tiles in the way you want. For Hexagonal mode, you can keep the mode on Square, but change Half Offset property to either Offset Yor
Offset X, depending on the map orientation. This will make the grid look like a “brick wall,” where the rows or columns have an offset in relation
to the previous one.
You can also make a custom projection by selecting the Custommode and changing the CustomTransformproperty to your own transform
matrix.
ParallaxBackground
Another interesting and useful node is the ParallaxBackground. It allows you to easily make the parallax effect, in which distant objects seem to
move more slowly than closer ones. This effect is common in side-scrolling games and gives another depth to the visual aspect of your game.
ParallaxBackground Node
The node itself is a helper for you to achieve the desired effect. Together with the ParallaxLayer node, this provides all the options for you to
customize the parallax background. Let’s break down its properties:
Offset: This designates how much of the background is offset. This is set automatically if you have a Camera2D, but can otherwise be
set with code or animations to make effects (such as clouds moving).
Base offset: This sets the base value for the offset property of the children of ParrallaxLayer nodes.
Base scale: This is the base scale value for the children of ParallaxLayer.
Limit begin/end: This is the limit to where the background will scroll. The “limit begin” marks the top-left limit, while “limit end” sets the
bottom-right limit. The background will stop scrolling as the camera reaches outside those limits.
Ignore camera zoom: If enabled, the background will ignore the camera zoom property and will be drawn at its regular size.
ParallaxLayer Node
The ParallaxBackground works by having multiple ParallaxLayer nodes as its children (see Figure 3.6). Each layer works as a plane in a
distant position. By having multiple layers, you can make each layer move at its own speed, giving the parallax effect you want. This node has
only three properties:
FIGURE 3.6
Parallax background sample
Scale: This is how much this layer moves relative to the background offset. Lower values make it go slowly, and it’s used for further
layers. You can set different scale values for each axis.
Offset: This is the starting offset of this layer. This makes the layer start in a different position.
Mirroring: This is the size of the layer frame. Once it passes the size defined here, the layer will start repeating. Note that if this property
is less than the screen size, it may not work as intended.
111111111
22222222TRY IT YOURSELF
Make a ParallaxBackground
This effect is much more interesting when seeing it in practice. Follow these steps to make your own project:
1. Make a new project and add the images for the background, ship, and stars into its folder.
2. Create a new scene and add a
Node2D as the root.
3. Save the scene as “parallax-background.tscn”.
4. Add a
Sprite as a child of the root and name it “ship”.
5. Set the Sprite’s texture as the ship’s image.
6. Add a
Camera2D node as a child of the ship. Set it as Current using the Inspector dock.
7. Add a
ParallaxBackground node as a child of the root.
8. Add a
ParallaxLayer as child of the previous node. Set its Scale to (0.2, 0.2). This will be the back one.
9. Add a
Sprite as a child of the layer and assign the background texture to it. Stretch it to fill the viewport.
10. Add the small stars as Sprites. You can do that easily by selecting the ParallaxLayer node and dragging the star image from the
FileSystem dock to the viewport. They’ll be added to the tree as sprites and children of the selected node.
11. Create another
ParallaxLayer as a child of the ParallaxBackground. Set the Scale to (0.5, 0.5). This will be a closer layer
so it’ll move faster.
12. Add the big stars as children of the last ParallaxLayer.
13. Add a new script to the Ship node with the code in Listing 3.3.
14. Save the scene and play it. You can move the ship using the arrow keys of your keyboard or the d-pad of a joystick. The parallax
effect should be visible when you move it.
LISTING3.3 Ship Movement
Click here to view code image
extends Sprite
export var speed = 500
func _process(delta):
var direction = Vector2()
if Input.is_action_pressed(“ui_left”):
direction.x = -1.0
elif Input.is_action_pressed(“ui_right”):
direction.x = 1.0
if Input.is_action_pressed(“ui_up”):
direction.y = -1.0
elif Input.is_action_pressed(“ui_down”):
direction.y = 1.0
var velocity = direction speed delta;
position += velocity
Summary
In this hour, you gained a lot of knowledge about 2D graphics not only inGodot but in general. You learned how Sprites work and in which order
nodes are drawn. You saw how vectors and matrices help deal with transformation of objects in the screen. You also learned how to use 2D
cameras, tile maps, and the ParallaxBackground effect.
Q&A
Q. What are the other 2D nodes?
A. There are a lot of nodes for use in 2D: all the descendants of
Node2D and a few more. Some of them are covered in other chapters,
but some are out of the scope of this book. You can learn about them in the engine documentation.
Q. Why there are some artifacts when I use a region of a spritesheet?
A. The filtering of textures may cause artifacts if the Sprites are close together. This can be fixed either by disabling the filter of the texture in
the Import dock or enabling the Filter Clip property of the Sprite.
Q. Vector math seems too complicated. Do I really need to learn it?
A. While it’s not essential, it’ll make your game code much easier to make and cleaner, especially in complex movements. Without that, you’ll
have to rely on angles and trigonometry, which can become even more complicated.
111111111
22222222Workshop
See if you can answer the following questions to test your knowledge.
Quiz
1. True or False: the children of a node are drawn before their parent.
2. How can you show only part of an image using a
Sprite node?
3. What happens if you multiply two transforms?
4. Is it possible to multiply a vector by another?
5. What is the purpose of the
Camera2D node?
6. True or False: Godot needs an external tool to deal with tile maps.
7. What does the Scale property of the
ParallaxLayer node do?
Answers
1. False. The parent nodes are drawn before their children.
2. Enable the Region property and set its Rect to the desired portion of the image.
3. You get a new transform that combines the effects of the two.
4. There are two ways to multiply vectors: the dot product and the cross product.
5. It serves to move around and show the level that is bigger than the window.
6. False. Godot has tools to make TileMaps inside the editor.
7. It changes how fast the layer moves in relation to the background offset.
Exercises
Here are few exercises to get yourself acquainted with 2D graphics.
1. Create a new scene with a
Sprite as the root. Set its texture to some image.
2. Add another Sprite as its child, set its texture, and move it away from the start position.
3. Move the root node around and see how the child moves.
4. Add a
RemoteTransform2D node as a child of the root and assign its Remote Path property to the other child of the root.
5. Move the RemoteTransform2D around (use the
Move tool). See how the target Sprite moves around to follow it.
*6. Save the scene and play it to see the results.