This is the second part of the tutorial creating platformer game on Godot Engine. In this tutorial, I will explain how to make player, from the basic node creation until moving. So let’s get started!

  1. Part 1 : Preparation
  2. Part 2 : Player Creation
  3. Part 3 : Player Creation 2
  4. Part 4 : Tilemap and Camera
  5. Part 5 : Player Animation
  6. Part 6 : Parallax Background and Level Bounds
  7. Part 7 : Character Controller and Enemy

Prepare the Node

Okay, now we will create a Player. First of all, create a new scene by clicking the Scene Menu at the top left toolbar, then select the New Scene. Now, new tab named as [empty] in the Scene View appears.

Create Scene

Create KinematicBody2D

Now go into Scene Window, create a new KinematicBody2D node, by clicking ‘+’ button and search KinematicBody2D, then double click it or click create button. Rename the KinematicBody2D to “Player”.

Create KinematicBody2D

Create Sprite

Make sure Player Node has been selected, then create a Sprite Node by clicking the ‘+’ button, search Sprite and create it.

Create Sprite

Now we need to assign the sprite image, select the Sprite Node, go to the Inspector Window, navigate into the Texture, click the button, select Load. The new window will show up, select the tiles.png.

Manage Sprite

Sprite in Godot support for the tileset, so as you can see our image is a bunch of sprites with each tile size is 16px (for the character the size is 32px). Because our image size is 320px x 352px, so we need to set the VFrames 10 (320 / 32 = 10) and HFrames 11 (352 / 32 = 11). Divided by 32 because the character size is 32px x 32px.

Now save the Node by press Ctrl + S, save as Player.tscn. Now try to change the Frame by clicking the up and down button on the right side.

Sprite Frame

Doesn’t change anything?? Don’t panic, sometimes that happened. Make sure you have saved the Node, then close the Player Scene by clicking ‘x’ button at the tab Player, open again the Player.tscn from the FileSystem Window. Now try to change the Frame Value, now must be fixed.

Create CollisionShape2D

Next, create a new node by right click the Player Node, select Add Child Node, find the CollisionShape2D, and create it.

Create CollisionShape2D

Select the CollisionShape2D and go to the Inspector View, navigate to Shape, click the button, select New RectangleShape2D. Now you can setup the collision size directly from the Scene View.

PRO TIPS : You can edit collision shape into precise value by activating the Snap Option. Click Edit - Use Snap, setup the snap value by clicking Edit - Configure Snap.

Create CollisionShape2D Shape CollisionShape2D Shape

That was only the preparation, now the real challenge just BEGIN!!

Ready to become a Wizard?

Script is like a human brain. Without a script, node can’t make a decision what should they do. In Godot, we use GDScript for the scripting language. C# support will be available in the future. GDScript is easy to learn, so don’t let yourself down now, at least try it a bit. You don’t know until you try, right? I bet when Godot V3 released, you will love scripting with GDScript inside Godot Editor, much improvement, I’ve been tried it!! If you don’t know anything about GDScript, I recommend to learn from here!!!

So, back to the topic! Select Player node, see in the inspector, scroll into deep down, you will found Script, click the button, select New Script. A new window will appear, for me, I just click the create button since I don’t want to change anything here. The 2D view will automatically switch to script view.

Create Script

Now we need to write some code, follow my script from now, read the code for the explanation.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extends KinematicBody2D
# defines GRAVITY
# `export` makes your variable editable in the editor
# `var GRAVITY = 10` defines a variable named GRAVITY and assign it 10
export var GRAVITY = 10
# Called when the node is "ready", that means called when the game started.
# Use this function for initialize
func _ready():
# makes `_fixed_process(delta)` running
set_fixed_process(true)
# Called during the fixed processing step of the main loop.
# Fixed processing means that the frame rate is synced to the physics,
# i.e. the delta variable should be constant.
# only active when set_fixed_process(true) is called
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0,GRAVITY)
# apply the movement by calling move(movement*delta)
move(movement*delta)

Press F6 to test it. Make sure the result is same as mine, the character will fall down. If your character just stays, or different as mine, there must be something wrong.

Result

If you come from Unity, you must be wondering about GRAVITY. The Gravity value is positive, means the character must go up, not down. Yes, I once thought that way, but in Godot 2D, the vector y is opposite, so the down direction is positive and up direction is negative, got it?

Create the Test Scene

Create a new scene and add Node2D. After that, add StaticBody2D as a child of Node2D. Then add CollisionShape2D as a child of StaticBody2D. StaticBody2D is container for non-moveable CollisionShape2D (ex: ground), more about physics. Now Create the new RectangleShape2D of the CollisionShape2D, resize and move it. Save it as World.tscn.

