GETTING STARTED IN GODOT – ORIGINAL VERSION
By Alex K.

 


PART 1 (TAB 1)

Once you’ve created a new project, press the “Node2D” button on the left side of the editor. This should bring you to this screen.


https://lh7-rt.googleusercontent.com/docsz/AD_4nXd31sWLXxVdFKfTJFMmlZxVvAffrSXYAydsJ-kyIAOIJgv03MoK_WOKPIkUiiJ60uD0jKrDzffD2DOsQAwnv2peuGXgNEyLpkb7a8u9uEWlqaQABs-_kgOI_906tl_-mAxeUc_0bQ?key=A319pMMFgwhCL9UM9V1AOWMl

To start, this basic screen has three things you should be paying attention to:
https://lh7-rt.googleusercontent.com/docsz/AD_4nXeB2HMOC-EgeqVwnf0p444bcKSLKFbQbJptQcWp_eUEUh7uMXvq4GTIp8hkswUyabsCfnLRtpSmegEBalYmXner_TwFKf444OL17e8K7eHVSr3v1GBbldFR94wwC_kcYIcq5BsZ?key=A319pMMFgwhCL9UM9V1AOWMl
This is called the “Scene tree.” →

It’s where you see the nodes in the scene.

Right now you only have a single node. Called the “root node.”

https://lh7-rt.googleusercontent.com/docsz/AD_4nXfbjqB1k-btRYRCZA6A5A-QsOmzbUBuq6enxIVhYr5z9X2KI3n4aQtdNa0zVmy1pTyJ259edAlQET3eFIpPVJZ5uK_15uUaaWA-C7fKjOEvTUNud8w3tNZbrPIMk9oqwgjvp0iOZA?key=A319pMMFgwhCL9UM9V1AOWMl


This is the file loader, it stores any images, code, or assorted things that your project will be loaded with.

Icon.svg is an image, specifically the godot logo. We’ll be using it for the demo.

Select icon.svg, and drag it into the centre of the screen.

 

https://lh7-rt.googleusercontent.com/docsz/AD_4nXejmHNfoUu_klUTb1CDj0gnz29ThT7T2dYlLY_43Th_WMY0o3btnc7beIU5S75KuVFsq0UbcF93xcLqKLgm7Q3lqoY3aqiqkD6XiRCThTBn8XyWPDOskhmxXDfYU3ov0X3wjum47A?key=A319pMMFgwhCL9UM9V1AOWMl

 

Good job! You’ve created a node. Specifically, a Sprite2D.

https://lh7-rt.googleusercontent.com/docsz/AD_4nXfrZBxhkuuF1j0rgG1xugZQGkvn3shnHLwklbYsoFbcB7ECiB73XEQf_PdH741_uRkhbfQPO9uZ4EQO-Aag7_xVPwUqqbZvD164DIDhG36ntSeCb8UZtKxekC5SQHbiH8lNnoLj?key=A319pMMFgwhCL9UM9V1AOWMlNow look to the right of the screen.

This →

Is called the inspector.

Open transform. You’ll get the image below:https://lh7-rt.googleusercontent.com/docsz/AD_4nXcL82LMsfMEcUr8XZkxWuqmQUMc5BsG8dEyUdWqT5oEChzIZQhfrxWFjpcEDZqaX9q0LgEv_z5tnm5TlsmpXN0w1Nk4orEdegLKklm4SonmXb3FJmFwQNEdGD9A5ChRubRpb7Rd?key=A319pMMFgwhCL9UM9V1AOWMl


Play around with the values a bit. Some questions to solve before the next section:

  1. If I wanted the object to be 100 pixels right from the middle of the screen, what would it’s position be.
  2. If I set skew to 45 degrees, How would the object change.
  3. How would I halve the size of the image?
  4. What does the little chain icon beside scale do, can you see reasons to turn it off?

Solved those?

Good. now press the little recycle image beside all the values.

You’re almost ready to press play. But we need a camera first.

Right click on the root node, (the Node2D) and press add child.

This menu opens up:https://lh7-rt.googleusercontent.com/docsz/AD_4nXfNM1a5I8H4V056pls4KV5ZVbVHeV8sXGSiXdc5FGVhyhfuTSmS4IVOwjn3l6f8Vbt0JcuiLkgbmdfVfA0088GxxePxSieoB7zWkFepWsetjpb9uv_dCZJKLvEqZPJJRN3Szx1krQ?key=A319pMMFgwhCL9UM9V1AOWMl

