Moving the player with code (2024)

It's time to code! We're going to use the input actions we created in the lastpart to move the character.

Note

For this project, we will be following the Godot naming conventions.

  • GDScript: Classes (nodes) use PascalCase, variables andfunctions use snake_case, and constants use ALL_CAPS (SeeGDScript style guide).

  • C#: Classes, export variables and methods use PascalCase,private fields use _camelCase, local variables and parameters usecamelCase (See C# style guide). Be careful to typethe method names precisely when connecting signals.

Right-click the Player node and select Attach Script to add a new script toit. In the popup, set the Template to Empty before pressing the Createbutton. We set it to Empty because we want to write our own code forplayer movement.

Moving the player with code (1)

Let's start with the class's properties. We're going to define a movement speed,a fall acceleration representing gravity, and a velocity we'll use to move thecharacter.

extends CharacterBody3D# How fast the player moves in meters per second.@export var speed = 14# The downward acceleration when in the air, in meters per second squared.@export var fall_acceleration = 75var target_velocity = Vector3.ZERO

These are common properties for a moving body. The target_velocity is a 3D vectorcombining a speed with a direction. Here, we define it as a property becausewe want to update and reuse its value across frames.

Note

The values are quite different from 2D code because distances are in meters.While in 2D, a thousand units (pixels) may only correspond to half of yourscreen's width, in 3D, it's a kilometer.

Let's code the movement. We start by calculating the input direction vectorusing the global Input object, in _physics_process().

func _physics_process(delta): # We create a local variable to store the input direction. var direction = Vector3.ZERO # We check for each move input and update the direction accordingly. if Input.is_action_pressed("move_right"): direction.x += 1 if Input.is_action_pressed("move_left"): direction.x -= 1 if Input.is_action_pressed("move_back"): # Notice how we are working with the vector's x and z axes. # In 3D, the XZ plane is the ground plane. direction.z += 1 if Input.is_action_pressed("move_forward"): direction.z -= 1

Here, we're going to make all calculations using the _physics_process()virtual function. Like _process(), it allows you to update the node everyframe, but it's designed specifically for physics-related code like moving akinematic or rigid body.

See also

To learn more about the difference between _process() and_physics_process(), see Idle and Physics Processing.

We start by initializing a direction variable to Vector3.ZERO. Then, wecheck if the player is pressing one or more of the move_* inputs and updatethe vector's x and z components accordingly. These correspond to theground plane's axes.

These four conditions give us eight possibilities and eight possible directions.

In case the player presses, say, both W and D simultaneously, the vector willhave a length of about 1.4. But if they press a single key, it will have alength of 1. We want the vector's length to be consistent, and not move faster diagonally. To do so, we cancall its normalized() method.

#func _physics_process(delta): #... if direction != Vector3.ZERO: direction = direction.normalized() # Setting the basis property will affect the rotation of the node. $Pivot.basis = Basis.looking_at(direction)

Here, we only normalize the vector if the direction has a length greater thanzero, which means the player is pressing a direction key.

We compute the direction the $Pivot is looking by creating a Basisthat looks in the direction direction.

Then, we update the velocity. We have to calculate the ground velocity and thefall speed separately. Be sure to go back one tab so the lines are inside the_physics_process() function but outside the condition we just wrote above.

func _physics_process(delta): #... if direction != Vector3.ZERO: #... # Ground Velocity target_velocity.x = direction.x * speed target_velocity.z = direction.z * speed # Vertical Velocity if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity target_velocity.y = target_velocity.y - (fall_acceleration * delta) # Moving the Character velocity = target_velocity move_and_slide()

The CharacterBody3D.is_on_floor() function returns true if the body collided with the floor in this frame. That's whywe apply gravity to the Player only while it is in the air.

For the vertical velocity, we subtract the fall acceleration multiplied by thedelta time every frame.This line of code will cause our character to fall in every frame, as long as it is not on or colliding with the floor.

The physics engine can only detect interactions with walls, the floor, or otherbodies during a given frame if movement and collisions happen. We will use thisproperty later to code the jump.

On the last line, we call CharacterBody3D.move_and_slide() which is a powerfulmethod of the CharacterBody3D class that allows you to move a charactersmoothly. If it hits a wall midway through a motion, the engine will try tosmooth it out for you. It uses the velocity value native to the CharacterBody3D

And that's all the code you need to move the character on the floor.

Here is the complete Player.gd code for reference.

