Build your first game
Pt2. Creating a GMAP Node
Published: Tue May 27 2025 00:29:52 GMT+0000 (Coordinated Universal Time)
Explanation
Most sections will have an explanation in front, feel free to skip to the instructions section if you want to just get to the results.
A quick definition of scene from the user manual:
“In Godot, you break down your game in reusable scenes. A scene can be a character, a weapon, a menu in the user interface, a single house, an entire level, or anything you can think of. Godot's scenes are flexible; they fill the role of both prefabs and scenes in some other game engines.
You can also nest scenes. For example, you can put your character in a level, and drag and drop a scene as a child of it.
A scene is composed of one or more nodes. Nodes are your game's smallest building blocks that you arrange into trees. “
Every node in Godot has different built in methods and properties and is part of why godot development is so easy, as just by picking the node you’ll have dozens of functions for that task. The first node you pick in a scene is considered the Parent Node.
The first scene we are going to make is a GMAP node, this is a custom node that comes with the addon folders. It inherits from the standard 2D node, and anything a 2D node can do this node can as well, as well as the added functionality.
The main thing the GMAP node does is it’s editable using the GMAP editor window which is accessible. You can certainly create games without GMAP, but its purpose is to aid in designing more complicated levels and avoid needing to remember where everything is located.
It also has a handful of helpful functions to aid in development that we will cover.
So for our 2D platformer, it is going to be the node we pick as our game room.
Then we will set the size of our first GMAP node.
Instructions
Ctrl+F8 go to scene tab
CTRL + A (If a node is previously made, CTRL+N first) to Open “Create new node” window
Focus should be in the search bar, type in GMAP, spelled G M A P (in case the screen reader ignores the G.)
press enter to create GMAP as the root node for your new scene
Focus should be on your node on a list of items, press enter to rename it, type in Game, enter.
ctrl+f6 goes to the inspector tab, where all built in attributes/variables of a node can be edited.
Ctrl + U will take you to the top of the inspector tree, skipping past the search bar and several other options.
Down one more time to node size.
Tab to move focus edit field, enter, type in 64. This means each “sector” in the map editor will be 64 by 64 pixels.
Enter to exit edit mode
Press down until you find ROWS, press tab, type 11, enter
Press down until you find COLUMNS, press tab, enter 11, enter
This means our first room will be 11 sectors by 11 sectors, with each sector being 64.
Ctrl+s to save, leave the name default, press ENTER, saving our first scene.
Creating Player and Ground scenes.
Explanation:
We now have an empty scene that will be the primary container of our game. But we need things to put in it.
Next we are going to create two scenes that we will interact with a lot.
First we will create our floor. There is a special node called staticbody2d that is perfect for floors, then once we create the scene we can create as many instances of it as we want. As part of making the floor, we are going to assign an image and a collision box.
The second scene we will create is the player. Our player will have a root CharacterBody2d. A node that comes with a variety of functions specifically for making a character that moves via code, and by default understands that colliding on different sides means different things. Much of our focus will be on our player throughout this tutorial. It will get the camera and 2DListener node, and what is allowed to happen will be based on its state. So it’s going to get a good number of nodes.
Additionally we are going to use a built-in GMAP function to make a collision box and give it a color. Without this code users would create a collision box 2D node, go to inspector, assign a shape, assign size, then create a 2D sprite node, then go to inspector and assign an image that had been imported. For a bigger game or one with a team, learning that is a great idea, but for now we will focus on testing if you enjoy making games in Godot!
Instructions:
CTRL+F8 to go to the scene tab
Note: if you already are in the scene tab this is unneeded, but I’ll always include going to the proper tab/menu as part of the instructions so that way if menus get closed, or you explore so change focus in between steps, the instructions will work by starting from the top of a section
CTRL+N to create a new scene
CTRL+A to open the new node selector
Type in "staticbody2d", press enter.
Press enter, rename to "Floor", press enter
Press shift tab twice to get to the “attach a script” button and press Enter, or press CTRL+ = (Equal sign)
Press enter to create script with default name
Under the line that read “extends StaticBody2d” paste the below code:
Code Snippet 1
#Func _ready() is a built in function that gets ran when an instance enters the scene once every other node has finished its “_enter_tree()” actions.
func _ready():
# GM.create_collide_rect is a function that came with the addons and is not part of Godot.
# It creates a CollisionShape2d, makes it a rectangle of x,y then attaches to self.
# The last argument is whether it should have a graphic or not. It is optional and defaults to false.
GM.create_collide_rect(64,64,self,true)
ctrl+s to save, enter to confirm save.
Player
Ctrl+f8, Ctrl+n, CTR+A, to go to Scene tab, create a new scene, then open the menu to pick a root node.
Type in characterbody2d, enter
Press enter again with focus on our character and and type in "Player" to rename it
Ctrl+F8 to go back to scene tab
CTRL+A
Type in Camera2D, press enter. The view will now follow the player, which allows for sharing issues easier with sighted devs, and enables the use of features revolving around having scenes take certain actions when rendered, which is a good way to have things become active only when near by..
Press up to confirm "player" is focused. Whatever is focused will become the parent of our next child.
CTRL+A
Type in AudioListener2D, press enter. This will be our ears, soon we will make 2D audio nodes attached to other items, and how loud they are is going to be based on how close they are to this node, and the settings of the audio source.
With it still focused press CTRL+F6
CTRL+U to go to top of inspector
Press tab until find “Current” then find its on check box.
In the inspector, press enter to toggle it active. Only one AudioListender2D can be marked current at a time.
Adding player audio:
At this point we would attach a large number of audio players. To do so we would:
focus “player” in the Scene tree
press CTRL+A
Type in "audiostreamplayer2d"
press enter to rename it
With it still focused press CTRL+F6
CTRL+U to go to top of inspector
Press down to get to "stream properties" row, then Tab twice to get to the "button" and press enter.
From the drop down list, select "Quick load"
Type in the name of the sound file, press enter.
We would then do this 5 more times for this character, then another dozen times throughout the tutorial. Instead this tutorial will have this be done via code.
Follow along again now:
Press up until “Player” is focused in the tree view.
Press Shift+Tab twice, then press select to create a script, press Enter, you should now have focus on the script editor
Copy this script to below the line it puts there automatically. If it puts many lines there, remove everything but the line "extends characterbody2d". By using a characterbody2d we get access to a number of functions designed to make creating a platformer easier.
Code Snippet 2
#needs to be declared here to be accessed everywhere in script. Will be used a little later!
var spawn_point
var grounded = false
#when we want to ask the room to do something for us, we'll just call parent
var parent = get_parent()
#-1 is going to be left, 1 is right, 0 is not moving
var direction
#How many pixels per second our character should move. Feel free to change this around!
const SPEED = 300.0
#how much we will launch ourself when jumping. Feel free to change it and get a feel for it!
const JUMP_VELOCITY = -400.0
#we are creating 6 audio players that will always play on top of the player, so are not 2d.
# We can replace what audio file each one is playing as the game goes, such as changing the footsteps as they enter new terrain.
# But the main thing to remember is each audio player can only play one audio source at a time.
# So that's why each action needs it own AudioStreamPlayer, since many of these actions can play at the same time.
var step_sfx = AudioStreamPlayer.new()
var bonk_sfx = AudioStreamPlayer.new()
var jump_sfx = AudioStreamPlayer.new()
var death_sfx = AudioStreamPlayer.new()
var land_sfx = AudioStreamPlayer.new()
var pickup_sfx = AudioStreamPlayer.new()
var scared_sfx = AudioStreamPlayer.new()
#Any functionas that starts with a _ is a built in function that the game engine will call at the proper time automatically that we can modify.
# _ready is code that runs as final step before the game starts, or before it starts taking actions if activated later. So everything else is loaded before any ready steps are ran
func _ready():
#Setting our collision mask to 3, it is a bitwise operator. So that means we will be "visible" on layers 1 & 2.
#So if we want things to only interact with the player, we have them only look in layer 2.
collision_layer = 3
#making a smaller hit box for our player, making it red.
GM.create_collide_rect(32,32,self,true,Color.RED)
# When a node is created like above, they are in the "void" where they exist but can't do anything. Here we are adding them to be attached to the player so they will function and we can hear them.
add_child(step_sfx)
add_child(bonk_sfx)
add_child(jump_sfx)
add_child(death_sfx)
add_child(land_sfx)
add_child(pickup_sfx)
add_child(scared_sfx)
#assigning the audio files that they will have at the start of the game. Stream is the audio file that they will play.
#They will not play until the .play() method is called on them, shorlty down we will cover when they are called and how to manipulate them.
step_sfx.stream = preload("res://audio/footsteps.wav")
bonk_sfx.stream = preload("res://audio/bonk.wav")
jump_sfx.stream = preload("res://audio/jump.wav")
death_sfx.stream = preload("res://audio/death.wav")
land_sfx.stream = preload("res://audio/land.wav")
pickup_sfx.stream = preload("res://audio/pickup.mp3")
scared_sfx.stream =preload("res://audio/danger.mp3")
step_sfx.play()
#Menus are navigated by "ui_" actions.
#this is setting up so that W/A/S/D also can be used to navigate menus. By default arrow keys always will work.
# this can also be done by going to project - project settings - input map - selecting + next to each UI option, pressing the key you want added, then pressing enter.
#or just use a bit of code. Additionally, we are using "physical" so we are checking the keys at those locations on a QWERTY keyboard, even if they are remapped
# once again again we are using a GMap function
GM.add_event("ui_left",KEY_A)
GM.add_event("ui_right",KEY_D)
GM.add_event("ui_up",KEY_W)
GM.add_event("ui_down",KEY_S)
#Anything that starts with a _ is a built in function that the game engine will call at the proper time automatically that we can modify.
# _physics_process is called every frame for physics actions. Delta is time since last frame.
func _physics_process(delta: float) -> void:
# Add the gravity. is_on_floor is a built in fucition of character body2d, that checks for collision directly below character.
if not is_on_floor():
velocity += get_gravity() * delta
# if W is pressed, and we are on the ground we apply our jump_sfx to our velocity.
#but since we apply postivie velocity from gravity, we only go up so high.
if Input.is_action_just_pressed("ui_up") and is_on_floor():
jump_sfx.play()
velocity.y = JUMP_VELOCITY
# setting direction we will start to move based on left and right keys
if Input.is_action_pressed("ui_left"):
direction = -1
elif Input.is_action_pressed("ui_right"):
direction = 1
else:
direction =0
if direction != 0:
#setting our side to side velocity based on direction
velocity.x = direction * SPEED
#playing sound if moving and only is touching the floor, not a wall! So doesnt play if stopped by wall
if step_sfx.playing == false and is_on_floor_only():
step_sfx.play()
#if we run into a wall, we don't play step_sfx! We play bonk_sfx!
elif step_sfx.playing == true and is_on_wall() == true:
step_sfx.stop()
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
if step_sfx.playing == true:
step_sfx.stop()
#playing bonk_sfx if not playing, if we are touching a wall, and are trying to move!
if bonk_sfx.playing == false and is_on_wall() == true and velocity.x != 0:
bonk_sfx.play()
#playing sound if hitting head on ceiling!
if is_on_ceiling() and bonk_sfx.playing == false:
bonk_sfx.play()
#calling this makes the movement happen using the variable velocity
move_and_slide()
#get_parent() is a way to reference the room so we can run a function that belongs to the room
#gmap_view_map() is a special function that came with the GMAP viewer addon.
#We will use it to soon to help make sure our game objects go in correctly!
#_unhandled_input is another way to respond to player actions. This function is called whenever input happens that no other node consumes.
func _unhandled_input(_event):
if Input.is_action_just_pressed("ui_cancel"):
print("player")
print(global_position)
get_parent().gmap_view_map(global_position,11,"ui_cancel")
Script Explanation
Ctrl+S to save the script
In the script is included part that gives the player a collision layer of “3”. Collision layer is bitwise, so it is in layers 1 and 2. 2 will be our special layer that we have things that should only interact with the player check.
Usually this can also be set in the inspector by going to the collision header and checking the “2” box. These boxes are not accessible at the moment.