This is a lot of things. Most of them are not important right now. But for a rough explanation:
Anything that is white is a special node. Like audio, multiplayer, or other shenanigans.

Anything opened by selecting the Node2D section, coloured blue. are 2D objects. That’s the type we’re working with right now.

Anything opened by selecting the Node3D section, coloured red, are 3D objects. They’re a bit too complex to explain right now.

Control, the green nodes. Are special, they’re 2D. And designed for HUDS or GUI. the interface and buttons. We’ll go into them later.

Select Node2D –> Camera2D. Double click or press “Create.”

Now you have your Camera, you can select it on the scene tree.

Now to play! The play button is the triangle above the inspector.

 

https://lh7-rt.googleusercontent.com/docsz/AD_4nXfH_3WaiMrroPISz4ckU1C3L9pkxBUqnW-rDax71d7xPHjmLJ-Tk13If1-dF6KNM2F80WlfWi6MsVy-ZzsM24D_1faQABlVjIahFXEIplzDzt4EnDZPem7m8NlkMXdX7n3TqvNJ?key=A319pMMFgwhCL9UM9V1AOWMl

Uh Oh!

This isn’t too bad. It’s just a reminder that you need to set where the game starts. Press “select current” and you’ll be prompted to save the scene. Call it “Main.”

Now your game is running:
https://lh7-rt.googleusercontent.com/docsz/AD_4nXcJNkTh_mcLMDg3ebKt7qHLbln3udQvVVm9hjxEVZPQ0IcQNbBWEgsFI9tDgAFgcdZO6wNiasTXmU9hALESvMHLj5TeuSY6ruHijSMvMUFfcF_ZapXnBQPfIqtb4UmEqUgpUKr-?key=A319pMMFgwhCL9UM9V1AOWMl

Isn’t it glorious?

Now, you can’t do anything but stare at the face, because we don’t have any Scripts.

Scripts are the instructions on how to run.

Close off your game, Right mouse button on the icon, and press “attach script”

https://lh7-rt.googleusercontent.com/docsz/AD_4nXe7SZcQVugmC-Y1nlq0aQp6Kyfi-70FPCtWIOzVtEMTFdjend1N7c0QZQ-01DWTQ9EaxwyX2OnDs6C5_8I-iS_DIGqEt2kdyJAxrNf6VGJ5viiOZWpq6plHZLu-eK1CdKv6b3yuZA?key=A319pMMFgwhCL9UM9V1AOWMl

Select a different path, call it “player” or something. But leave the “res://” and the “.gd

https://lh7-rt.googleusercontent.com/docsz/AD_4nXfMpUL3OQ6Ql5iCAUDcZXWb_TwY8g5PEbySbLHcQCtBO10lfjZyo7sTZX_lZAlVi6peb3nQnDAkEoQpsAraSnWh9EYVig7dfOBnnLwL9XzCRXGIxyqA1gm7l6U01g5BHTI82E-dDQ?key=A319pMMFgwhCL9UM9V1AOWMl

This is your script, you can change between the 2D scene and scripting at the top of the screen.

 

Closer look, there are three things you’ll notice.

 

https://lh7-rt.googleusercontent.com/docsz/AD_4nXcIJTAB1-Xyz0BOiD2785rS6l3vrkCuQqMIu-g_510h38TtLvWmjWw27KF3EuS5errX6ce1NhAqRSpwvb2hicwDckVXVjcKmSy0XMWWcSdGeLbm4MGS3FdVI3zksVsPcnLyhVlJ?key=A319pMMFgwhCL9UM9V1AOWMl“extends Sprite2D” means that this script can give orders to Sprite2D nodes. Like “change your image” or “play an animation”

 

Everything indented after “_ready()” will run a single time. When you start the game.

 

Everything indented after “_process(delta: float)” will run constantly.

 

Let's start coding, remove the pass from after _process. And replace it with:

 

print(“Hello World”)

 

Now run your game, and look at the console. (the little box below the scripts)

Pretty cool right?

Now remove the print function. Add this:

 

if Input.is_action_pressed(“ui_accept”):

            position.y += 10*delta

 

What does this do?

Lets break this down.

“If” is an if statement, it checks conditions.

Input is a class. A collection of different concepts.

is_action_pressed() is a function that returns a condition. Checking if you’re pressing something

ui_accept” is one of Godot’s pre-existing key presses, it checks for the space key.