Create World

Now add a new Camera2D node as a child of Node2D. Set the Zoom into (0.25, 0.25) and activate the Current option. Camera2D is a projection for 2D scenes, if we don’t use camera, the projection is always set from the (0,0) until the size of the viewport (found at project settings).

Create Camera2D Camera Inspector

Drag and drop player.tscn from the FileSystem window into Node2D at the Scene Window.

Assign Player into Scene

Don’t forget to set active the Visible Collision Shape from the Debug menu (inside of the play menu center top, right corner is the Debug Menu). When the option is set as ON, the collision will visible while play mode.

Visible Collision Shape

Play it (press F6)

Test Play

Fixing the gravity

When an object falling down because of gravity, the speed will increase incrementally. To do this, add one more variable to store our velocity

var velocity = Vector2()

And change the old code

1
2
var movement = Vector2(0,GRAVITY)
move(movement*delta)

with this one

1
2
3
var movement = Vector2(0, velocity.y + GRAVITY * delta)
velocity = movement
move(velocity)

So the final code will look like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
extends KinematicBody2D
# defines GRAVITY
# `export` makes your variable editable in the editor
# `var GRAVITY = 10` defines a variable named GRAVITY and assign it 10
export var GRAVITY = 10
# store the player velocity
var velocity = Vector2()
# Called when the node is "ready", that means called when the game started.
# Use this function for initialize
func _ready():
# makes `_fixed_process(delta)` running
set_fixed_process(true)
# Called during the fixed processing step of the main loop.
# Fixed processing means that the frame rate is synced to the physics,
# i.e. the delta variable should be constant.
# only active when set_fixed_process(true) is called
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0, velocity.y + GRAVITY * delta)
# set the velocity = movement
velocity = movement
# apply the movement by calling move(velocity)
move(velocity)

KEEP IN MIND! The concept of gravity is per second, so the character will falling down by 10px per second (incrementally), not per frame. This is why we multiply the GRAVITY by delta. Multiply a number by delta will make anything into per second.

You can try to play it, press F6, the gravity will look good now, the fall speed will increase each frame, not constant like before.

Gravity Fix

Set Maximum Falling speed

When the character falling down from high ground, the falling speed always increases by gravity and make the character falling really fast. So we need to make the falling speed not more than max falling speed. Create a new variable MAX_FALLING_SPEED, and follow this code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//another code
export var GRAVITY = 10
# set the maximum falling speed per frame
export var MAX_FALLING_SPEED = 15
//another code
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0, velocity.y + GRAVITY * delta)
# set the velocity = movement
velocity = movement
# set the maximum falling speed
if velocity.y > MAX_FALLING_SPEED:
velocity.y = MAX_FALLING_SPEED
# apply the movement by calling move(velocity)
move(velocity)
//another code

So when the velocity.y reached the MAX_FALLING_SPEED, then set the velocity.y to MAX_FALLING_SPEED.

Make the player moving

Setup the Input Map

We need to setup our Input Map to define what button we use in the game. For now, I need to define 5 buttons, right, left, up, down, jump. To do this, click Scene - Project Settings - Input Map, add new Action, just write the action name, for example, ‘right’, then click Add button. Re-do this until you have right, left, up, down, jump action. Then, scroll down and navigate your action. Select one of your action, for example, ‘right’ action. Then on the right side, you can find ‘+’ button, click it and select Key, now press ‘D’ key and click OK button. So, we have bound our right action with ‘D’ key. Re-do this step until our all action bound with a key.

  • right : D
  • left : A
  • up : W
  • down : S
  • jump : Space
Setup Input Map

Horizontal Movement

Now implement the horizontal movement. First of all, we need to add our Input variable.

1
2
3
4
5
6
7
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0, velocity.y + GRAVITY * delta)
#input
var right_input = Input.is_action_pressed("right")
var left_input = Input.is_action_pressed("left")
# Some other code

Input.is_action_pressed("right"), the parameter get from the Input Map Action name, If you still remember, we’ve been setup 5 input map right?

Next one, we need to apply our movement velocity. First of all, we need to define the move speed, add one variable with export prefix, so we can edit while in the editor.

export var MOVE_SPEED = 5

Then, we create the movement logic.

1
2
3
4
5
6
7
8
9
func _fixed_process(delta):
.....
var left_input = Input.is_action_pressed("left")
#Apply the horizontal movement
if right_input:
movement.x = MOVE_SPEED
elif left_input:
movement.x = -MOVE_SPEED
.....