extends CharacterBody3D# How fast the player moves in meters per second.@export var speed = 14# The downward acceleration when in the air, in meters per second squared.@export var fall_acceleration = 75var target_velocity = Vector3.ZEROfunc _physics_process(delta): var direction = Vector3.ZERO if Input.is_action_pressed("move_right"): direction.x += 1 if Input.is_action_pressed("move_left"): direction.x -= 1 if Input.is_action_pressed("move_back"): direction.z += 1 if Input.is_action_pressed("move_forward"): direction.z -= 1 if direction != Vector3.ZERO: direction = direction.normalized() $Pivot.basis = Basis.looking_at(direction) # Ground Velocity target_velocity.x = direction.x * speed target_velocity.z = direction.z * speed # Vertical Velocity if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity target_velocity.y = target_velocity.y - (fall_acceleration * delta) # Moving the Character velocity = target_velocity move_and_slide()

Testing our player's movement

We're going to put our player in the Main scene to test it. To do so, we needto instantiate the player and then add a camera. Unlike in 2D, in 3D, you won'tsee anything if your viewport doesn't have a camera pointing at something.

Save your Player scene and open the Main scene. You can click on the Maintab at the top of the editor to do so.

Moving the player with code (2)

If you closed the scene before, head to the FileSystem dock and double-clickmain.tscn to re-open it.

To instantiate the Player, right-click on the Main node and select InstantiateChild Scene.

Moving the player with code (3)

In the popup, double-click player.tscn. The character should appear in thecenter of the viewport.

Adding a camera

Let's add the camera next. Like we did with our Player's Pivot, we'regoing to create a basic rig. Right-click on the Main node again and selectAdd Child Node. Create a new Marker3D, and name it CameraPivot.Select CameraPivot and add a child node Camera3D to it.Your scene tree should look similar to this.

Moving the player with code (4)

Notice the Preview checkbox that appears in the top-left of the 3D view when youhave the Camera selected. You can click it to preview the in-game camera projection.

Moving the player with code (5)

We're going to use the Pivot to rotate the camera as if it was on a crane.Let's first split the 3D view to be able to freely navigate the scene and seewhat the camera sees.

In the toolbar right above the viewport, click on View, then 2 Viewports.You can also press Ctrl + 2 (Cmd + 2 on macOS).

Moving the player with code (6)

Moving the player with code (7)

On the bottom view, select your Camera3D and turn on cameraPreview by clicking the checkbox.

Moving the player with code (8)

In the top view, make sure your Camera3D is selected and move the camera about19 units on the Z axis (drag the blue arrow).

Moving the player with code (9)

Here's where the magic happens. Select the CameraPivot and rotate it -45degrees around the X axis (using the red circle). You'll see the camera move asif it was attached to a crane.

Moving the player with code (10)

You can run the scene by pressing F6 and press the arrow keys to move thecharacter.

Moving the player with code (11)

We can see some empty space around the character due to the perspectiveprojection. In this game, we're going to use an orthographic projection insteadto better frame the gameplay area and make it easier for the player to readdistances.

Select the Camera again and in the Inspector, set the Projection toOrthogonal and the Size to 19. The character should now look flatter andthe ground should fill the background.

Note

When using an orthogonal camera in Godot 4, directional shadow quality isdependent on the camera's Far value. The higher the Far value, thefurther away the camera will be able to see. However, higher Far valuesalso decrease shadow quality as the shadow rendering has to cover a greaterdistance.

If directional shadows look too blurry after switching to an orthogonalcamera, decrease the camera's Far property to a lower value such as100. Don't decrease this Far property too much, or objects in thedistance will start disappearing.

Moving the player with code (12)

Test your scene and you should be able to move in all 8 directions and not glitch through the floor!

Ultimately, we have both player movement and the view in place. Next, we willwork on the monsters.

Moving the player with code (2024)
Top Articles
Latest Posts
Article information

Author: Duncan Muller

Last Updated:

Views: 5902

Rating: 4.9 / 5 (59 voted)

Reviews: 90% of readers found this page helpful

Author information

Name: Duncan Muller

Birthday: 1997-01-13

Address: Apt. 505 914 Phillip Crossroad, O'Konborough, NV 62411

Phone: +8555305800947

Job: Construction Agent

Hobby: Shopping, Table tennis, Snowboarding, Rafting, Motor sports, Homebrewing, Taxidermy

Introduction: My name is Duncan Muller, I am a enchanting, good, gentle, modern, tasty, nice, elegant person who loves writing and wants to share my knowledge and understanding with you.