position.y is a variable. Specifically, it’s the thing you see when you check the position on the inspector.

Delta is another variable. It’s the amount of time that passed since last frame, we use it to ensure that lag doesn’t affect physics.

Now try running your game.

 

Your challenge for this section:

Using “ui_left”, “ui_right”, “ui_up” and “ui_down”, allow the player to move in all directions.

 

PART 2 (TAB 2)

Variables + Project Settingshttps://lh7-rt.googleusercontent.com/docsz/AD_4nXeHLZTaQcp42toEzxAm7EWc2UticouLuFFZ4nXg2k8dEC2UbrK2sIO_tdREZ1MG2zYTM2bYcFLnDj4NkLk4k8lSI9GiwUiwi2rmktgdZO9rnfDxEZ3ITLz2V3PhwdA12qtg2vCKWw?key=A319pMMFgwhCL9UM9V1AOWMl

 

Roughly this is what the editor should look like.

Today, we’re going to talk about some important concepts.

 

First: Variables.

Between the extends and _ready(). Place this code:

var speed = 10

This is called a variable. A saved value in the code.

Now, go through and set the position to be moved by speed*delta instead of 10*delta.https://lh7-rt.googleusercontent.com/docsz/AD_4nXcydpcKZ8dbWRcCkQTmwhkdCxplz0AmXMDqmRhSqlVMB0HVIDsPplQTKqW9NBIO-3nubdwQfjduLiF7_zzgF9Xw7QwuSkCUWwIWZOnsihoMuNUObXODFDa3puQG5v1PTJn8R3Vu?key=A319pMMFgwhCL9UM9V1AOWMl

No change?

Try changing speed. See what happens.


Good job! You can now change how fast the player moves with only a single value.

But it gets easier. Place:

@export

Before the “var”.

Then check out the icon in the inspector again. Cool, right?

 

Next step:

Moving is cool and all, but you can leave the screen very easily. Here’s how we can change it. First, define a variable with this code:

@onready var camera = $”../Camera2D”

This is complicated so let's break it down:

@onready means that the code only runs once everything has loaded.

“var camera” is just a standard variable define, like speed.

$”../Camera2D” is a reference in the scene tree. What it’s saying is “go back up one step on the tree, then find a node called Camera2D”

Got it? Good.

Now, in the process function, write:

Camera.position = position

This is pretty self explanatory, it makes the camera have the same position as the player.

Try running it. You’ve stopped moving, right?

No you haven’t. It’s just that the camera is stuck to the icon. So you’re always going to be at the centre of the screen.

To solve it, we’re going to do something fun with the variable, replace the position change with:

Camera.position = position.snapped(Vector2(1152,648))

This snaps your position to the default size of the game. Using a special variable calleda a “Vector” which is basically just a position. This ensures that the camera only moves when you move the screen. But there’s two problems:

  1. It moves instantly, which can be disorientating 
  2. If you fullscreen the game, the camera moves before you reach the edge of the screen.

The first is solved with this code:

var snappedPos = position.snapped(Vector2(1152,648))
camera.position = camera.position.move_toward(snappedPos, speed*delta*10)

This assigns a new variable, “snappedPos” and sets it to the your position, but snapped to default screen size.

Then it sets the camera position to the result of a function. The function “move_toward” moves the position it’s called on towards a second position, by an amount depending on the second value.

With problem #1 solved, let’s look at problem #2.

This one isn’t solved in code. At the bar on the top of the screen, press “Project” then “Project Settings…”

https://lh7-rt.googleusercontent.com/docsz/AD_4nXdH2tPJAPlJyGbrcXq8d0IEWIF3FXQaaCi6DTCXGzgEEPzz9y6y3MVqIGFFESiaH3Hd5-M8-3SXu9-r0emOC0ql6AWdBNMA6-N563OFPF32_MNOj9wAnyG2HsXITcaTxSqDMW_iHg?key=A319pMMFgwhCL9UM9V1AOWMlThat opens this menu. You’re looking for Display -> Window on the left side of the screen. Which will open this one:

https://lh7-rt.googleusercontent.com/docsz/AD_4nXecfgVivlp7O82fyN_W4TMiC86GTys2vOt_3J-UaZuNe_gDGex122zXvJwX5h15wDzUToCW_4A8-6q_ksc9x_yvjrUzM1Q26_s7_Bmd0UKqppFMUqO9nYmt5tqeMEx77S7l--fx2w?key=A319pMMFgwhCL9UM9V1AOWMl