So, if the right action is pressed, set the x axis of movement into = MOVE_SPEED, if the left action is pressed, then set the x axis of movement into = -MOVE_SPEED. Remember, the right direction is positive, left direction is negative.

The final code looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
extends KinematicBody2D
# defines GRAVITY
# `export` makes your variable editable in the editor
# `var GRAVITY = 10` defines a variable named GRAVITY and assign it 10
export var GRAVITY = 10
# set the maximum falling speed per frame
export var MAX_FALLING_SPEED = 15
# MOVE_SPEED
export var MOVE_SPEED = 5
# store the player velocity
var velocity = Vector2()
# Called when the node is "ready", that means called when the game started.
# Use this function for initialize
func _ready():
# makes `_fixed_process(delta)` running
set_fixed_process(true)
# Called during the fixed processing step of the main loop.
# Fixed processing means that the frame rate is synced to the physics,
# i.e. the delta variable should be constant.
# only active when set_fixed_process(true) is called
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0, velocity.y + GRAVITY * delta)
#input
var right_input = Input.is_action_pressed("right")
var left_input = Input.is_action_pressed("left")
#Apply the horizontal movement
if right_input:
movement.x = MOVE_SPEED
elif left_input:
movement.x = -MOVE_SPEED
# set the velocity = movement
velocity = movement
# set the maximum falling speed
if velocity.y > MAX_FALLING_SPEED:
velocity.y = MAX_FALLING_SPEED
# apply the movement by calling move(velocity)
move(velocity)

Try to play and press the ‘D’ or ‘A’ key.

Horizontal Movement

Fixing the Horizontal Movement

Did you notice it? While on the air, the movement is fast, and while on the ground, the movement is really slow. Before into that, see the explanation about how the character can moving.

Velocity number is just abstract number, not the real number. Used for explain where the character move!!


Explanation about Movement

Got it? now this is the explanation why the character really slow while on the ground

Explanation about slow movement

Understand? So the velocity.y is always pushing down, and the result of func move always stopped at where the collision detected, that’s the problem. So how we fix this? See the picture below.

Explanation about fixing the movement

There are so many ways to fix this, but I recommend this one. We can use slide function to fix this, it can handle all collision direction. Formula behind slide function is

V1.slide(V2) = V2 - V1 * scalar(V1, V2) Scalar is same as dot product, read here for more explanation.

Now, implement the code! follow my lead!!

1
2
3
4
5
6
7
8
9
10
11
12
13
func _fixed_process(delta):
....
# set the maximum falling speed
if velocity.y > MAX_FALLING_SPEED:
velocity.y = MAX_FALLING_SPEED
# apply the movement by calling move(velocity) and store the remaining movement
var remaining_movement = move(velocity)
# collision handling
if is_colliding():
var normal = get_collision_normal()
remaining_movement = normal.slide(remaining_movement)
velocity = normal.slide(velocity)
move(remaining_movement)

The final code looks like this

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
extends KinematicBody2D
# defines GRAVITY
# `export` makes your variable editable in the editor
# `var GRAVITY = 10` defines a variable named GRAVITY and assign it 10
export var GRAVITY = 10
# set the maximum falling speed per frame
export var MAX_FALLING_SPEED = 15
# MOVE_SPEED
export var MOVE_SPEED = 5
# store the player velocity
var velocity = Vector2()
# Called when the node is "ready", that means called when the game started.
# Use this function for initialize
func _ready():
# makes `_fixed_process(delta)` running
set_fixed_process(true)
# Called during the fixed processing step of the main loop.
# Fixed processing means that the frame rate is synced to the physics,
# i.e. the delta variable should be constant.
# only active when set_fixed_process(true) is called
func _fixed_process(delta):
# make a Vector2 variable movement and add gravity into y axis
var movement = Vector2(0, velocity.y + GRAVITY * delta)
#input
var right_input = Input.is_action_pressed("right")
var left_input = Input.is_action_pressed("left")
#Apply the horizontal movement
if right_input:
movement.x = MOVE_SPEED
elif left_input:
movement.x = -MOVE_SPEED
# set the velocity = movement
velocity = movement
# set the maximum falling speed
if velocity.y > MAX_FALLING_SPEED:
velocity.y = MAX_FALLING_SPEED
# apply the movement by calling move(velocity) and store the remaining movement
var remaining_movement = move(velocity)
# collision handling
if is_colliding():
var normal = get_collision_normal()
remaining_movement = normal.slide(remaining_movement)
velocity = normal.slide(velocity)
move(remaining_movement)

Test it and see, the result must be like this

Fixing Movement while Colliding

So for today, that was enough. If you still have extra energy, follow this link. All of you are AWESOME!

Download Project Here