Go down to stretch. That has three modes:
Disabled is default, it means that expanding the tab increases how much the camera picks up.

Canvas items means that all objects are expanded when you expand the tab. This is good for detailed art, not so much for pixel art.

 

Viewport means that everything keeps the same resolution (amount of pixels) but the tab is stretched to fill the screen. This means that if you’re going for a specific pixel art size, it’s best.

 

Pick canvas items for now, we’re not doing pixel art yet.

 

Now you’ve got basic movement. Your challenge for this section is:

Add another icon and another script, both called “enemy”

 have the enemy be coloured red (Visibility -> modulate in the inspector). And have the enemy script constantly move the enemy towards the player.

 

PART 3 (TAB 3)

 

So, based on the previous challenges, you’ve got a player. An enemy, and a camera. The enemy follows the player.https://lh7-rt.googleusercontent.com/docsz/AD_4nXeeejzBhOJw8JLcthAMWi757MCE6NRA07BanniczpTRKca_EnQP5jPVKN6rvGalj4FL3siNfLKJwF-M3QROupziqttrbR4a2XIamG7ItUE6oUT-qnT7uHBceg2eAo8xjXVGLHp68A?key=A319pMMFgwhCL9UM9V1AOWMl

Lets give it a bit more stuff.

Select your player (the Icon), right click it. And “Add Child Node”

You want to add an Area2D. Make sure that it’s indented and underneath the Icon.


https://lh7-rt.googleusercontent.com/docsz/AD_4nXe-8OhqWHeHxyiAjF-kf86h46PWu741LuVgrKSewytd9gmcVcB75UdRFUCaRaFuJ7hdc33BoxtzVivmeTe6Ab_1Y4S1RbEKRQExR3kn4-SbXhan3rqQlqSZa5n39Ty_b_I93mLgsQ?key=A319pMMFgwhCL9UM9V1AOWMl

It should look like this. See that little error? That’s because we need to add another node. Give the Area2D a child “CollisionShape2D”https://lh7-rt.googleusercontent.com/docsz/AD_4nXeZIK0qeLazSO7kpsN4xSDi3ja7EmoXpO0HpYR-KmNVDmWLYudHpbu699rZSu4IU-ttGTxVFzk7EdE-OkU1rUrVf-kKK05rnDzSD9yNmpwCbUk17yvF44hjJNmVrvyJDNNaOP3V6A?key=A319pMMFgwhCL9UM9V1AOWMl

That just moves the error down. But we don’t need another node, this time we go to the inspector. Selecting the CollisionShape2D.https://lh7-rt.googleusercontent.com/docsz/AD_4nXcLei1tu2GZVAbUAiSDM_kxYlwOfZTX3q3n4ou6VbR6wodZO8PPm8qNrAvdg-jLyNcIAM9wHJWY0sSSVepI4fHViM54cV3E14OOAOMs65BUUDBUiiPnuX0Z6ezDZhk-Mvo6o1XLHg?key=A319pMMFgwhCL9UM9V1AOWMl

Select shape, add a new rectangle shape.

This will be the shape of the player’s hitbox.https://lh7-rt.googleusercontent.com/docsz/AD_4nXdE2oSxK3OC3f_pO03k68JZ1z8SWKWYGJclTzCaZ2oyZXOE56_lbj0qOrNGvT49jKcYanmBHzm-_eJBoqEciovNLEOJPdpHTJEfuz1VpDIxyOkAGGLyhSWB7y-d5DoScw_6f7MwKw?key=A319pMMFgwhCL9UM9V1AOWMl

However, as you can see here. It’s way too small! Select the orange dots, and drag it to fill the player approximately.

Now select the area. Right mouse button, press “copy” then paste a copy of the area on the enemy.

Now the player and enemy can collide. But they don’t actually, because there’s nothing that triggers when they collide.https://lh7-rt.googleusercontent.com/docsz/AD_4nXdufLnMybnqgsmPo-HDIzfQEC4ZR233mQKggaHK1TPx5rvzEv2y0D1ImTotuRAKRq8T0RDJZetG-Tg02Atd05KWtTK1V2jUBtw8giirMaPr9NEJxCIh19YKBI8B1UWZgGCcclDZ1w?key=A319pMMFgwhCL9UM9V1AOWMl

Let’s fix that. Select the player’s Area2D, then Select “Node” on the bar above the inspector.

That’ll open the Signals tab. Remember this, but for the second we aren’t using it. Go to groups.

Add a group, call it “Player Hitbox”

Do the same for the enemy, but call it’s group “Enemy Hitbox”

Now back to signals. With the player’s Area2D selected, press the little area next to “area_entered.” Connect it to the icon.




https://lh7-rt.googleusercontent.com/docsz/AD_4nXdvtsrdzpPtp4KTPegZGz2KvPDRnHrFUHjaBeuRQV9mkKC2YSGl29a8k_D0S3oS_rTsCoL3SERY1Yc8Gtt-ZwpNVz__NM7atc8E8ZxMi7xwfjQOV9mFCdC9kDVtfh7mPk2Tk5lF5Q?key=A319pMMFgwhCL9UM9V1AOWMl

That will open up the player’s script. And add a new function.

Everything after this function runs when an area touches the player. With a variable “area” that represents the area that touched the player.

We want this code:
if area.is_in_group(“Enemy Hitbox”):

            get_tree().quit()

 

This is another if statement, this one checks if the colliding area is the enemy, and if it is then it quits. 

Cool. it works, but now you’re helpless. Lets change that, with the magic of Scenes.

Create a new icon with a hitbox. Have it’s group be “Bullet Hitbox,” scale it down to one fourth of the standard size, call it “bullet” and give it a new script.

Make sure the bullet is at position 0,0. The centre of the game.

In the bullet’s script, add a variable with a value of “Vector2(0,0)” and the name “direction”

Have it move by the direction*delta every frame.

Now for the fun part.

 

Save your bullet as a scene. Then delete the bullet in the main scene.

Now you have two scenes. Select “bullet.tscn” in the file select. This will open the “bullet” as its own scene. You can play around with the bullet here, make it green. Then go back to the main scene and select the player code.https://lh7-rt.googleusercontent.com/docsz/AD_4nXeitCrw6ffOuxgiTrGxuHbfg6MCRJERsSmiCk_h5ukKHho-44RbOUsotyMnPGp2gC_tAT0g81m3cdvbhB0_cmLMAzBOP1mydNH_lbHj64ROEBxw4AcMTteKeuErxLEV2CaqHqDp_w?key=A319pMMFgwhCL9UM9V1AOWMl

Add a new variable to the player:

var bullet = preload("res://bullet.tscn")

This will store the bullet scene as a variable.

Then create:

var hasshot = false

Now, in the processing:






if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):

            if !hasshot:

                        hasshot = true

                        var bulletinst = bullet.instantiate()

                        bulletinst.position = position

                        bulletinst.direction = position.direction_to(get_global_mouse_position())*10

                        $"..".add_child(bulletinst)

else:

            hasshot = false

 

Complex code again, so it’s time for another breakdown!

Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT) detects if you’re holding down the left mouse button.

!hasshot detects if hasshot is false.

The code then sets hasshot to true (so that it doesn’t shoot an endless stream of bullets if you hold down)

var bulletinst = bullet.instantiate() makes a copy of the bullet scene. And saves it to bulletinst .

We then set the bulletinst to be the player’s position. And set it’s direction to be based on where the mouse is, relative to the player’s position.

Then we add the bulletinst to the world, as a child of the root node.

If you aren’t pressing, then it sets hasshot to false so that you can shoot again next time you start pressing.

Now you can shoot bullets, but they don’t do anything.

Set it so the enemy can detect areas entering, and then add this script to it’s “area enters” function:

if area.is_in_group("Bullet Hitbox"):

            queue_free()

queue_free() means “destroy this object.”

Now do the same for the bullet, but make it be destroyed if it hits “Enemy Hitbox”

Now for one more thing:

Save the enemy as a scene (making sure it’s at position 0,0 first). Then drag the “enemy.tscn” from the filemanager to the main scene.

Now you can spawn arbitrary enemies! Good job.

 

Challenge for this section:

Give the enemy an exported variable “health” with value of 5,

Set it to lose one health when the bullet hits it, then queue_free() when health hits zero.

 

PART 4 (TAB 4)

 

Now we’re setting up animation.

First, save this image -> https://lh7-rt.googleusercontent.com/docsz/AD_4nXcikIhjqDpqhmhfLkKEUahiLS5ZIQgGXfkJGOscR3FkFMStF8dcgOuE_7sXje8eNwin9TCixKlQn9L6cQtetG0SbKkBpb2woAB9gmYl9IU17gJENZQz20FYvT4ifQWbs-3bg6-3xA?key=A319pMMFgwhCL9UM9V1AOWMl as “player” on your computer, in the folder you get to when you press “show in file manager” on icon.svg.

 

Now, right mouse click the player, and press “Change type.”

Then set them to be an AnimatedSprite2D.

You’re going to need to change the “extends” at the top of the player’s script to be AnimatedSprite2D instead of Sprite2D.

In the inspector go animation -> sprite frames and create new sprite frames.

Now if you select the sprite frames, it opens a little menu at the bottom:https://lh7-rt.googleusercontent.com/docsz/AD_4nXcMkHCCxbUAYBhr-_5-1NH4WsGOFfMlQYrYERS88BFH_rmBmdeb537SUgfQX7jm5w5IVY4_b-Zd6l3BvVWYnHzGkrrd-BSZFvRAzZZFjmldskZ9BTDG0SIQg1zJrWiYkp4JBU_a0g?key=A319pMMFgwhCL9UM9V1AOWMl

Press the waffle. Then select the player image you saved. It’ll open up this:

https://lh7-rt.googleusercontent.com/docsz/AD_4nXe3cTdY9S4WJKsm6KCfgG0gjzh_HKWOiDkkB2pclt3nvvbYfHZX0skqELzifGZr1imvjUZmKNrh_BiunwHnIfJiH4p0IleuC0ugn-CXO8AVi-8gbR7-tV3YGaZfvpPd7eoNSSVKag?key=A319pMMFgwhCL9UM9V1AOWMl

Set “Vertical” to 1. Then select each of the steps and press “Add 4 Frame(s)”

https://lh7-rt.googleusercontent.com/docsz/AD_4nXeeQs6nfOioMyKK5QZqk4yxapjWOW_m-XaX5Cw5AclX8xN--aCXjtLnUx0sIUXTQCicC3-5X0lrqsT8ZfnXtSN4at2gxxatWQz7_04se08VEUJUgNgOoOTIUtixfbb_oXdhkc4Khw?key=A319pMMFgwhCL9UM9V1AOWMlNow press the arrow above the “filter animations”

And it will start playing.

But now a problem:

Pixel art animation is much smaller than our scene is made for. So let’s go back to project settings.

Set both the “Viewport Width” and “Viewport Height” to 128.

Search for “default texture filter” and set it to Nearest (this makes it less blurry)

Then change the stretch, because we’re doing pixel art now.

You’ll want to go into player scripts and set the snapping to be your new width and height.

(Also make the size of your hitbox match your new size.)

Now the enemies are massive!

Repeat this process on the enemy scene. They should still be red.

Also scale down your bullet, you can keep it with Icon.svg

Now you’re small, and animated. But you dance when you’re standing still and always point right.

First, the dancing. Add a new animation called “still” to your player’s sprite frames. Make it be only the unmoving frame.

Add this code to your player:

if Input.get_vector("ui_left","ui_right","ui_down","ui_up") == Vector2():

            play("still")

else:

            play("default")

Input.get_vector returns a Vector2() based on what direction the four inputs are being inputted.

So with this, you are still unless you’re inputting.

Now for the turning:

if get_global_mouse_position().x > position.x:

            flip_h = false

else:

            flip_h = true

 

Great! Now you face the mouse.

Your challenge for this section:
Using Input.get_vector, compress the player’s movement to a single line of code.

 

PART 5 (TAB 5)

 

Part 5:

Now we’ve got streamlined code, a swarm of enemies, a weapon, and a camera. But it’s still all drab and gray.

Now, we can change the grayness just by going into project settings and changing the “default clear colour” but it’d still be a drab world.

We could make a thousand blocks, all static bodies that block the player’s movement. Or we could make one node: A tilemaplayer.https://lh7-rt.googleusercontent.com/docsz/AD_4nXddE5dtDPC3Sz91hIyJwMTvBDuAug9rVV-C3Q3Jcbr0GDG7-B7oRNumnhDXAXqiu397lyM2gTNA6hwLnc9bl47ndtAug1uNoVwGN70eLs8kpAJzk8h0w4bRTH37-Mi4PdKHCFtNfQ?key=A319pMMFgwhCL9UM9V1AOWMl

First, create a tileMapLayer node, it’s just like any other node.

Give it a new tileset (A Collection of different blocks)

Now you’ll want to set the tilesize to (8,8) instead of (16,16).

https://lh7-rt.googleusercontent.com/docsz/AD_4nXdjB5RjYb26DEaZMxte0B8PPX3MD_DCTo1yns4oZ_NuHBxigI-kHzcEXU5f61y4nSlSrNqXwArkAUiJ9YoicpsyhzCcIBE02wL6f17ZbFNZKEEY9NFbZ9aK0Ckdigv8t1lHAHlU?key=A319pMMFgwhCL9UM9V1AOWMl<- Download this image, save it as “tileset.”

Now with the TileMapLayer selected, go down to where it says “TileSet” at the bottom of the screen, and drag the tileset image into the box at the left of the screen.

It’ll ask you if you want to auto-create tiles, say yes.

Now you have the tiles, go back to “TileMap” and you can paint them onto the screen

https://lh7-rt.googleusercontent.com/docsz/AD_4nXfFW3BcA66tJs-iskd_o9aYM9mDa7_PNiB7EoGdoix3-wSCg_CKjTS8U7FrfuQvJFK5LCbcrcV-GbaSvHqcrf3rCnsLPVGgCXgXKkMLjsAGP8ZqI4shOE8ojtwwxQkGbkRjOMyotg?key=A319pMMFgwhCL9UM9V1AOWMlBut uh oh! They block the player.

In the navigator, search and change “Z Index” to -10, this is how far back the tilemap is,

But those tiles don’t do anything right now. So with the image I used, the red should be a blocker. So lets set that up,

First, in the inspector, add a physics layer to the tileset. We don’t need to change anything right now about that. So go down to the bottom of the screen and select TileSet. Navigate to where it says paint.

 

Scroll down in the properties box until you get to physics layer 0, and paint it onto the red tile.

If you accidentally get it on the green tile. C and F swap between adding and erasing.

 

Now to add collision on the player’s end, give them four children:

A Raycast2D pointing to x:-3 y:0 called Left

A Raycast2D pointing to x:2 y:0 called Right

A Raycast2D pointing to x:0 y:4 called Down

A Raycast2D pointing to x:0 y:-5 called Up

For each raycast, set the player’s script to check for their collision, and if so, move by 16*delta in the opposite direction.

 

Your challenge:

Make the blocks also block enemies and bullets.

 

GUIDE 2 PART 1 (TAB 1)

 

Part 2:

Okay! Now that you’ve got the basics down, let's make a platformer.

You’ll want to create a new game, get it to 128 by 128, with the right stretch mode for pixel art.

This time, you’ll want to add a CharacterBody2D, it’s the same type of node as the area, so you’ll need to give it a shape2D.https://lh7-rt.googleusercontent.com/docsz/AD_4nXfcPNzAsfC1ag9W5aRsUO-lhWKlYndU7JA_aF2T7UpbK2GitTFR7GDkydNuIKAPfjYc5f84iwW1PLY3SAT-onKhnPTautYcwCUrcjldwwZE3XLCYOzlB5VZH_wKqtmspmlhmuJ6sQ?key=A319pMMFgwhCL9UM9V1AOWMl

 

Give it an animatedSprite2D, using this image ->https://lh7-rt.googleusercontent.com/docsz/AD_4nXdOgCUqEF1P9msFqiP_AZFYNBCevEo_8uWYQpA1pMiXkXCiIQ1N0s5fFxxxrFH6vXp99nu5L3DVsK8IfVMV-J07aBxCrWrPZwfpqTZm4UO7usjZQBuhOXEWyOXz4CpCo5ITStEoew?key=A319pMMFgwhCL9UM9V1AOWMl

Only use the first frame so far.

 

Then, give it a script. THIS IS IMPORTANT: make sure the template text says “Node: Default,” not “CharacterBody2D: Basic Player”

 

Ok cool, now 

You’ll have the image below:

 |

V



https://lh7-rt.googleusercontent.com/docsz/AD_4nXeceGpoFgR_F-rPv0kdqZ9uRq5Vr6X2KFV0V7l7CaQvDNngTcYF6IfSHFAgPuo7JMqbzgb384oJFSOinCLFBA4dFSi6MtGcPMuLW4SFWJVow7K-mD_ybbKXB4DCt5r3xr-fuesuNA?key=A319pMMFgwhCL9UM9V1AOWMl



You’ll want to add “@export var speed: float” “@export var gravity: float” and “@export var jumpHeight: float” to the top. These are basic variables.

Now, after the _process(delta), write:

            velocity.x = Input.get_axis("ui_left","ui_right")*speed

            if is_on_floor():

                        velocity.y = 0

            else:

                        velocity.y += grav*delta*60

            move_and_slide()

 

Breakdown time!

Velocity is a special variable used by character bodies. It represents how much you’re moving.

You should recognize Input.get_axis() from the earlier section. We don’t need delta here because it’s setting, not adding.

Is_on_floor is a function unique to character bodies, can you guess what it does?

move_and_slide() does the actual moving, based on the velocity you set.

Make sure the variables aren’t zero, then try running this, what happens?

Yep. That’s what happens when you don’t have a floor.

So, let’s add a tileMap, use this -> https://lh7-rt.googleusercontent.com/docsz/AD_4nXe_so6v4e0nzesN6zkw2sYYDJdz6X58dOwoMeKULg9MITamG90222I3aUzOiPk_c_6JYGLOtAuXO7PV_JMChS7ptvNCK-P5l6U72u4mRL7O9oifjlAlUz31eOBbrOpI1D2A1-XnyQ?key=A319pMMFgwhCL9UM9V1AOWMl image. Make all the tiles into blockers.

Now, unlike the previous section, you don’t need to code collision, because everything’s in the move_and_slide().

So you can move, and fall, but you can’t jump.

Add this, just before the move_and_slide:

            if Input.is_action_just_pressed("ui_accept"):

                        if is_on_floor():

                                    velocity.y -= jumpHeight

I think you should be able to figure out what this does by now.

Play around with the values until it feels good to play, this is what I’m using:

https://lh7-rt.googleusercontent.com/docsz/AD_4nXcfJqZo8V_b2MHI7BO2cSK9FjcTgLQc7wsRiOIr7kTUeJ8EUprA6upgRcQpapOnb_6lf1o4e40kgS_4C3kfpBkFhR14djk-YOCV0PyYmVMjzkTVulsE5yuWuBxUa8w36wXysIaM1w?key=A319pMMFgwhCL9UM9V1AOWMl

 

Anyway, your challenges for this section

- add animations, a “still” animation for when your velocity.x equals zero, a “run” animation for when it doesn’t, and a “jump” animation for when you are not on the ground.

- add a camera, have it always at the same x position as the player, but not move in y.

 

GUIDE 2 PART 2 (TAB 2)


So, now that your platformer works, now to add enemies.

Do everything you did to make the player, add it to the enemy group, then give it a raycast2D. Make sure the raycast is aiming down a little below the enemies feet, use this -> https://lh7-rt.googleusercontent.com/docsz/AD_4nXdtxXl5uENEz4Yq0fKafyZWIE6JeGGBCqt6O1V2xj6C08u31SGWIIS_2dtjcIamnUZke8MzeklofA9vn9mdasHUbABmF2owBzrF-nseA6gxfnp-YqrY3EPd5IRnXRU093tlsYnC?key=A319pMMFgwhCL9UM9V1AOWMl image.

Now in the script for the enemy, you’ll want a variable “direction” and make it have a value of 1.

This is the start of the enemies process script:

            if is_on_wall() or !$RayCast2D.is_colliding():

                        direction *= -1

            velocity.x = direction*10

            $AnimatedSprite2D.scale.x = direction

 

Nothing here should be new to you. And it shouldn’t be hard to figure out what the last line needs to be. (move_and_slide())

So this way, the enemy will walk back and forth, bouncing when it hits a wall or would walk over the edge. But it can’t attack or anything.

So we can’t just use the area system, because the player’s not an area. So here’s what we do

Go to the enemy’s inspector, and go down to Collision, look at the layer and mask, they both have the 1 highlighted, but nothing else. Switch that around so it’s 2 that’s highlighted, and not 1.

Now you need to go to the tilemap, and set its physics layer to have both 1 and 2 highlighted.

Now the player doesn’t collide with the enemy, but the enemy collides with the walls. Now you’ll want to go into the player’s code and put:

 

            for i in get_tree().get_nodes_in_group("enemy"):

                        if i.global_position.distance_to(global_position) < 8:

                                    get_tree().quit()

 

This checks for every enemy, and ends the game if they are touching the player.

 

Your challenges for this section:

Save the enemy as a scene for easy movement and placing.

Set it up so that if the player is falling and touches the enemy, the enemy dies and the player bounces.

Set it up so the player dies if they pass below where the camera sees.