From f9ee16593f6bc03f7d2ce2f0d761f27cc3cca2f6 Mon Sep 17 00:00:00 2001 From: Chris Bradfield Date: Sun, 8 Oct 2023 15:52:37 -0700 Subject: [PATCH] updates --- docs/4.x/2d/2d_shooting/index.html | 38 +++++----- docs/4.x/2d/8_direction/index.html | 36 +++++----- docs/4.x/2d/car_steering/index.html | 30 ++++---- docs/4.x/2d/coyote_time/index.html | 26 +++---- docs/4.x/2d/enter_exit_screen/index.html | 22 +++--- docs/4.x/2d/grid_movement/index.html | 34 ++++----- docs/4.x/2d/grid_pathfinding/index.html | 44 ++++++------ docs/4.x/2d/index.html | 22 +++--- docs/4.x/2d/moving_platforms/index.html | 22 +++--- docs/4.x/2d/multi_target_camera/index.html | 30 ++++---- docs/4.x/2d/platform_character/index.html | 26 +++---- docs/4.x/2d/screen_wrap/index.html | 22 +++--- docs/4.x/2d/topdown_movement/index.html | 22 +++--- docs/4.x/2d/using_ysort/index.html | 36 +++++----- docs/4.x/3d/3d_align_surface/index.html | 28 ++++---- docs/4.x/3d/3d_sphere_car/index.html | 40 +++++------ .../3d/assets/character_animation/index.html | 42 +++++------ .../3d/assets/character_controller/index.html | 34 ++++----- .../4.x/3d/assets/importing_assets/index.html | 34 ++++----- docs/4.x/3d/assets/index.html | 22 +++--- docs/4.x/3d/basic_fps/index.html | 26 +++---- docs/4.x/3d/camera_gimbal/index.html | 26 +++---- .../3d/characterbody3d_examples/index.html | 30 ++++---- docs/4.x/3d/click_to_move/index.html | 36 +++++----- docs/4.x/3d/healthbars/index.html | 46 ++++++------ docs/4.x/3d/index.html | 22 +++--- docs/4.x/3d/interpolated_camera/index.html | 22 +++--- docs/4.x/3d/rolling_cube/index.html | 34 ++++----- docs/4.x/3d/rotate_interpolate/index.html | 30 ++++---- docs/4.x/3d/shooting_raycasts/index.html | 22 +++--- docs/4.x/3d/spaceship/index.html | 38 +++++----- docs/4.x/404.html | 4 +- docs/4.x/ai/chasing/index.html | 26 +++---- docs/4.x/ai/homing_missile/index.html | 30 ++++---- docs/4.x/ai/index.html | 22 +++--- docs/4.x/ai/pet_following/index.html | 26 +++---- docs/4.x/animation/index.html | 22 +++--- .../spritesheet_animation/index.html | 38 +++++----- .../animation/using_animation_sm/index.html | 40 +++++------ docs/4.x/audio/audio_manager/index.html | 30 ++++---- docs/4.x/audio/index.html | 22 +++--- docs/4.x/basics/file_io/index.html | 22 +++--- docs/4.x/basics/getting_nodes/index.html | 30 ++++---- docs/4.x/basics/index.html | 22 +++--- docs/4.x/basics/migrating/index.html | 22 +++--- docs/4.x/basics/node_communication/index.html | 38 +++++----- docs/4.x/basics/tree_ready_order/index.html | 26 +++---- .../4.x/basics/understanding_delta/index.html | 34 ++++----- docs/4.x/categories/index.html | 22 +++--- docs/4.x/g101/3d/101_3d_01/index.html | 54 +++++++------- docs/4.x/g101/3d/101_3d_02/index.html | 36 +++++----- docs/4.x/g101/3d/101_3d_03/index.html | 42 +++++------ docs/4.x/g101/3d/index.html | 22 +++--- docs/4.x/g101/gdscript/gdscript_01/index.html | 36 +++++----- docs/4.x/g101/gdscript/index.html | 22 +++--- docs/4.x/g101/index.html | 26 +++---- docs/4.x/g101/start/101_01/index.html | 26 +++---- docs/4.x/g101/start/101_02/index.html | 38 +++++----- docs/4.x/g101/start/101_03/index.html | 38 +++++----- docs/4.x/g101/start/index.html | 26 +++---- .../4.x/games/first_2d/first_2d_01/index.html | 30 ++++---- .../4.x/games/first_2d/first_2d_02/index.html | 42 +++++------ .../4.x/games/first_2d/first_2d_03/index.html | 34 ++++----- .../4.x/games/first_2d/first_2d_04/index.html | 26 +++---- .../4.x/games/first_2d/first_2d_05/index.html | 26 +++---- .../4.x/games/first_2d/first_2d_06/index.html | 28 ++++---- .../4.x/games/first_2d/first_2d_07/index.html | 26 +++---- .../4.x/games/first_2d/first_2d_08/index.html | 22 +++--- .../4.x/games/first_2d/first_2d_09/index.html | 42 +++++------ .../4.x/games/first_2d/first_2d_10/index.html | 22 +++--- .../games/first_2d/first_2d_end/index.html | 22 +++--- docs/4.x/games/first_2d/index.html | 26 +++---- docs/4.x/games/index.html | 22 +++--- docs/4.x/index.html | 26 +++---- docs/4.x/index.json | 2 +- docs/4.x/input/custom_actions/index.html | 22 +++--- docs/4.x/input/index.html | 22 +++--- docs/4.x/input/input_actions/index.html | 22 +++--- docs/4.x/input/mouse_capture/index.html | 22 +++--- docs/4.x/input/mouse_input/index.html | 22 +++--- docs/4.x/input/multi_unit_select/index.html | 36 +++++----- docs/4.x/input/processing_inputs/index.html | 19 +++++ docs/4.x/kyn/index.html | 22 +++--- docs/4.x/kyn/raycast2d/index.html | 36 +++++----- docs/4.x/math/dot_cross_product/index.html | 36 +++++----- docs/4.x/math/index.html | 22 +++--- docs/4.x/math/interpolation/index.html | 22 +++--- docs/4.x/math/transforms/index.html | 46 ++++++------ docs/4.x/physics/asteroids_physics/index.html | 30 ++++---- .../4.x/physics/character_vs_rigid/index.html | 38 +++++----- docs/4.x/physics/index.html | 22 +++--- .../physics/rigidbody_drag_drop/index.html | 22 +++--- .../physics/smooth_rigid_rotate/index.html | 22 +++--- docs/4.x/recent/index.html | 22 +++--- docs/4.x/tags/index.html | 22 +++--- docs/4.x/ui/heart_containers_3/index.html | 32 ++++----- docs/4.x/ui/index.html | 22 +++--- docs/4.x/ui/level_select/index.html | 40 +++++------ docs/4.x/ui/minimap/index.html | 58 +++++++-------- src-4/content/3D/assets/level_design.md | 70 ++++++++++++++++--- src-4/content/_index.md | 2 +- src-4/content/input/multi_unit_select.md | 6 +- src-4/content/input/processing_inputs.md | 7 ++ 103 files changed, 1511 insertions(+), 1433 deletions(-) create mode 100644 docs/4.x/input/processing_inputs/index.html create mode 100644 src-4/content/input/processing_inputs.md diff --git a/docs/4.x/2d/2d_shooting/index.html b/docs/4.x/2d/2d_shooting/index.html index 0356ef34..c2fb18e2 100644 --- a/docs/4.x/2d/2d_shooting/index.html +++ b/docs/4.x/2d/2d_shooting/index.html @@ -1,11 +1,11 @@ -Shooting projectiles :: Godot 4 Recipes - +Shooting projectiles :: Godot 4 Recipes +

Shooting projectiles

Problem

You want to shoot projectiles from your player/mob/etc..

Solution

Setting up the bullet

First, we’ll set up a “bullet” object that we can instance. Here are the nodes we’ll use:

 Area2D: Bullet
      Sprite2D
      CollisionShape2D
-

For the Sprite2D’s texture, you can use any image you like. Here’s an example one:

alt -alt

Set up the nodes and configure the sprite and collision shape. If your texture is oriented pointing up, like the one above, make sure to rotate the Sprite node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.

Add a script and connect the Area2D’s body_entered signal.

extends Area2D
+

For the Sprite2D’s texture, you can use any image you like. Here’s an example one:

alt +alt

Set up the nodes and configure the sprite and collision shape. If your texture is oriented pointing up, like the one above, make sure to rotate the Sprite node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.

Add a script and connect the Area2D’s body_entered signal.

extends Area2D
 
 var speed = 750
 
@@ -16,34 +16,34 @@
     if body.is_in_group("mobs"):
         body.queue_free()
     queue_free()
-

For this example, we’ll remove the bullet if it hits anything at all. We’ll also delete anything tagged in the “mobs” group that it hits.

Shooting

We need to set up a spawn location for the bullets. Add a Marker2D and place it where you want the bullets to spawn. Here’s an example, placed at the barrel of the gun. I’ve named it “Muzzle”.

alt -alt

Notice that as the player rotates, the Muzzle’s transform remains oriented the same way relative to the gun. This will be very convenient when spawning the bullets, as they can use the transform to get the proper position and direction. We just set the new bullet’s transform equal to the muzzle’s.

Tip

This will work for any character type, not just the “rotate-and-move” style shown here. Just attach the Marker2D where you want the bullets to spawn.

In the character’s script we add a variable to hold the bullet scene for instancing:

@export var Bullet : PackedScene
+

For this example, we’ll remove the bullet if it hits anything at all. We’ll also delete anything tagged in the “mobs” group that it hits.

Shooting

We need to set up a spawn location for the bullets. Add a Marker2D and place it where you want the bullets to spawn. Here’s an example, placed at the barrel of the gun. I’ve named it “Muzzle”.

alt +alt

Notice that as the player rotates, the Muzzle’s transform remains oriented the same way relative to the gun. This will be very convenient when spawning the bullets, as they can use the transform to get the proper position and direction. We just set the new bullet’s transform equal to the muzzle’s.

Tip

This will work for any character type, not just the “rotate-and-move” style shown here. Just attach the Marker2D where you want the bullets to spawn.

In the character’s script we add a variable to hold the bullet scene for instancing:

@export var Bullet : PackedScene
 

And check for our defined input action:

    if Input.is_action_just_pressed("shoot"):
         shoot()
 

Now in our shoot() function we can instance a bullet and add it to the tree. A common mistake is to add the bullet as a child of the player:

func shoot():
     var b = Bullet.instantiate()
     add_child(b)
     b.transform = $Muzzle.transform
-

The problem here is that since the bullets are children of the player, they are affected when the player moves or rotates.

alt -alt

To fix this, we should make sure the bullets are added to the world instead. In this case, we’ll use owner, which refers to the root node of the scene the player is in. Note that we also need to use the muzzle’s global transform, or else the bullet would not be where we expected.

func shoot():
+

The problem here is that since the bullets are children of the player, they are affected when the player moves or rotates.

alt +alt

To fix this, we should make sure the bullets are added to the world instead. In this case, we’ll use owner, which refers to the root node of the scene the player is in. Note that we also need to use the muzzle’s global transform, or else the bullet would not be where we expected.

func shoot():
     var b = Bullet.instantiate()
     owner.add_child(b)
     b.transform = $Muzzle.global_transform
-

alt -alt

Download This Project

Download the project code here: https://github.com/godotrecipes/2d_shooting

+ + \ No newline at end of file diff --git a/docs/4.x/2d/8_direction/index.html b/docs/4.x/2d/8_direction/index.html index 4ec0c87b..a2792a66 100644 --- a/docs/4.x/2d/8_direction/index.html +++ b/docs/4.x/2d/8_direction/index.html @@ -1,11 +1,11 @@ -8-Directional Movement/Animation :: Godot 4 Recipes - +8-Directional Movement/Animation :: Godot 4 Recipes +

8-Directional Movement/Animation

Problem

You need a 2D character that has 8-directional movement, including animation.

Solution

For our example, we’ll use the Isometric Mini-Crusader, which contains 8-directional animations for idle, run, attack, and several other states.

alt -alt

The animations are organized in folders, with a separate image for each frame. We’ll use an AnimatedSprite2D and we’ll name each animation based on its direction. For example, idle0 pointing to the right and going clockwise to idle7.

When our character moves, it will pick an animation based on the direction of movement:

alt -alt

We’ll use the mouse to move - the character will always face the mouse and run in that direction when we click the mouse button.

To choose which animation to play, we need to get the mouse direction and map it to this same range of 0-7. get_local_mouse_position() gives us the position of the mouse relative to the character. We can then use snappedf() to snap the angle of the mouse vector to the closest multiple of 45° (PI/4 radians) giving the following result:

alt -alt

Divide each value by 45° (PI/4 radians), and we have:

alt -alt

Finally, we need to map the resulting range to 0-7 using the wrapi() function, and we’ll have our correct values. Adding that value to the end of the animation name (“idle”, “run”, etc) gives us the correct animation:

func _physics_process(delta):
+

8-Directional Movement/Animation

Problem

You need a 2D character that has 8-directional movement, including animation.

Solution

For our example, we’ll use the Isometric Mini-Crusader, which contains 8-directional animations for idle, run, attack, and several other states.

alt +alt

The animations are organized in folders, with a separate image for each frame. We’ll use an AnimatedSprite2D and we’ll name each animation based on its direction. For example, idle0 pointing to the right and going clockwise to idle7.

When our character moves, it will pick an animation based on the direction of movement:

alt +alt

We’ll use the mouse to move - the character will always face the mouse and run in that direction when we click the mouse button.

To choose which animation to play, we need to get the mouse direction and map it to this same range of 0-7. get_local_mouse_position() gives us the position of the mouse relative to the character. We can then use snappedf() to snap the angle of the mouse vector to the closest multiple of 45° (PI/4 radians) giving the following result:

alt +alt

Divide each value by 45° (PI/4 radians), and we have:

alt +alt

Finally, we need to map the resulting range to 0-7 using the wrapi() function, and we’ll have our correct values. Adding that value to the end of the animation name (“idle”, “run”, etc) gives us the correct animation:

func _physics_process(delta):
     current_animation = "idle"
 
     var mouse = get_local_mouse_position()
@@ -17,8 +17,8 @@
         velocity = mouse.normalized() * speed
         move_and_slide()
     $AnimatedSprite2D.animation = current_animation + str(a)
-

Testing the movement, we see this:

alt -alt

Keyboard input

If you’re using keyboard controls instead of mouse, you can get the angle of movement based on which keys are being held. The rest of the process works in the same way.

func _process(delta):
+

Testing the movement, we see this:

alt +alt

Keyboard input

If you’re using keyboard controls instead of mouse, you can get the angle of movement based on which keys are being held. The rest of the process works in the same way.

func _process(delta):
     current_animation = "idle"
     var input_dir = Input.get_vector("left", "right", "up", "down")
     if input_dir.length() != 0:
@@ -31,17 +31,17 @@
 

Download This Project

Download the project code here: https://github.com/godotrecipes/8_direction_animation

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/car_steering/index.html b/docs/4.x/2d/car_steering/index.html index 76dc40c1..87b63055 100644 --- a/docs/4.x/2d/car_steering/index.html +++ b/docs/4.x/2d/car_steering/index.html @@ -1,5 +1,5 @@ -Car steering :: Godot 4 Recipes - +Car steering :: Godot 4 Recipes +

Car steering

Problem

You need to create a 2D top-down car controller.

Solution

When approaching this problem, beginners often wind up creating something that handles nothing like a real car. Some common mistakes you’ll find in amateur car games:

  • A car doesn’t rotate around its center. Put another way, a car’s rear wheels don’t slide side-to-side. (Unless it’s drifting, but we’ll talk about that later.)
  • A car can only turn when it’s moving - it can’t spin in place.
  • A car isn’t a train; it’s not on rails. Turning at high speeds should involve some sliding (drifting).

There are many approaches to 2D car physics, mainly depending on how “realistic” you want to be. For this solution, we’re going for an “arcade” level of realism, meaning we’ll prioritize action over realism.

Note

The method below is based on the algorithm found here: http://engineeringdotnet.blogspot.com/2010/04/simple-2d-car-physics-in-games.html

The recipe below is broken into 5 parts, each adding a different feature to the car’s movement. Feel free to mix-and-match for your needs.

Scene setup

Here’s the car scene setup:

 CharacterBody2D
      Sprite2D
@@ -49,8 +49,8 @@
     move_and_slide()
 

Now when you run, the car should gradually increase its speed. Careful: we don’t have any way to slow down yet!

Part 3: Friction/drag

A car experiences two different deceleration forces: friction and drag.

  • Friction is the force applied by the ground. It’s very high if driving on sand, but very low if driving on ice. Friction is proportional to velocity - the faster you’re going the stronger the force.

  • Drag is the force resulting from wind resistance. It’s based on the car’s cross-section - a large truck or van experiences more drag than a sleek race car. Drag is proportional to the velocity squared.

This means that friction is more significant when moving slowly, but drag becomes dominant at high speeds. We’ll add both of these forces to our calculation. As a bonus, the values of these quantities will also give our car a maximum speed - the point where the force from the engine can’t overcome the drag force any longer.

Here are our starting values for these quantities:

var friction = -55
 var drag = -0.06
-

As you can see in this graph, these values mean that at a speed of 600 the drag force overcomes the friction force.

alt -alt

You can play with the values here to see how they change: +

As you can see in this graph, these values mean that at a speed of 600 the drag force overcomes the friction force.

alt +alt

You can play with the values here to see how they change: https://www.desmos.com/calculator/e4ayu3xkip

In _physics_process() we’ll call a function to calculate the current friction and apply it to the acceleration force.

func _physics_process(delta):
     acceleration = Vector2.ZERO
     get_input()
@@ -100,21 +100,21 @@
     if d < 0:
         velocity = -new_heading * min(velocity.length(), max_speed_reverse)
     rotation = new_heading.angle()
-

Here, we select which traction value to use and apply lerp() to the velocity.

Adjustments

At this point, we have a large number of settings that control the car’s behavior. Adjusting them can drastically change how the car drives. To make experimenting with different values easier, download the project for this recipe below. When you run the game, you’ll see a set of sliders you can use to change the car’s behavior as you drive (press <Tab> to show/hide the slider panel).

alt -alt

Download This Project

Download the project code here: https://github.com/godotrecipes/2d_car_steering

+ + \ No newline at end of file diff --git a/docs/4.x/2d/coyote_time/index.html b/docs/4.x/2d/coyote_time/index.html index 09f94bb3..1edffad4 100644 --- a/docs/4.x/2d/coyote_time/index.html +++ b/docs/4.x/2d/coyote_time/index.html @@ -1,8 +1,8 @@ -Coyote Time :: Godot 4 Recipes - +Coyote Time :: Godot 4 Recipes +

Coyote Time

Problem

Your platformer jumping feels “off”. Players don’t have good control and sometimes they “miss” jumping off the edge of platforms.

Solution

The answer to this problem is to use a technique called “coyote time”. This gives the player a greater feeling of control and a little “wiggle room” around the process of jumping from the edges of platforms.

“Coyote time” works like this:

If the player walks off the edge of a platform, for a few frames afterward, we still allow them to jump as if they were still on the ground.

Origins

The name “coyote time” comes from the famous cartoon coyote, who wouldn’t fall until he looked down:

alt -alt

We’re going to add this to an already existing platform character. See the Platform character recipe for how to set one up.

To handle the timing, we’ll add a Timer node called CoyoteTimer and set it to One Shot.

There are a few new variables we’ll need to keep track of coyote time:

var coyote_frames = 6  # How many in-air frames to allow jumping
+

Coyote Time

Problem

Your platformer jumping feels “off”. Players don’t have good control and sometimes they “miss” jumping off the edge of platforms.

Solution

The answer to this problem is to use a technique called “coyote time”. This gives the player a greater feeling of control and a little “wiggle room” around the process of jumping from the edges of platforms.

“Coyote time” works like this:

If the player walks off the edge of a platform, for a few frames afterward, we still allow them to jump as if they were still on the ground.

Origins

The name “coyote time” comes from the famous cartoon coyote, who wouldn’t fall until he looked down:

alt +alt

We’re going to add this to an already existing platform character. See the Platform character recipe for how to set one up.

To handle the timing, we’ll add a Timer node called CoyoteTimer and set it to One Shot.

There are a few new variables we’ll need to keep track of coyote time:

var coyote_frames = 6  # How many in-air frames to allow jumping
 var coyote = false  # Track whether we're in coyote time or not
 var last_floor = false  # Last frame's on-floor state
 

Since we’re using frames to set the duration, we can translate that to time when setting the Timer’s length in _ready():

$CoyoteTimer.wait_time = coyote_frames / 60.0
@@ -18,17 +18,17 @@
 
Implementing in 3D

You can apply the same process to 3d characters.

Download This Project

The character in the Moving Platforms project has coyote time implemented.

Download the project code here: https://github.com/godotrecipes/2d_moving_platforms

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/enter_exit_screen/index.html b/docs/4.x/2d/enter_exit_screen/index.html index ea62d39c..7c921df3 100644 --- a/docs/4.x/2d/enter_exit_screen/index.html +++ b/docs/4.x/2d/enter_exit_screen/index.html @@ -1,5 +1,5 @@ -Entering/Exiting the screen :: Godot 4 Recipes - +Entering/Exiting the screen :: Godot 4 Recipes +

Entering/Exiting the screen

Problem

You want to detect when an object enters or exits the screen.

Solution

The engine provides a node for this: VisibleOnScreenNotifier2D. Attach this node to your object, and you’ll be able to use its screen_entered and screen_exited signals. *

Example 1

Consider a projectile that travels in a straight line after it’s fired. If we continue firing, eventually we’ll have a large number of objects for the engine to track, event though they’re offscreen, which can cause lag.

Here’s the movement code for the projectile:

extends Area2D
@@ -25,17 +25,17 @@
 
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/grid_movement/index.html b/docs/4.x/2d/grid_movement/index.html index 84f8cdfa..5c99c099 100644 --- a/docs/4.x/2d/grid_movement/index.html +++ b/docs/4.x/2d/grid_movement/index.html @@ -1,5 +1,5 @@ -Grid-based movement :: Godot 4 Recipes - +Grid-based movement :: Godot 4 Recipes +

Grid-based movement

Problem

You need a 2D character that moves in a grid pattern.

Solution

Grid- or tile-based movement means the character’s position is restricted. They can only stand on a particular tile - never between two tiles.

Character setup

Here are the nodes we’ll use for the player:

  • Area2D (“Player”): Using an Area2D means we can detect overlap (for picking up objects or colliding with enemies).
    • Sprite2D: You can use a sprite sheet here (we’ll set up the animation below).
    • CollisionShape2D: Don’t make the hitbox too big. Since the player will be standing on the center of a tile, overlaps will be from the center.
    • RayCast2D: For checking if movement is possible in the given direction.
    • AnimationPlayer: For playing the character’s walk animation(s).

Add some input actions to the Input Map. We’ll use “up”, “down”, “left”, and “right” for this example.

Basic movement

We’ll start by setting up the tile-by-tile movement, without any animations or interpolation.

extends Area2D
@@ -19,16 +19,16 @@
 
 func move(dir):
     position += inputs[dir] * tile_size
-

Here’s the actual movement code. When an input event occurs, we check the four directions to see which one matched, then pass it to move() to change the position.

alt -alt

Collision

Now we can add some obstacles. You can add StaticBody2Ds to manually add some obstacles (enable snapping to make sure they’re aligned with the grid) or use a TileMap (with collisions defined), as in the example below.

We’ll use the RayCast2D to determine whether a move to the next tile is allowed.

onready var ray = $RayCast2D
+

Here’s the actual movement code. When an input event occurs, we check the four directions to see which one matched, then pass it to move() to change the position.

alt +alt

Collision

Now we can add some obstacles. You can add StaticBody2Ds to manually add some obstacles (enable snapping to make sure they’re aligned with the grid) or use a TileMap (with collisions defined), as in the example below.

We’ll use the RayCast2D to determine whether a move to the next tile is allowed.

onready var ray = $RayCast2D
 
 func move(dir):
     ray.target_position = inputs[dir] * tile_size
     ray.force_raycast_update()
     if !ray.is_colliding():
         position += inputs[dir] * tile_size
-

When changing a raycast’s target_position property, the physics engine won’t recalculate its collisions until the next physics frame. force_raycast_update() lets you update the ray’s state immediately. If it’s not colliding, then we allow the move.

alt -alt

Note

Another common method is to use 4 separate raycasts, one for each direction.

Animating movement

Lastly we can interpolate the position between tiles, giving a smooth feel to the movement. We’ll use the Tween node to animate the position property.


+

When changing a raycast’s target_position property, the physics engine won’t recalculate its collisions until the next physics frame. force_raycast_update() lets you update the ray’s state immediately. If it’s not colliding, then we allow the move.

alt +alt

Note

Another common method is to use 4 separate raycasts, one for each direction.

Animating movement

Lastly we can interpolate the position between tiles, giving a smooth feel to the movement. We’ll use the Tween node to animate the position property.


 var animation_speed = 3
 var moving = false
 

Add a reference to the Tween node and a variable to set our movement speed.

func _unhandled_input(event):
@@ -48,21 +48,21 @@
         moving = true
         await tween.finished
         moving = false
-

alt -alt

Experiment with different tween transitions for different movement effects.

Download This Project

Download the project code here: https://github.com/godotrecipes/2d_grid_movement/

+ + \ No newline at end of file diff --git a/docs/4.x/2d/grid_pathfinding/index.html b/docs/4.x/2d/grid_pathfinding/index.html index b45e55cb..1f545868 100644 --- a/docs/4.x/2d/grid_pathfinding/index.html +++ b/docs/4.x/2d/grid_pathfinding/index.html @@ -1,5 +1,5 @@ -Pathfinding on a 2D Grid :: Godot 4 Recipes - +Pathfinding on a 2D Grid :: Godot 4 Recipes +

Pathfinding on a 2D Grid

Problem

You have a grid-based environment and you’d like to set up pathfinding to allow navigation.

Solution

Godot provides a number of methods for pathfinding. For this recipe, we’ll consider the A* algorithm.

About A*

A* is a widely-used algorithm for finding the shortest path between two points. It can be used in any graph-based data structure, not just a grid.

AStarGrid2D is a specialized version of Godot’s more generic AStar2D class. Because it’s specialized for using with a grid, it’s quicker and easier to set up because you don’t have to manually add all the individual grid cells and their connections.

Setting up the Grid

The most important configuration decision is the size of the cells and the size of the grid itself. We’ll use (64, 64) for this example, and we’ll use the window size to determine how many cells fit on the screen, but everything will work the same regardless of cell size.

Add this code to a Node2D.

extends Node2D
 
@@ -29,17 +29,17 @@
         draw_line(Vector2(0, y * cell_size.y),
             Vector2(grid_size.x * cell_size.x, y * cell_size.y),
             Color.DARK_GRAY, 2.0)
-

This gives us a nice visual of the grid:

alt -alt

Drawing the Path

In order to find a path, we need a start and end point. Add these variables at the top of the script:

var start = Vector2i.ZERO
+

This gives us a nice visual of the grid:

alt +alt

Drawing the Path

In order to find a path, we need a start and end point. Add these variables at the top of the script:

var start = Vector2i.ZERO
 var end = Vector2i(5, 5)
 

And a couple of lines in _draw() to show them:

    draw_rect(Rect2(start * cell_size, cell_size), Color.GREEN_YELLOW)
     draw_rect(Rect2(end * cell_size, cell_size), Color.ORANGE_RED)
 

We can find the path between the two points using the get_point_path() method, but we also need to visualize it. We can use a Line2D, so add one to the scene.

Here’s how we can get the path, and add the resulting points to the Line2D:

func update_path():
     $Line2D.points = PackedVector2Array(astar_grid.get_point_path(start, end))
-

Here’s the result:

alt -alt

Note that we have a diagonal line between the two points. This is because, by default, the path will use diagonals. This can be modified by changing the diagonal_mode:

  • DIAGONAL_MODE_ALWAYS - The default value, uses diagonals.
  • DIAGONAL_MODE_NEVER - All movement is orthogonal.
  • DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE - This allows diagonals, but prevents the path going “between” diagonally placed obstacles.
  • DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES - This allows diagonals only in “open” areas, not near obstacles.

Modifying this property can give you very different results, so make sure to experiment based on your setup. Let’s add this in the initialize_grid() function:

astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
-

Now we only have orthogonal moves:

alt -alt

Adding Obstacles

We can also add obstacles to the grid. By marking a cell as “solid”, the path will not include that cell. A cell can be toggled solid/not solid by using the set_point_solid() function.

Let’s add some code to draw our walls (when they exist), by finding any solid cells and coloring them in:

func fill_walls():
+

Here’s the result:

alt +alt

Note that we have a diagonal line between the two points. This is because, by default, the path will use diagonals. This can be modified by changing the diagonal_mode:

  • DIAGONAL_MODE_ALWAYS - The default value, uses diagonals.
  • DIAGONAL_MODE_NEVER - All movement is orthogonal.
  • DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE - This allows diagonals, but prevents the path going “between” diagonally placed obstacles.
  • DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES - This allows diagonals only in “open” areas, not near obstacles.

Modifying this property can give you very different results, so make sure to experiment based on your setup. Let’s add this in the initialize_grid() function:

astar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER
+

Now we only have orthogonal moves:

alt +alt

Adding Obstacles

We can also add obstacles to the grid. By marking a cell as “solid”, the path will not include that cell. A cell can be toggled solid/not solid by using the set_point_solid() function.

Let’s add some code to draw our walls (when they exist), by finding any solid cells and coloring them in:

func fill_walls():
     for x in grid_size.x:
         for y in grid_size.y:
             if astar_grid.is_point_solid(Vector2i(x, y)):
@@ -53,25 +53,25 @@
                 astar_grid.set_point_solid(pos, not astar_grid.is_point_solid(pos))
             update_path()
             queue_redraw()
-

Note that we’re checking is_in_boundsv() first - this will prevent errors from being thrown if we click outside the grid boundaries.

Now we can see the effect of obstacles on the path:

alt -alt

Choosing a Heuristic

A big factor that affects the resulting path is what heuristic you choose to use. The term “heuristic” refers to a “best guess”, and in the context of pathfinding just means: what direction should we try first when moving toward the goal?

For example, the Euclidean distance uses the Pythagorean theorem to estimate the path to try:

alt -alt

While Manhattan distance only considers distance in N/S or E/W directions:

alt -alt

And the Octile heuristic results in a path like this:

alt -alt

You can choose the heuristic using this property:

astar_grid.default_estimate_heuristic = AStarGrid2D.HEURISTIC_OCTILE
+

Note that we’re checking is_in_boundsv() first - this will prevent errors from being thrown if we click outside the grid boundaries.

Now we can see the effect of obstacles on the path:

alt +alt

Choosing a Heuristic

A big factor that affects the resulting path is what heuristic you choose to use. The term “heuristic” refers to a “best guess”, and in the context of pathfinding just means: what direction should we try first when moving toward the goal?

For example, the Euclidean distance uses the Pythagorean theorem to estimate the path to try:

alt +alt

While Manhattan distance only considers distance in N/S or E/W directions:

alt +alt

And the Octile heuristic results in a path like this:

alt +alt

You can choose the heuristic using this property:

astar_grid.default_estimate_heuristic = AStarGrid2D.HEURISTIC_OCTILE
 

Which of these works best (results in the most pleasing paths) depends on the nature of your environment. Is it mostly wide-open spaces with few obstacles scattered around? Or is it a maze of twisty passages? Make sure to experiment with your specific project.

Download the example project below to experiment with this setup yourself. In addition to placing walls, you can use the right/middle mouse buttons to move the end/start locations.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/grid_pathfinding

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/index.html b/docs/4.x/2d/index.html index d40a354a..1693c39b 100644 --- a/docs/4.x/2d/index.html +++ b/docs/4.x/2d/index.html @@ -1,19 +1,19 @@ -2D :: Godot 4 Recipes - +2D :: Godot 4 Recipes +
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/moving_platforms/index.html b/docs/4.x/2d/moving_platforms/index.html index 173b1d2c..c5a2a690 100644 --- a/docs/4.x/2d/moving_platforms/index.html +++ b/docs/4.x/2d/moving_platforms/index.html @@ -1,5 +1,5 @@ -Moving Platforms :: Godot 4 Recipes - +Moving Platforms :: Godot 4 Recipes +

Moving Platforms

Problem

You need moving platforms in your 2D platformer.

Solution

There are several ways to approach this problem. In this recipe, we’ll use AnimatableBody2Ds for our platform and move it with a Tween. This allows for a variety of movement styles while minimizing the amount of code we need to write.

Info

You can also implement this moving platform technique using an AnimationPlayer rather than a tween. Much of the setup will be the same, but rather than tween code, you’ll animate the body’s position property.

Setting up

We’ll start with a basic platformer setup using the Platform character recipe. The basic movement from that recipe will work fine with the platforms. If you’ve modified it or used your own, everything should still work the same.

Creating the platform

The platform scene contains the following nodes:

  • Node2D (“MovingPlatform”): The Node2D parent is there to act as the “anchor” or start point for the platform. We’ll animate the platform’s position relative to this parent node.
    • AnimatableBody2D: This represents the platform itself. This is the node that will move.
      • Sprite2D: You can use a sprite sheet here, individual images, or even a TileMap.
      • CollisionShape2D: Don’t make the hitbox too big, or the player will appear to be “hovering” off the edge of the platform.

Set up the Sprite2D’s Texture and the collision shape appropriately. In the AnimatableBody2D, set the Sync to Physics property “On”. Since we’re moving the body in code, this ensures that it’s moved during the physics step, keeping it in sync with the player and other physics bodies.

Now add a script to the root Node2D:

extends Node2D
 
@@ -17,17 +17,17 @@
 

We’ve used a few of Tween’s options here to make everything work smoothly:

  • set_process_mode(): ensures that all movement takes place during the physics processing step.
  • set_loops(): this makes the tween repeat.
  • set_parallel(false): by default, all tween_property() changes would happen at that same time. This makes the two happen one after another: moving to one end of the offset, then back to the start.

Using the two exported properties, you can adjust the platform’s movement. Set the offset to determine where the tween moves relative to its starting point, and the duration to determine how long it takes to complete the cycle.

Add some platforms in your level/world and try them out:

Download This Project

Download the project code here: https://github.com/godotrecipes/2d_moving_platforms

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/multi_target_camera/index.html b/docs/4.x/2d/multi_target_camera/index.html index 15d09bae..9a834954 100644 --- a/docs/4.x/2d/multi_target_camera/index.html +++ b/docs/4.x/2d/multi_target_camera/index.html @@ -1,8 +1,8 @@ -Multitarget Camera :: Godot 4 Recipes - +Multitarget Camera :: Godot 4 Recipes +

Multitarget Camera

Problem

You need a dynamic camera that moves and zooms to keep multiple objects on screen at the same time.

An example might be in a 2 player game, keeping both players on-screen as they move farther and closer together, like so:

alt -alt

Solution

In a single-player game, you’re probably used to attaching the camera to the player, so that it automatically follows them. We can’t really do this here because we have 2 (or more) players or other game objects that we want to keep on the screen at all times.

We need our camera to do 3 things:

  1. Add/remove any number of targets.
  2. Keep the camera’s position centered at the midpoint of the targets.
  3. Adjust the camera’s zoom to keep all targets on screen.

Create a new scene with a Camera2D and attach a script. We’ll add this camera to our game once we’re done.

Let’s break down how the script works.

Note

You can see the full script at the end of the article.

Here’s how the script starts:

extends Camera2D
+

Multitarget Camera

Problem

You need a dynamic camera that moves and zooms to keep multiple objects on screen at the same time.

An example might be in a 2 player game, keeping both players on-screen as they move farther and closer together, like so:

alt +alt

Solution

In a single-player game, you’re probably used to attaching the camera to the player, so that it automatically follows them. We can’t really do this here because we have 2 (or more) players or other game objects that we want to keep on the screen at all times.

We need our camera to do 3 things:

  1. Add/remove any number of targets.
  2. Keep the camera’s position centered at the midpoint of the targets.
  3. Adjust the camera’s zoom to keep all targets on screen.

Create a new scene with a Camera2D and attach a script. We’ll add this camera to our game once we’re done.

Let’s break down how the script works.

Note

You can see the full script at the end of the article.

Here’s how the script starts:

extends Camera2D
 
 @export var move_speed = 30 # camera position lerp speed
 @export var zoom_speed = 3.0  # camera zoom lerp speed
@@ -40,8 +40,8 @@
 else:
     z = 1 / clamp(r.size.y / screen_size.y, min_zoom, max_zoom)
 zoom = lerp(zoom, Vector2.ONE * z, zoom_speed)
-

The key functionality here comes from Rect2. We want to find a rectangle that encloses all the targets, which we can get with the expand() method. We then grow the rect by the margin.

Here you can see the rectangle being drawn (press “Tab” in the demo project to enable this drawing):

alt -alt

Then, depending whether the rectangle is wider or taller (relative to the screen’s aspect ratio), we find the scale and clamp it in the max/min range we’ve defined.

Full script

extends Camera2D
+

The key functionality here comes from Rect2. We want to find a rectangle that encloses all the targets, which we can get with the expand() method. We then grow the rect by the margin.

Here you can see the rectangle being drawn (press “Tab” in the demo project to enable this drawing):

alt +alt

Then, depending whether the rectangle is wider or taller (relative to the screen’s aspect ratio), we find the scale and clamp it in the max/min range we’ve defined.

Full script

extends Camera2D
 
 @export var move_speed = 30 # camera position lerp speed
 @export var zoom_speed = 3.0  # camera zoom lerp speed
@@ -89,17 +89,17 @@
 

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/multitarget_camera

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/platform_character/index.html b/docs/4.x/2d/platform_character/index.html index cc05e127..fef50c23 100644 --- a/docs/4.x/2d/platform_character/index.html +++ b/docs/4.x/2d/platform_character/index.html @@ -1,5 +1,5 @@ -Platform character :: Godot 4 Recipes - +Platform character :: Godot 4 Recipes +

Platform character

Problem

You need to make a 2D platform-style character.

Solution

New developers are often surprised at how complex a platform character can be to program. Godot provides some built-in tools to assist, but there are as many solutions as there are games. In this tutorial, we won’t be going in-depth with features like double-jumps, crouching, wall-jumps, or animation. Here we’ll discuss the fundamentals of platformer movement. See the rest of the recipes for other solutions.

Tip

While it’s possible to use RigidBody2D to make a platform character, we’ll be focusing on CharacterBody2D. Kinematic bodies are well-suited for platformers, where you are less interested in realistic physics than in responsive, arcade feel.

Start with a CharacterBody2D node, and add a Sprite2D and CollisionShape2D to it.

Attach the following script to the root node of the character. Note that we’re using input actions we’ve defined in the InputMap: "walk_right", "walk_left", and "jump". See InputActions.

extends CharacterBody2D
 
@@ -40,21 +40,21 @@
     move_and_slide()
     if Input.is_action_just_pressed("jump") and is_on_floor():
         velocity.y = jump_speed
-

Try changing the values for friction and acceleration to see how they affect the game’s feel. An ice level, for example, could use very low values, making it harder to maneuver.

alt -alt

Conclusion

This code gives you a starting point for building your own platformer controller. For more advanced platforming features such as wall jumps, see the other recipes in this section.

Download This Project

Download the project code here: https://github.com/godotrecipes/2d_platform_basic

+ + \ No newline at end of file diff --git a/docs/4.x/2d/screen_wrap/index.html b/docs/4.x/2d/screen_wrap/index.html index 855dae45..c858c7f4 100644 --- a/docs/4.x/2d/screen_wrap/index.html +++ b/docs/4.x/2d/screen_wrap/index.html @@ -1,5 +1,5 @@ -Screen wrap :: Godot 4 Recipes - +Screen wrap :: Godot 4 Recipes +

Screen wrap

Problem

You want to allow the player to “wrap around” the screen, teleporting from one side of the screen to the other. This is a common feature, especially in old-school 2D games (think Pac-man).

Solution

  1. Get your screen (viewport) size

    @onready var screen_size = get_viewport_rect().size
     

    get_viewport_rect() is available to any CanvasItem derived node.

  2. Compare your player’s position

    if position.x > screen_size.x:
    @@ -15,17 +15,17 @@
     
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/topdown_movement/index.html b/docs/4.x/2d/topdown_movement/index.html index eb2900e6..24ce6c13 100644 --- a/docs/4.x/2d/topdown_movement/index.html +++ b/docs/4.x/2d/topdown_movement/index.html @@ -1,5 +1,5 @@ -Top-down movement :: Godot 4 Recipes - +Top-down movement :: Godot 4 Recipes +

Top-down movement

Problem

You’re making a 2D top-down game, and you want to control a character’s movement.

Solution

For this solution, we’ll assume you have the following input actions defined:

Action NameKey(s)
"up"W,↑
"down"S,↓
"right"D,→
"left"A,←
"click"Mouse button 1

We will also assume you’re using a CharacterBody2D node.

We can solve this problem in many ways, depending on what type of behavior you’re looking for.

Option 1: 8-way movement

In this scenario, the player uses the four directional keys to move (including diagonals).

extends CharacterBody2D
 
@@ -49,17 +49,17 @@
 

Note that we stop moving if we get close to the target position. If you don’t do this, the character will “jiggle” back and forth as it moves a little bit past the target, moves back, goes a little past it, and so on. Optionally, you can use look_at() to face in the direction of movement.

Download This Project

Download the project code here: https://github.com/godotrecipes/topdown_movement

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/2d/using_ysort/index.html b/docs/4.x/2d/using_ysort/index.html index 5ab52f50..38375d80 100644 --- a/docs/4.x/2d/using_ysort/index.html +++ b/docs/4.x/2d/using_ysort/index.html @@ -1,26 +1,26 @@ -Using Y-Sort :: Godot 4 Recipes - +Using Y-Sort :: Godot 4 Recipes +

Using Y-Sort

Problem

Many 2D games use a “3/4 view” perspective, giving the impression that the camera is looking at the world at an angle. To make this work, objects that are “farther” away need to be rendered behind “nearer” objects. In practice, that means we want to “y-sort” - making the drawing order tied to the object’s y coordinate. The higher on the screen, the farther away and therefore lower the render order.

Here’s an example of the problem:

alt -alt

These objects are being drawn in the default render order: tree order. They are arranged like this in the scene tree:

alt -alt

Solution

Godot has a built-in option to change the render order: on any CanvasItem node (Node2D or Control), we can enable the Y Sort Enabled property. When this is enabled, all child nodes are then y-sorted.

In the above example, we can enable the property on the TileMap node. However, there’s still a problem:

alt -alt

The draw order is based on each object’s y coordinate. By default, that is the object’s center:

alt -alt

Since we want to give the impression that the objects are on the “ground”, we can solve this by offsetting each object’s sprite so that the object’s position is aligned with the bottom of the sprite:

alt -alt

Now things look a lot better:

alt -alt

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/using_ysort

+ + \ No newline at end of file diff --git a/docs/4.x/3d/3d_align_surface/index.html b/docs/4.x/3d/3d_align_surface/index.html index 2cc7683d..15acf062 100644 --- a/docs/4.x/3d/3d_align_surface/index.html +++ b/docs/4.x/3d/3d_align_surface/index.html @@ -1,9 +1,9 @@ -CharacterBody3D: Align with Surface :: Godot 4 Recipes - +CharacterBody3D: Align with Surface :: Godot 4 Recipes +

CharacterBody3D: Align with Surface

Problem

You need your character body to align with the surface or terrain.

Solution

This recipe builds on the basic CharacterBody3D controller described in the CharacterBody3D: Movement recipe, so read that one first.

First, we’ve added some terrain to the scene. You can download the terrain from here: https://fertile-soil-productions.itch.io/modular-terrain-pack. This is low-poly terrain, but you can use or make any terrain you like for this technique.

As you can see, the movement still works with the terrain, but the tank seems to “float” above the slopes because it doesn’t change its orientation.

Instead, we need to rotate the tank so that its treads are aligned with the ground, even as the slope changes. To do that, we need to know which way is up.

Surface normals

A surface normal is a unit vector (“normal vector” and “unit vector” mean the same thing) perpendicular to a surface. It shows which way the surface is facing. In the case of a mesh, every surface has a normal pointing outward.

alt -alt

alt -alt

In Godot, when a body collides, you can get the normal of the collision. This will be the colliding body’s normal at the point of contact.

Once we have the surface normal, we need to align the tank’s Y axis with it. Note that we can’t use Transform3D.looking_at(), because that will align the -Z (forward) axis with the normal.

To do this, we’ll use the following function:

func align_with_y(xform, new_y):
+

CharacterBody3D: Align with Surface

Problem

You need your character body to align with the surface or terrain.

Solution

This recipe builds on the basic CharacterBody3D controller described in the CharacterBody3D: Movement recipe, so read that one first.

First, we’ve added some terrain to the scene. You can download the terrain from here: https://fertile-soil-productions.itch.io/modular-terrain-pack. This is low-poly terrain, but you can use or make any terrain you like for this technique.

As you can see, the movement still works with the terrain, but the tank seems to “float” above the slopes because it doesn’t change its orientation.

Instead, we need to rotate the tank so that its treads are aligned with the ground, even as the slope changes. To do that, we need to know which way is up.

Surface normals

A surface normal is a unit vector (“normal vector” and “unit vector” mean the same thing) perpendicular to a surface. It shows which way the surface is facing. In the case of a mesh, every surface has a normal pointing outward.

alt +alt

alt +alt

In Godot, when a body collides, you can get the normal of the collision. This will be the colliding body’s normal at the point of contact.

Once we have the surface normal, we need to align the tank’s Y axis with it. Note that we can’t use Transform3D.looking_at(), because that will align the -Z (forward) axis with the normal.

To do this, we’ll use the following function:

func align_with_y(xform, new_y):
     xform.basis.y = new_y
     xform.basis.x = -xform.basis.z.cross(new_y)
     xform.basis = xform.basis.orthonormalized()
@@ -32,17 +32,17 @@
 

Feel free to experiment with the interpolation amount. We found 12 to work well in this situation, but you might find a higher or lower value works better for your setup.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/3d_sphere_car/index.html b/docs/4.x/3d/3d_sphere_car/index.html index 10e20779..d10fde3e 100644 --- a/docs/4.x/3d/3d_sphere_car/index.html +++ b/docs/4.x/3d/3d_sphere_car/index.html @@ -1,14 +1,14 @@ -Arcade-style Car :: Godot 4 Recipes - +Arcade-style Car :: Godot 4 Recipes +

Arcade-style Car

Problem

You want to make an arcade-style car game, so you’re looking for simplicity over realistic physics. In this recipe, you’ll learn how to make a fun, driveable car using a rolling sphere.

Solution

There are a lot of ways to make a driving game. Different games need different levels of realism. If you’re trying to make a light, arcade-style car, you don’t need all of the features that Godot’s VehicleBody3D node provides, such as supension, independently modeled wheels, etc.

Instead, we’re going to use a single RigidBody3D sphere to handle the driving physics. The sphere will be invisible, and the car mesh will be placed at the sphere’s location, making it look like it’s the car that’s driving.

As you can see in the preview clip above, the result looks remarkably good (and feels great to play!). Read on, and you’ll see that the amount of code required is also surprisingly small.

Inputs

For control, we’re going to add four inputs to the Input Map:

  • accelerate
  • brake
  • steer_left
  • steer_right

You can use keyboard input, game controller, or both. However, we recommend going with the analog stick for better steering.

Node setup

The car is made with two main nodes: a RigidBody3D sphere for the physics, and a MeshInstance3D to display the car body. Here’s the scene layout:

 RigidBody3D (Car)
       CollisionShape3D (Sphere)
       CarMesh (Imported model)
-

Here’s how these nodes will interact: pressing “accelerate” will apply a force on the RigidBody3D in the direction the CarMesh is facing, while the turning inputs will rotate the CarMesh. As the ball rolls, it will carry the car mesh along with it (we’ll ignore the ball’s rotation).

CarMesh

Here’s the car model we’ll use:

alt -alt

Note

You can find this and other car models in Kenney’s “Car Kit”, available here: -https://kenney.nl/assets/car-kit. Download the whole kit; you can use any of them that you choose. Note that this kit includes the models in multiple formats - you won’t need all of them for your project. GLTF is the recommended format for use with Godot.

If you use the GLTF models, you shouldn’t have adjust anything in the import settings.

Here’s what the node tree looks like when importing the “suv” model:

alt -alt

Note that the wheels & body are separate meshes. This will make it easy to add some visual appeal - like turning the wheels when steering.

Ball

Add a sphere shape to the CollisionShape3D. We’re using a radius of 1 here, but you’ll want to experiment with the size of the ball to get different driving behaviors.

Here’s how to adjust the settings on the body:

  • Angular Damp: 10 - this property will have a huge effect on the driving feel. A higher value will bring the car to a stop much faster.
  • Gravity Scale: 5 - Default gravity in Godot (9.8) feels a bit floaty, especially when going for an action feel. This will really matter if you plan to have jumps, hills, etc. in your world. You can set this globally in the Project Settings instead, if you prefer.
  • Physics Material/Bounce: 0.1 - Playing around with this value can be a lot of fun. Be careful going above 0.5, though!

For the demo, we’ve also added a spherical mesh to the collision shape for debugging purposes. You don’t need this, but it helps when troubleshooting to have a visual of the ball rolling.

RayCast

Finally, add a RayCast3D node as a child of the CarMesh. Set its Target Position to (0, -1, 0).

alt -alt

We’re going to use this for ground detection. When the car’s in the air, steering and acceleration won’t work. We can also use it to align the car mesh to a slope (if your game’s track isn’t flat).

Now we’re ready to start coding.

Script

We’ll begin the script with some node references we’ll need:

extends RigidBody3D
+

Here’s how these nodes will interact: pressing “accelerate” will apply a force on the RigidBody3D in the direction the CarMesh is facing, while the turning inputs will rotate the CarMesh. As the ball rolls, it will carry the car mesh along with it (we’ll ignore the ball’s rotation).

CarMesh

Here’s the car model we’ll use:

alt +alt

Note

You can find this and other car models in Kenney’s “Car Kit”, available here: +https://kenney.nl/assets/car-kit. Download the whole kit; you can use any of them that you choose. Note that this kit includes the models in multiple formats - you won’t need all of them for your project. GLTF is the recommended format for use with Godot.

If you use the GLTF models, you shouldn’t have adjust anything in the import settings.

Here’s what the node tree looks like when importing the “suv” model:

alt +alt

Note that the wheels & body are separate meshes. This will make it easy to add some visual appeal - like turning the wheels when steering.

Ball

Add a sphere shape to the CollisionShape3D. We’re using a radius of 1 here, but you’ll want to experiment with the size of the ball to get different driving behaviors.

Here’s how to adjust the settings on the body:

  • Angular Damp: 10 - this property will have a huge effect on the driving feel. A higher value will bring the car to a stop much faster.
  • Gravity Scale: 5 - Default gravity in Godot (9.8) feels a bit floaty, especially when going for an action feel. This will really matter if you plan to have jumps, hills, etc. in your world. You can set this globally in the Project Settings instead, if you prefer.
  • Physics Material/Bounce: 0.1 - Playing around with this value can be a lot of fun. Be careful going above 0.5, though!

For the demo, we’ve also added a spherical mesh to the collision shape for debugging purposes. You don’t need this, but it helps when troubleshooting to have a visual of the ball rolling.

RayCast

Finally, add a RayCast3D node as a child of the CarMesh. Set its Target Position to (0, -1, 0).

alt +alt

We’re going to use this for ground detection. When the car’s in the air, steering and acceleration won’t work. We can also use it to align the car mesh to a slope (if your game’s track isn’t flat).

Now we’re ready to start coding.

Script

We’ll begin the script with some node references we’ll need:

extends RigidBody3D
 
 @onready var car_mesh = $CarMesh
 @onready var body_mesh = $CarMesh/suv2
@@ -59,26 +59,26 @@
 

And right after getting input, add the following:

    # rotate wheels for effect
     right_wheel.rotation.y = rotate_input
     left_wheel.rotation.y = rotate_input
-

alt -alt

3. Tilt the body

This one adds lots of visual appeal. We’re going to tilt the car’s body based on the speed of the turn. Add a variable at the top of the script:

var body_tilt = 35
+

alt +alt

3. Tilt the body

This one adds lots of visual appeal. We’re going to tilt the car’s body based on the speed of the turn. Add a variable at the top of the script:

var body_tilt = 35
 

The smaller this number, the more extreme the tilt effect will be. Between 35 and 40 works well for the SUV model.

Now add the following right after rotating the car mesh (in the if statement):

# tilt body for effect
 var t = -rotate_input * ball.linear_velocity.length() / body_tilt
 body_mesh.rotation.z = lerp(body_mesh.rotation.z, t, 10 * delta)
-

Observe the difference:

alt -alt

Credits

The demo project seen here uses the following open-source/creative commons assets:

Download This Project

Download the project code here: https://github.com/godotrecipes/3d_car_sphere

+ + \ No newline at end of file diff --git a/docs/4.x/3d/assets/character_animation/index.html b/docs/4.x/3d/assets/character_animation/index.html index 6829bbe2..f1680b65 100644 --- a/docs/4.x/3d/assets/character_animation/index.html +++ b/docs/4.x/3d/assets/character_animation/index.html @@ -1,29 +1,29 @@ -Character Animation :: Godot 4 Recipes - +Character Animation :: Godot 4 Recipes +

Character Animation

Problem

You’ve got a rigged, animated 3D character (either made by you or downloaded from a third party) and you want to set up its animations in Godot.

Solution

In this recipe, we’ll assume you’ve already imported your character model and animations. If you haven’t yet, see Importing Assets for details. As a reminder, we’re using the art packs linked in the section description.

Prepping the character

We’ve chosen CharacterBody3D for our character, so your scene should look like this (I’ve collapsed the Rig node since the mesh list is so long):

alt -alt

The first thing you probably noticed is that the character’s hands are full! The artist has helpfully provided all the weapons & shields attached and oriented at the correct points. You can go down the list and hide the ones you don’t want to see.

alt -alt

About the AnimationTree

With all of the animations we have available, it’s going to quickly get very complicated to handle all of them in code. Think about how many if statement’s we’d need to decide which animation to play at which time, depending on what the player is doing. While this is not bad if you only have a few animations, it quickly gets out of hand and becomes impractical.

Also, consider when the character is standing still: it should be playing the “Idle” animation. When the player presses “forward”, the character should move and switch to playing the “Walking” animation. This sudden transition is going to look jarring, so we’d prefer if the two animations can be “blended” into a smoother transition.

The solution to these complex animation issues is to use the AnimationTree node. This node is designed to control an AnimationPlayer and has functionality to control how animations transition and blend together.

Add an AnimationTree to the scene. In the Inspector, set Tree Root to a new AnimationNodeStateMachine, in Anim Player select the character’s AnimationPlayer node, and check the box next to Active.

alt -alt

Note

You may notice that when the AnimationTree is active, you can’t choose animations in the AnimationPlayer. If you need to make any changes or test the animations, uncheck the tree’s Active property while doing so.

The Idle/Walk/Run Cycle

There are a lot of animations provided with these models. For this example, we’re going to focus on the idle-walk-run cycle, jumping, and attacking. If you want to include other animations, they’ll be handled in a similar way.

In the AnimationPlayer, find the “Idle”, “Running_A”, “Walking_Backwards”, and “Running_Strafe_Left”/“Running_Strafe_Right” animations. Make sure they’re all set to loop - you can test them by pressing the “Play” button: (▶). If any of them are not, reimport the character after setting them (see Importing Assets).

Select the AnimationTree node and you’ll see the panel open at the bottom of the window:

alt -alt

As an example, right-click in the empty space and choose Add Animation → Idle, then add the “1H_Melee_Attack_Chop” animation as well.

Select the Connect Nodes button and draw a connection from Start to Idle. You should immediately see the “Idle” animation playing.

Now, we want to be able to transition from idle to attack and then back to idle when the attack animation finishes. Draw two more connection arrows to and from the attack. It won’t quite work, however, you’ll just be rapidly flickering between the two animations, because both are set to immediately transition.

To change the transition conditions, change to Select mode using the icon and then click on one of the connections. In the Inspector, you’ll see the connection properties. For the connection from idle to attack, we want Advance/Mode to be “Enabled” (not “Auto”). This means it happens only when told to. Notice that the icon on the connection line changes color.

For the connection from attack to idle, set Switch Mode to “At End” and Advance Mode to “Auto”.

Now, when you press the ▶ button on the attack node, it will play and then transition back to idle as soon as it completes.

This gives you an idea how to set up different animations and transition between them. However, we want to do a little more here, so delete the two animations using the trash can icon, and let’s set up a blendspace.

Blendspaces

Right-click in the empty space to create a new BlendSpace2D. Click on its name to rename it to IWR (for idle-walk-run). Add a transition from Start so that the blendspace will start playing automatically.

Click the pencil icon to edit the blend space.

alt -alt

This 2D space represents the character’s horizontal movement vector. When standing still that’s (0, 0), so click the Create Points button and click in the center of the grid to Add Animation → Idle.

At the center-top, add the “Running_A” animation, and center-bottom, “Walking_Backwards”. At the two horizontal ends, add the strafe animations.

alt -alt

Now click the crosshair button to set the blend position and click to drag it around the grid. You should see the animations transition smoothly between the extremes.

When you’re done experimenting with the blendspace, click “Root” in the Path at the top of the panel to return to the root of the tree.

Setting up the state machine

The IWR looping animations can be thought of as the “heart” of the animation tree. The character will spend most of its time playing these animations. Any other animations will branch off from it (like we did earlier with the attack).

In the image below, I’ve done that with several other animations. Note the transition properties are set as we did in the example above.

alt -alt

You can also click to change the names the animations, as some of them are quite long.

The one animation that’s different is jumping. The jump animation is split into three parts: “start"and “land”, which are played when the character starts jumping, and when the jump ends. The “idle” portion of the jump is a looping animation that plays as long as the character is in the air - if they fall a long way, for example.

Add the three jumping animations and link them like this:

alt -alt

We need to be able to go straight from IWR to Jump_Idle in the event of falling off a ledge, but if pressing “jump”, we’ll go through Jump_Start first.

In addition, we’ve left the transition from IWR to Jump_Start as “Auto”. Instead of changing it to “Enabled”, we’ve added a Condition of jumping to the transition:

alt -alt

Similarly, the transition between Jump_Idle and Jump_Land has a condition of grounded.

We’ll be able to set these conditions in code to trigger the transition.

Finally, if you’re looking closely, you may notice that the transition from Jump_Land to IWR does not look smooth, because the last frame and first frame of the two animations don’t quite match up. We can solve this by selecting the transition between them and setting a small Xfade Time of 0.1, which will smooth it out nicely.

Wrapping up

We’ve now set up our 3D character’s animations and they’re ready to use. By setting up the AnimationTree, it will now be much easier to select and transition between animations in the character’s movement code.

See the section description for more examples of working in 3D and for example Godot projects you can download.

Companion Video

https://youtu.be/YrNQCB34PAc

+ + \ No newline at end of file diff --git a/docs/4.x/3d/assets/character_controller/index.html b/docs/4.x/3d/assets/character_controller/index.html index ae1d6eb0..c6d2d154 100644 --- a/docs/4.x/3d/assets/character_controller/index.html +++ b/docs/4.x/3d/assets/character_controller/index.html @@ -1,8 +1,8 @@ -Character Controller :: Godot 4 Recipes - +Character Controller :: Godot 4 Recipes +

Character Controller

Problem

You’ve imported a rigged, animated 3D character in Godot and set up its animations using AnimationTree. Now you need to implement movement: you need a character controller.

Solution

In this recipe, we’ll assume you’ve already imported your character model and animations, and that you’re set up AnimationTree to handle transitioning and blending the animations. If you haven’t yet, see Importing Assets and Character Animation for details. As a reminder, we’re using the art packs linked in the section description.

Adding collision

We’ve chosen CharacterBody3D as the root node of the imported scene, and it’s complaining about a missing collision shape, so let’s fix that first. Add a CollisionShape3D child and choose CapsuleShape3D as its Shape property.

Size and position the capsule to enclose the character’s body. For reference, here are the values I used:

alt -alt

Note that the imported rig is positioned so that its feet are on the “ground”, ie at the body’s position. This will be helpful later, as the player’s position will represent its position on the ground, rather than floating in mid-air if it were at the center of its body.

If you’re familiar with Godot’s 3D orientation, you’ll also notice that the character is facing the +Z direction, which is backwards. Select the Skeleton3D node and set its Y Rotation to 180 to correct this.

Input actions

In the Input Map, we’re using the following inputs: forward, back, left, right, and jump. Assign them to whatever keys/buttons you prefer.

Camera

There are many ways to handle a 3D camera that follows the player. For this example, we’ll use a SpringArm3D as the camera “mount”.

The SpringArm3D node works by casting a ray and then moving its children to the collision point. Using this for a camera means nothing can get between the camera and the player, and we can implement zoom by varying this length.

Add one as a child of the root node, and then add a Camera3D as a child of that.

In the spring arm’s properties, set Spring Length to 5, the Margin to 0.1, and the Position to (0, 2.5, 0).

We don’t want the spring arm to collide with the player’s capsule shape, so in the root CharacterBody3D set the collision layer to 2. Since the spring arm is checking collision layer 1, that will prevent the camera hitting the player’s head.

Collision Layers

Eventually, we’ll want to organize our collision layers for various game objects: player, environment, enemies, etc.

Movement

Now we are ready to add a script to the player. We’ll start with the variables we’ll need:

extends CharacterBody3D
+

Character Controller

Problem

You’ve imported a rigged, animated 3D character in Godot and set up its animations using AnimationTree. Now you need to implement movement: you need a character controller.

Solution

In this recipe, we’ll assume you’ve already imported your character model and animations, and that you’re set up AnimationTree to handle transitioning and blending the animations. If you haven’t yet, see Importing Assets and Character Animation for details. As a reminder, we’re using the art packs linked in the section description.

Adding collision

We’ve chosen CharacterBody3D as the root node of the imported scene, and it’s complaining about a missing collision shape, so let’s fix that first. Add a CollisionShape3D child and choose CapsuleShape3D as its Shape property.

Size and position the capsule to enclose the character’s body. For reference, here are the values I used:

alt +alt

Note that the imported rig is positioned so that its feet are on the “ground”, ie at the body’s position. This will be helpful later, as the player’s position will represent its position on the ground, rather than floating in mid-air if it were at the center of its body.

If you’re familiar with Godot’s 3D orientation, you’ll also notice that the character is facing the +Z direction, which is backwards. Select the Skeleton3D node and set its Y Rotation to 180 to correct this.

Input actions

In the Input Map, we’re using the following inputs: forward, back, left, right, and jump. Assign them to whatever keys/buttons you prefer.

Camera

There are many ways to handle a 3D camera that follows the player. For this example, we’ll use a SpringArm3D as the camera “mount”.

The SpringArm3D node works by casting a ray and then moving its children to the collision point. Using this for a camera means nothing can get between the camera and the player, and we can implement zoom by varying this length.

Add one as a child of the root node, and then add a Camera3D as a child of that.

In the spring arm’s properties, set Spring Length to 5, the Margin to 0.1, and the Position to (0, 2.5, 0).

We don’t want the spring arm to collide with the player’s capsule shape, so in the root CharacterBody3D set the collision layer to 2. Since the spring arm is checking collision layer 1, that will prevent the camera hitting the player’s head.

Collision Layers

Eventually, we’ll want to organize our collision layers for various game objects: player, environment, enemies, etc.

Movement

Now we are ready to add a script to the player. We’ll start with the variables we’ll need:

extends CharacterBody3D
 class_name Knight
 
 @export var speed = 5.0
@@ -15,8 +15,8 @@
 @onready var model = $Rig
 @onready var anim_tree = $AnimationTree
 @onready var anim_state = $AnimationTree.get("parameters/playback")
-

We’ll use the anim_tree reference to set the blend position for the Idle/Walk/Run blendspace and the trigger conditions for jumping. Select the AnimationTree and you can see these properties in the Inspector:

alt -alt

anim_state is a reference to the animation state machine, which we can use to call transitions between animations. See the Character Animation recipe for how we set these up.

Movement is a matter of getting the player’s input and calling move_and_slide():

func _physics_process(delta):
+

We’ll use the anim_tree reference to set the blend position for the Idle/Walk/Run blendspace and the trigger conditions for jumping. Select the AnimationTree and you can see these properties in the Inspector:

alt +alt

anim_state is a reference to the animation state machine, which we can use to call transitions between animations. See the Character Animation recipe for how we set these up.

Movement is a matter of getting the player’s input and calling move_and_slide():

func _physics_process(delta):
     velocity.y += -gravity * delta
     get_move_input(delta)
 
@@ -47,8 +47,8 @@
 ]
 

Then, in _unhandled_input(), pick a random animation from the list when the action is pressed:

    if event.is_action_pressed("attack"):
         anim_state.travel(attacks.pick_random())
-

Jumping

Jumping is a little bit more involved, because it involves three separate animations. As a reminder, this is how we set up the state machine:

alt -alt

First, we want to transition to the “Jump_Start” animation by setting jumping = true. This triggers the transition in the state machine.

    if is_on_floor() and Input.is_action_just_pressed("jump"):
+

Jumping

Jumping is a little bit more involved, because it involves three separate animations. As a reminder, this is how we set up the state machine:

alt +alt

First, we want to transition to the “Jump_Start” animation by setting jumping = true. This triggers the transition in the state machine.

    if is_on_floor() and Input.is_action_just_pressed("jump"):
         velocity.y = jump_speed
         jumping = true
         anim_tree.set("parameters/conditions/grounded", false)
@@ -66,17 +66,17 @@
 

Wrapping up

We’ve now got a functional, controllable character with a chase camera and multiple animations. What’s next?

See the section description for more examples of working in 3D and for example Godot projects you can download.

Companion Video

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/assets/importing_assets/index.html b/docs/4.x/3d/assets/importing_assets/index.html index 879c1175..aeeefcfc 100644 --- a/docs/4.x/3d/assets/importing_assets/index.html +++ b/docs/4.x/3d/assets/importing_assets/index.html @@ -1,12 +1,12 @@ -Importing Assets :: Godot 4 Recipes - +Importing Assets :: Godot 4 Recipes +

Importing Assets

Problem

You’ve downloaded (or created) a set of 3D assets, including rigged and animated characters, and you want to import it into Godot.

Solution

For this example, we’ll assume you’ve downloaded the art packs linked in the section description and unzipped them.

Before copying the files into your Godot project, notice that there are multiple versions of the assets in different file formats: OBJ, FBX, and GLTF. There are also some extra files such as examples and separate textures in case you want to modify them. We don’t need all of that, and GLTF is the preferred import format for Godot. So make sure you’re only dragging the gltf folder or .gltf files (or .glb, which is the binary version of the same) into your project folder.

Here, I’ve taken the gltf folder from the “Dungeon” pack and the characters folder from the “Adventurers” pack and dragged them into my project.

Note

There are a lot of files in the Dungeon pack - Godot may take a little time to read them all!

Importing a Character

Select the knight.glb file in the FileSystem tab, then click the Import tab at the top left.

alt -alt

Here you’ll find some basic import settings, but we can go into more detail. Click Advanced button and you’ll see a new window appear:

alt -alt

One the left you’ll see all the data that is contained in the GLTF scene, including textures and animations. Note all the weapon options attached to the character and the extensive list of animations.

There’s a preview of the character in the middle, and a set of options on the right side where you can adjust how the selected item is configured.

Since we will code our player as a CharacterBody3D, we can go ahead and specify that node type here. Click on the Scene Root and on the right set the Root Type to CharacterBody3D.

Animations

Scroll down to the list of animations. You’ll see that there are many, but while some we’ll only want to play once, such as attacks, others like “Idle” and “Running”, we’d like to be looping. For any animation like this, select the animation name and set the Loop Mode to “Linear”. Do this for all of the “Walking”, “Running”, and “Idle” variations. When you’re done, click the Reimport button at the bottom.

alt -alt

Setting Loop Automatically

If you are making your own characters, you can skip this step by ensuring that your animations’ names end with "-loop". For details on this and other import hints, see Import Hints in the Godot documentation.

Right click knight.glb in the FileSystem and choose New Inherited Scene.

In this scene you’ll see all the models and the AnimationPlayer where you can test out the animations.

Importing World Items

Importing objects for the environment will be a similar process. As an example, let’s use one of the dungeon walls. There are a lot of files in the dungeon pack, so type “wall” in the file filter to help find it:

alt -alt

We’ll want our dungeon walls to be solid, and it would be painful to manually create a StaticBody3D and collision shape for each one. Fortunately, when importing, Godot can do this for us.

In the import window, select the mesh object. On the right side, check the Physics box, and set the Shape Type to “Simple Convex” (feel free to check out the other options too).

alt -alt

Click Reimport. Now when using this in the game, Godot will automatically create a StaticBody3D with a collision shape to match.

Automating Collision Shapes

As above, there is an import hint for collision shapes as well. In your Blender project, appending -col (or some other variations) will let the importer know to do this step automatically. See the import hints link for details.

Automating Imports

While adding import hints is the preferred method when making your own assets, it’s not something you can do when downloading an asset pack like the one we’re using.

It is possible to write an import script that can run on every imported node of a particular type. For example, we could automate the creation of the static collision we did above.

As an example, the following script will loop through all the nodes of the imported object and create a static collision on each mesh it finds.

@tool
+

Importing Assets

Problem

You’ve downloaded (or created) a set of 3D assets, including rigged and animated characters, and you want to import it into Godot.

Solution

For this example, we’ll assume you’ve downloaded the art packs linked in the section description and unzipped them.

Before copying the files into your Godot project, notice that there are multiple versions of the assets in different file formats: OBJ, FBX, and GLTF. There are also some extra files such as examples and separate textures in case you want to modify them. We don’t need all of that, and GLTF is the preferred import format for Godot. So make sure you’re only dragging the gltf folder or .gltf files (or .glb, which is the binary version of the same) into your project folder.

Here, I’ve taken the gltf folder from the “Dungeon” pack and the characters folder from the “Adventurers” pack and dragged them into my project.

Note

There are a lot of files in the Dungeon pack - Godot may take a little time to read them all!

Importing a Character

Select the knight.glb file in the FileSystem tab, then click the Import tab at the top left.

alt +alt

Here you’ll find some basic import settings, but we can go into more detail. Click Advanced button and you’ll see a new window appear:

alt +alt

One the left you’ll see all the data that is contained in the GLTF scene, including textures and animations. Note all the weapon options attached to the character and the extensive list of animations.

There’s a preview of the character in the middle, and a set of options on the right side where you can adjust how the selected item is configured.

Since we will code our player as a CharacterBody3D, we can go ahead and specify that node type here. Click on the Scene Root and on the right set the Root Type to CharacterBody3D.

Animations

Scroll down to the list of animations. You’ll see that there are many, but while some we’ll only want to play once, such as attacks, others like “Idle” and “Running”, we’d like to be looping. For any animation like this, select the animation name and set the Loop Mode to “Linear”. Do this for all of the “Walking”, “Running”, and “Idle” variations. When you’re done, click the Reimport button at the bottom.

alt +alt

Setting Loop Automatically

If you are making your own characters, you can skip this step by ensuring that your animations’ names end with "-loop". For details on this and other import hints, see Import Hints in the Godot documentation.

Right click knight.glb in the FileSystem and choose New Inherited Scene.

In this scene you’ll see all the models and the AnimationPlayer where you can test out the animations.

Importing World Items

Importing objects for the environment will be a similar process. As an example, let’s use one of the dungeon walls. There are a lot of files in the dungeon pack, so type “wall” in the file filter to help find it:

alt +alt

We’ll want our dungeon walls to be solid, and it would be painful to manually create a StaticBody3D and collision shape for each one. Fortunately, when importing, Godot can do this for us.

In the import window, select the mesh object. On the right side, check the Physics box, and set the Shape Type to “Simple Convex” (feel free to check out the other options too).

alt +alt

Click Reimport. Now when using this in the game, Godot will automatically create a StaticBody3D with a collision shape to match.

Automating Collision Shapes

As above, there is an import hint for collision shapes as well. In your Blender project, appending -col (or some other variations) will let the importer know to do this step automatically. See the import hints link for details.

Automating Imports

While adding import hints is the preferred method when making your own assets, it’s not something you can do when downloading an asset pack like the one we’re using.

It is possible to write an import script that can run on every imported node of a particular type. For example, we could automate the creation of the static collision we did above.

As an example, the following script will loop through all the nodes of the imported object and create a static collision on each mesh it finds.

@tool
 extends EditorScenePostImport
 
 func _post_import(scene):
@@ -22,17 +22,17 @@
 

In the Import tab, you can set this as the Import Script, and when you click Reimport, the collisions will be created.

Wrapping up

That concludes the overview of importing 3D assets into Godot.

See the section description for examples of working with the 3D assets you’ve imported.

Companion Video

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/assets/index.html b/docs/4.x/3d/assets/index.html index 7f8f2323..98e070e8 100644 --- a/docs/4.x/3d/assets/index.html +++ b/docs/4.x/3d/assets/index.html @@ -1,19 +1,19 @@ -Working with 3D Assets :: Godot 4 Recipes - +Working with 3D Assets :: Godot 4 Recipes +
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/basic_fps/index.html b/docs/4.x/3d/basic_fps/index.html index 5f769da5..0a08785e 100644 --- a/docs/4.x/3d/basic_fps/index.html +++ b/docs/4.x/3d/basic_fps/index.html @@ -1,5 +1,5 @@ -Basic FPS Character :: Godot 4 Recipes - +Basic FPS Character :: Godot 4 Recipes +

Basic FPS Character

Problem

You need to make a first-person shooter (FPS) character.

Solution

Start with a CharacterBody3D node, and add a CollisionShape3D to it. The CapsuleShape3D collision shape is the most common choice. Depending on your world setup, you may want to add additional shapes here, but for the purposes of this example, we’ll stick to the basics.

We’ll leave all the sizing at the default values, meaning the capsule will be 2 meters high. Move it up by 1.0 m to align its bottom with the ground.

Next, add a Camera3D as a child of the body and move it up about 1.6 m.

Where’s the body?

For this example, we’ll leave the character “bodyless” - meaning we’re not adding a mesh to display for the player’s body. Depending on your setup, you may or may not need to see the player’s body.

Attach a script to the body and start by defining some properties:

extends CharacterBody3D
 
@@ -28,21 +28,21 @@
         rotate_y(-event.relative.x * mouse_sensitivity)
         $Camera3D.rotate_x(-event.relative.y * mouse_sensitivity)
         $Camera3D.rotation.x = clampf($Camera3D.rotation.x, -deg_to_rad(70), deg_to_rad(70))
-

Holding a weapon

alt -alt

An FPS character typically has a 3D mesh of a weapon positioned in front. Setting this up can be easy with a couple of Godot editor tricks.

Add your weapon mesh as a child of the Camera3D. Then, in the editor view menu, choose “2 Viewports” and set one of them to preview the camera. Then, you can move around the weapon and easily see how it will look from the player’s perspective.

To add a little personality, try using an AnimationPlayer to animate the weapon’s position from side-to-side as the player moves.

Download This Project

Download the project code here: https://github.com/godotrecipes/basic_fps

+ + \ No newline at end of file diff --git a/docs/4.x/3d/camera_gimbal/index.html b/docs/4.x/3d/camera_gimbal/index.html index 2ba295fc..45e5c64b 100644 --- a/docs/4.x/3d/camera_gimbal/index.html +++ b/docs/4.x/3d/camera_gimbal/index.html @@ -1,5 +1,5 @@ -Camera Gimbal :: Godot 4 Recipes - +Camera Gimbal :: Godot 4 Recipes +

Camera Gimbal

Problem

You need a camera controller, using mouse or keyboard, that remains level while rotating and following a target.

Solution

Try this: take a Camera3D node and rotate it a small amount around X (the red ring on the gizmo), then a small amount around Z (the blue ring). Now reverse the X rotation and click the “Preview” button. Observe how the camera is now tilted.

The solution to this problem is to place the camera on a gimbal - a device designed to keep an object level during movement. We can create a gimbal using two Node3D nodes, which will control the camera’s left/right and up/down rotation respectively.

The node setup should look like this:

 Node3D: CameraGimbal
      Node3D: InnerGimbal
@@ -60,8 +60,8 @@
 
 func _process(delta):
     scale = lerp(scale, Vector3.ONE * zoom, zoom_speed)
-

Using lerp() to change the zoom level results in smoother zooming.

alt -alt

Following a target

Once you have the camera gimbal set up, it can follow a target by adding the following:

@export var target : Node3D
+

Using lerp() to change the zoom level results in smoother zooming.

alt +alt

Following a target

Once you have the camera gimbal set up, it can follow a target by adding the following:

@export var target : Node3D
 
 func _process(delta):
     if target:
@@ -123,17 +123,17 @@
 
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/characterbody3d_examples/index.html b/docs/4.x/3d/characterbody3d_examples/index.html index e5132183..37ab9b8a 100644 --- a/docs/4.x/3d/characterbody3d_examples/index.html +++ b/docs/4.x/3d/characterbody3d_examples/index.html @@ -1,10 +1,10 @@ -CharacterBody3D: Movement :: Godot 4 Recipes - +CharacterBody3D: Movement :: Godot 4 Recipes +

CharacterBody3D: Movement

Problem

You need a player-controlled 3D character body.

Solution

For this recipe, we’ll be using this adorable tank model:

alt -alt

You can grab this model on Itch.io: https://gtibo.itch.io/mini-tank or use any other model you’d like. We won’t be doing anything that’s tank-specific here.

In the case of this asset, the download includes an OBJ file, and we’ll find it more convenient if we import it as a scene:

alt -alt

We can add the model to the scene, but we’ll need a couple of additional nodes:

alt -alt

For the collision shape, we’re just going to use a BoxShape aligned and sized with the tank’s treads. CamPos is a Position3D we’ll use to place our following camera. It’s placed behind and above the tank, angled down.

We’ve also rotated the individual MeshInstance nodes 180 degrees around the Y axis. This is because they were modeled facing towards +Z, but -Z is the forward direction in Godot, and we don’t want our tank to look like it’s backwards.

Before we add a script, open the “Project Settings” and add the following inputs +

CharacterBody3D: Movement

Problem

You need a player-controlled 3D character body.

Solution

For this recipe, we’ll be using this adorable tank model:

alt +alt

You can grab this model on Itch.io: https://gtibo.itch.io/mini-tank or use any other model you’d like. We won’t be doing anything that’s tank-specific here.

In the case of this asset, the download includes an OBJ file, and we’ll find it more convenient if we import it as a scene:

alt +alt

We can add the model to the scene, but we’ll need a couple of additional nodes:

alt +alt

For the collision shape, we’re just going to use a BoxShape aligned and sized with the tank’s treads. CamPos is a Position3D we’ll use to place our following camera. It’s placed behind and above the tank, angled down.

We’ve also rotated the individual MeshInstance nodes 180 degrees around the Y axis. This is because they were modeled facing towards +Z, but -Z is the forward direction in Godot, and we don’t want our tank to look like it’s backwards.

Before we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:

Input ActionKey
forwardW
backS
rightD
leftA

Now let’s add a script, starting with the required variables:

extends CharacterBody3D
 
 @export var speed = 4.0
@@ -24,17 +24,17 @@
 

Let’s examine this more closely. Player input should affect horizontal movement: forward/back along the ground, and rotation around the tank’s center. Movement in the Y direction should only be affected by gravity, which means we don’t want to set it to 0 every frame. This is why we’re using the vy variable to temporarily hold that value while we assign a new velocity vector for the horizontal movement, then add it back in at the end.

For the forward and back movement, we’re using transform.basis.z so that we’ll move in our body’s local forward direction.

Here’s the tank in action. We’ve made a test scene with a StaticBody3D plane for the ground and an Camera3D using the Interpolated Camera recipe.

Wrapping up

This is the basis of movement for any kind of kinematic character. From here you can add jumping, shooting, AI behavior, etc. See the related recipes for examples that build on this recipe.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/click_to_move/index.html b/docs/4.x/3d/click_to_move/index.html index bfdd5645..4ce870c5 100644 --- a/docs/4.x/3d/click_to_move/index.html +++ b/docs/4.x/3d/click_to_move/index.html @@ -1,9 +1,9 @@ -Click to move :: Godot 4 Recipes - +Click to move :: Godot 4 Recipes +

Click to move

Problem

You want to move a 3D object to a clicked position.

Solution

We’ll start with a flat plane for our world. Our actor will move on this plane.

alt -alt

The actor for this demo is a triangular prism mesh:

alt -alt

Here is the code for the movement. If given a target, the object will turn and move toward it.

extends CharacterBody3D
+

Click to move

Problem

You want to move a 3D object to a clicked position.

Solution

We’ll start with a flat plane for our world. Our actor will move on this plane.

alt +alt

The actor for this demo is a triangular prism mesh:

alt +alt

Here is the code for the movement. If given a target, the object will turn and move toward it.

extends CharacterBody3D
 
 @export var speed = 5
 @export var gravity = -5
@@ -20,26 +20,26 @@
             target = Vector3.ZERO
             velocity = Vector3.ZERO
     move_and_slide()
-

We’ve also added a MeshInstance3D called “Marker” to the scene. This will be moved to indicate the clicked position.

alt -alt

Mouse -> 3D

Now we need a way to map mouse position into our 3D world. If you imagine the screen as a window into the 3D world, the mouse is trapped on the glass. To select something in 3D, we must project a ray from our eye (the camera), through the mouse’s position and into the world.

While this can be done manually using the Camera3D’s project_ray methods, we can take advantage of the fact that CollisionObject3D nodes do this automatically. All we need to do is connect our StaticBody3D ground’s input_event signal:

func _on_StaticBody_input_event(camera, event, click_position, click_normal, shape_idx):
+

We’ve also added a MeshInstance3D called “Marker” to the scene. This will be moved to indicate the clicked position.

alt +alt

Mouse -> 3D

Now we need a way to map mouse position into our 3D world. If you imagine the screen as a window into the 3D world, the mouse is trapped on the glass. To select something in 3D, we must project a ray from our eye (the camera), through the mouse’s position and into the world.

While this can be done manually using the Camera3D’s project_ray methods, we can take advantage of the fact that CollisionObject3D nodes do this automatically. All we need to do is connect our StaticBody3D ground’s input_event signal:

func _on_StaticBody_input_event(camera, event, click_position, click_normal, shape_idx):
     if event is InputEventMouseButton and event.pressed:
         $Marker.transform.origin = click_position
         $Player.target = click_position
-

We set the position of the marker and the Player’s target to the clicked position:

alt -alt

Wrapping up

You can use this technique to detect clicks on any objects in your 3D world.

+ + \ No newline at end of file diff --git a/docs/4.x/3d/healthbars/index.html b/docs/4.x/3d/healthbars/index.html index 6f842f8f..1a37054f 100644 --- a/docs/4.x/3d/healthbars/index.html +++ b/docs/4.x/3d/healthbars/index.html @@ -1,20 +1,20 @@ -3D Unit Healthbars :: Godot 4 Recipes - +3D Unit Healthbars :: Godot 4 Recipes +

3D Unit Healthbars

Problem

You want a floating “healthbar” for your 3D game objects (mobs, characters, etc.).

Solution

For this solution, we’re going to re-use a 2D healthbar based on a TextureProgressBar node. It’s already set up with textures and code for updating the value and color. If you already have something similar, feel free to use it here. In the example, we’ll name this scene “Healthbar2D”.

alt -alt

If you need some assets, here are the three images used in the bar:

alt -alt

alt -alt

alt -alt

Note

Re-using existing objects can save you a lot of time. Don’t re-invent the wheel everytime you need a healthbar, camera, or other common object.

Project setup

For our example “mob”, we’ll start with a CharacterBody3D node. It’s programmed to spawn and travel in a straight line. It also has the following code to handle damage:

func _on_input_event(_camera, event, _position, _normal, _shape_idx):
+

3D Unit Healthbars

Problem

You want a floating “healthbar” for your 3D game objects (mobs, characters, etc.).

Solution

For this solution, we’re going to re-use a 2D healthbar based on a TextureProgressBar node. It’s already set up with textures and code for updating the value and color. If you already have something similar, feel free to use it here. In the example, we’ll name this scene “Healthbar2D”.

alt +alt

If you need some assets, here are the three images used in the bar:

alt +alt

alt +alt

alt +alt

Note

Re-using existing objects can save you a lot of time. Don’t re-invent the wheel everytime you need a healthbar, camera, or other common object.

Project setup

For our example “mob”, we’ll start with a CharacterBody3D node. It’s programmed to spawn and travel in a straight line. It also has the following code to handle damage:

func _on_input_event(_camera, event, _position, _normal, _shape_idx):
     if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
         health -= 1
         if health <= 0:
             queue_free()
-

alt -alt

Clicking on a unit deals one damage. Do ten damage, and the unit is destroyed. Now we need a visual representation of that using our 2D bar.

2D in 3D

We can display a 2D image in 3D using a Sprite3D. Add one to a new scene and name it “Healthbar3D”. First, we’ll get it configured and sized, so set the Texture property to the green bar image.

The Sprite3D acts like any other 3D object - as we pan the camera around, our perspective on it changes. However, we want the healthbar to always “face” toward the camera so that we can see it.

In the Inspector, under Flags, set Billboard to “Enabled”.

Now try moving the camera to confirm that the texture is always facing you.

alt -alt

Add an instance of this scene to the Mob scene and position the bar above the mob’s body.

alt -alt

Viewport texture

We don’t want the Sprite3D to show a static texture - we want it to display the 2D TextureProgressBar. We can do that using a SubViewport node, which can export a texture.

Add a SubViewport as a child of the Sprite3D. In the Inspector set Transparent BG to On.

We also need to set the size of the viewport to match the size of the healthbar texture, which is (200, 26).

Instance the HealthBar2D as a child of the Viewport. Your scene should look like this:

alt -alt

If the SubViewport were not a child of the Sprite3D, we could set it as the sprite’s texture directly in the Inspector. Since it’s a child, it won’t be ready at the right time, so we’ll need to set it in a script attached to the Sprite3D:

extends Sprite3D
+

alt +alt

Clicking on a unit deals one damage. Do ten damage, and the unit is destroyed. Now we need a visual representation of that using our 2D bar.

2D in 3D

We can display a 2D image in 3D using a Sprite3D. Add one to a new scene and name it “Healthbar3D”. First, we’ll get it configured and sized, so set the Texture property to the green bar image.

The Sprite3D acts like any other 3D object - as we pan the camera around, our perspective on it changes. However, we want the healthbar to always “face” toward the camera so that we can see it.

In the Inspector, under Flags, set Billboard to “Enabled”.

Now try moving the camera to confirm that the texture is always facing you.

alt +alt

Add an instance of this scene to the Mob scene and position the bar above the mob’s body.

alt +alt

Viewport texture

We don’t want the Sprite3D to show a static texture - we want it to display the 2D TextureProgressBar. We can do that using a SubViewport node, which can export a texture.

Add a SubViewport as a child of the Sprite3D. In the Inspector set Transparent BG to On.

We also need to set the size of the viewport to match the size of the healthbar texture, which is (200, 26).

Instance the HealthBar2D as a child of the Viewport. Your scene should look like this:

alt +alt

If the SubViewport were not a child of the Sprite3D, we could set it as the sprite’s texture directly in the Inspector. Since it’s a child, it won’t be ready at the right time, so we’ll need to set it in a script attached to the Sprite3D:

extends Sprite3D
 
 func _ready():
     texture = $SubViewport.get_texture()
@@ -30,21 +30,21 @@
         texture_progress = bar_yellow
     if value < 0.45 * _max_value:
         texture_progress = bar_red
-

Click on the mobs to see the health bars change.

alt -alt

Wrapping up

You can use this technique to display any other Node2D or Control nodes, such as Label, VideoStreamPlayer, etc. You can even use the SubViewport to “project” an entire 2D game in 3D space.

Download This Project

Download the project code here: https://github.com/godotrecipes/3d_object_healthbars

+ + \ No newline at end of file diff --git a/docs/4.x/3d/index.html b/docs/4.x/3d/index.html index e8774c5d..abb6afb7 100644 --- a/docs/4.x/3d/index.html +++ b/docs/4.x/3d/index.html @@ -1,19 +1,19 @@ -3D :: Godot 4 Recipes - +3D :: Godot 4 Recipes + - - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/interpolated_camera/index.html b/docs/4.x/3d/interpolated_camera/index.html index 3e0fd90c..d131851e 100644 --- a/docs/4.x/3d/interpolated_camera/index.html +++ b/docs/4.x/3d/interpolated_camera/index.html @@ -1,5 +1,5 @@ -Interpolated Camera :: Godot 4 Recipes - +Interpolated Camera :: Godot 4 Recipes +

Interpolated Camera

Problem

You need a 3D camera that smoothly follows a target (interpolates).

Solution

Info

Godot’s built-in InterpolatedCamera node is deprecated and will be removed in the release of Godot 4.0.

Attach the script below to a Camera3D node in your scene. The three export properties let you choose:

  • lerp_speed - the camera’s movement speed. Lower values result in a “lazier” camera.
  • target - choose the camera’s target node.
  • offset - position of the camera relative to the target.

See below for some examples of the camera in action.

extends Camera3D
 
@@ -18,17 +18,17 @@
 

In the _physics_process() function we interpolate the camera’s position with the target’s (plus offset).

Examples

  • lerp_speed: 3.0
  • offset: (0, 7, 5)

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/rolling_cube/index.html b/docs/4.x/3d/rolling_cube/index.html index 13b3c3c9..4050268f 100644 --- a/docs/4.x/3d/rolling_cube/index.html +++ b/docs/4.x/3d/rolling_cube/index.html @@ -1,15 +1,15 @@ -Rolling Cube :: Godot 4 Recipes - +Rolling Cube :: Godot 4 Recipes +

Rolling Cube

Problem

You want to make a rolling cube in 3D.

Solution

Rolling a cube is trickier than it seems. You can’t just rotate the cube around its center:

alt -alt

Instead, the cube needs to be rotated around its bottom edge.

alt -alt

Here’s the tricky part: which bottom edge? It depends on which direction the cube is rolling.

In preparing this recipe, I experimented with a few different solutions to this problem:

  • Pure math - calculating and applying rotation transforms
  • AnimationPlayer - using animations to key the rotations and offsets
  • Helper nodes - using Spatial(s) as rotation helpers

They all worked fine, but I found the last option the most flexible and easiest to adapt, so that’s what we’ll do here.

Node setup

Cube:  CharacterBody3D
+

Rolling Cube

Problem

You want to make a rolling cube in 3D.

Solution

Rolling a cube is trickier than it seems. You can’t just rotate the cube around its center:

alt +alt

Instead, the cube needs to be rotated around its bottom edge.

alt +alt

Here’s the tricky part: which bottom edge? It depends on which direction the cube is rolling.

In preparing this recipe, I experimented with a few different solutions to this problem:

  • Pure math - calculating and applying rotation transforms
  • AnimationPlayer - using animations to key the rotations and offsets
  • Helper nodes - using Spatial(s) as rotation helpers

They all worked fine, but I found the last option the most flexible and easiest to adapt, so that’s what we’ll do here.

Node setup

Cube:  CharacterBody3D
     Pivot:  Node3D
         Mesh:  MeshInstance3D
     Collision:  CollisionShape3D
-
Tip

You can do this with RigidBody3D, CharacterBody3D, or Area3D as your collision node. There will be minor differences in how you handle movement. Which node you choose should depend on what other behavior you want in your game. For this recipe, we’re only concerned with the movement.

By default, everything is centered at (0, 0, 0) so the first thing we’re going to do is offset everything so that the bottom center of the cube is the CharacterBody3D’s position.

The default size of a BoxMesh3D is (1, 1, 1), so do this, move the mesh and collision nodes both up to (0, 0.5, 0), leaving the rest where they are. Now when you select the root node, its position will be the bottom of the cube:

alt -alt

Now when you want to roll the cube, you’ll need to move the Pivot 0.5 in the direction you want to move. Since the mesh is attached, you need to move it the opposite amount. For example, to roll to the right (+X), you’ll end up with this:

alt -alt

Now the pivot node is at the correct edge and rotating it will also rotate the mesh.

Movement script

The movement is broken in to 3 steps:

Step 1

Here we apply the two offsets shown above: shift the Pivot in the direction of movement, and shift the Mesh in the opposite direction.

Step 2

In this step we animate the rotation. We find the axis of rotation using the cross product of the direction and the down vector. Then we use a Tween to animate rotating the pivot’s transform.

Step 3

Finally, once the animation has finished, we need to reset everything so that it’s ready to happen again. In the end, we want to have the cube moved 1 unit in the chosen direction (for a cube of size 1) and have the pivot and mesh back at their original positions.

extends CharacterBody3D
+
Tip

You can do this with RigidBody3D, CharacterBody3D, or Area3D as your collision node. There will be minor differences in how you handle movement. Which node you choose should depend on what other behavior you want in your game. For this recipe, we’re only concerned with the movement.

By default, everything is centered at (0, 0, 0) so the first thing we’re going to do is offset everything so that the bottom center of the cube is the CharacterBody3D’s position.

The default size of a BoxMesh3D is (1, 1, 1), so do this, move the mesh and collision nodes both up to (0, 0.5, 0), leaving the rest where they are. Now when you select the root node, its position will be the bottom of the cube:

alt +alt

Now when you want to roll the cube, you’ll need to move the Pivot 0.5 in the direction you want to move. Since the mesh is attached, you need to move it the opposite amount. For example, to roll to the right (+X), you’ll end up with this:

alt +alt

Now the pivot node is at the correct edge and rotating it will also rotate the mesh.

Movement script

The movement is broken in to 3 steps:

Step 1

Here we apply the two offsets shown above: shift the Pivot in the direction of movement, and shift the Mesh in the opposite direction.

Step 2

In this step we animate the rotation. We find the axis of rotation using the cross product of the direction and the down vector. Then we use a Tween to animate rotating the pivot’s transform.

Step 3

Finally, once the animation has finished, we need to reset everything so that it’s ready to happen again. In the end, we want to have the cube moved 1 unit in the chosen direction (for a cube of size 1) and have the pivot and mesh back at their original positions.

extends CharacterBody3D
 
 @onready var pivot = $Pivot
 @onready var mesh = $Pivot/MeshInstance3D
@@ -70,17 +70,17 @@
 

Download This Project

Download the project code here: https://github.com/godotrecipes/rolling_cube

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/rotate_interpolate/index.html b/docs/4.x/3d/rotate_interpolate/index.html index e16c2d0c..d75071af 100644 --- a/docs/4.x/3d/rotate_interpolate/index.html +++ b/docs/4.x/3d/rotate_interpolate/index.html @@ -1,31 +1,31 @@ -Smooth rotation :: Godot 4 Recipes - +Smooth rotation :: Godot 4 Recipes +

Smooth rotation

Problem

You want to smoothly rotate a 3D object to point in a new direction.

Solution

When you first encounter this problem, you may find yourself thinking in terms of Euler angles - the three values representing the angles to the x/y/z axes. While Godot will allow you to see the object’s Euler angles in the rotation property, it is not recommended to use them to work in 3D. There are a number of reasons why this the case, such as a problem called “gimbal lock”, where you lose one degree of freedom when one of your rotations reaches 90 degrees.

Info

If you’re interested in the background behind Euler angles and the problems they introduce, like gimbal lock, here’s a video that explains it well.

We can avoid using 3D Euler angles in Godot by using the object’s transform property. This property represents the body’s position and orientation in space. It uses a mathematical construct called a matrix to do this, but you don’t really need to understand the underlying math in order to make use of it.

look_at()

Let’s say you have a 3D object such as a missile or arrow and you want it to point at its target. You can do this using the Node3D method look_at():

func _process(delta):
     var target_position = $Target.transform.origin
     $Arrow.look_at(target_position, Vector3.UP)
-

This code would make our node ($Arrow) always point at the target’s position, no matter how it moves.

alt -alt

Note that look_at() requires 2 parameters: the target position, and an “up vector”. Imagine an airplane pointing its nose towards a target - there are an infinite number of ways it could be oriented, because the plane could roll about its axis. This second parameter is how you define what you want the final orientation to be.

Smooth rotation

The above code works, but it snaps the rotation instantly to the target. This might be fine if you have a very slow-moving target, but looks unnatural. It would look better if we move smoothly, or “interpolated”, the rotation smoothly between the starting orientation and the ending.

Godot has us covered here too. Rather than look_at(), we can use the Transform object’s looking_at() method, which doesn’t rotate the node, but returns the transform that would be looking at the target. Combine this with the interpolate_with() method, which returns an intermediate transform between a current one and a target one, and we can smoothly transition between the current orientation and our desired one.

var speed = 5
+

This code would make our node ($Arrow) always point at the target’s position, no matter how it moves.

alt +alt

Note that look_at() requires 2 parameters: the target position, and an “up vector”. Imagine an airplane pointing its nose towards a target - there are an infinite number of ways it could be oriented, because the plane could roll about its axis. This second parameter is how you define what you want the final orientation to be.

Smooth rotation

The above code works, but it snaps the rotation instantly to the target. This might be fine if you have a very slow-moving target, but looks unnatural. It would look better if we move smoothly, or “interpolated”, the rotation smoothly between the starting orientation and the ending.

Godot has us covered here too. Rather than look_at(), we can use the Transform object’s looking_at() method, which doesn’t rotate the node, but returns the transform that would be looking at the target. Combine this with the interpolate_with() method, which returns an intermediate transform between a current one and a target one, and we can smoothly transition between the current orientation and our desired one.

var speed = 5
 
 func _process(delta):
     var target_position = $Target.transform.origin
     var new_transform = $Arrow.transform.looking_at(target_position, Vector3.UP)
     $Arrow.transform  = $Arrow.transform.interpolate_with(new_transform, speed * delta)
-

alt -alt

Note that since interpolate_with() operates on the transform, it can be used to interpolate both rotation and position of an object.

Wrapping up

That’s it! Use this handy method to rotate your 3D objects, and stop thinking about angles!

+ + \ No newline at end of file diff --git a/docs/4.x/3d/shooting_raycasts/index.html b/docs/4.x/3d/shooting_raycasts/index.html index f6d5a442..c7b80576 100644 --- a/docs/4.x/3d/shooting_raycasts/index.html +++ b/docs/4.x/3d/shooting_raycasts/index.html @@ -1,5 +1,5 @@ -Shooting with Raycasts :: Godot 4 Recipes - +Shooting with Raycasts :: Godot 4 Recipes +

Shooting with Raycasts

Problem

You need to implement shooting in an FPS, but moving individual projectiles is impractical.

Solution

Game physics engines often break down when trying to handle very fast-moving objects. The solution is to cast a ray from the shooter’s location and detect the first thing that would be hit.

There are two ways to approach raycasting in Godot: the RayCast3D node, or directly casting a ray in space using the physics engine. While they can both accomplish the same thing, each has its uses. The node method tends to be best for situations where you continuously want to check for collisions - a downward-facing ray to check if you’re on the floor, for example.

We’ll use the second method, querying the physics state, because we want to know, at the moment we press the “shoot” key, whether we’ve hit anything.

Note

This recipe assumes you already have a working FPS character controller and a world to move around in. If you don’t, see the Basic FPS Character recipe first.

To display what we’ve hit, add a CanvasLayer with a Label node to the FPSPlayer scene.

We’ll add an input check in the _input() function, which we’re already using to handle mouse input.

    if event.is_action_pressed("shoot"):
         shoot()
@@ -15,17 +15,17 @@
 

Download This Project

Download the project code here: https://github.com/godotrecipes/3d_shoot_raycasts

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/3d/spaceship/index.html b/docs/4.x/3d/spaceship/index.html index 92970fdf..94a3c700 100644 --- a/docs/4.x/3d/spaceship/index.html +++ b/docs/4.x/3d/spaceship/index.html @@ -1,8 +1,8 @@ -Arcade-style Spaceship :: Godot 4 Recipes - +Arcade-style Spaceship :: Godot 4 Recipes +

Arcade-style Spaceship

Problem

You want to make a 3D spaceship that flies in an arcade/cinematic way. You’re not looking for realistic physics, but more of a dog-fighting, “Star Wars”-style of spaceflight.

Solution

To accomplish this, we’ll use a CharacterBody3D for the ship. The three axis inputs (pitch, roll, and yaw) will rotate the body’s basis around the corresponding axis. The direction of motion will always point forward.

Note

You can do this with RigidBody3D and get the same results. See the example project linked below, which includes a rigid body version as well.

Assets

Spaceship models are from this asset pack:

Ultimate Spaceships Pack by Quaternius

I’ve chosen the “Executioner” ship model:

alt -alt

Feel free to choose your favorite design.

Setup

Select the gltf file of the ship you want, and click the Import tab. Change the Root Type to CharacterBody3D and click “Reimport”. Then double-click the gltf and you’ll have a new inherited scene with a CharacterBody3D root and a MeshInstance child. Add a CollisionShape3D to the body.

In Project Settings -> Input Map, set up the following inputs:

  • roll_right / roll_left
  • pitch_up / pitch_down
  • yaw_right / yaw_left
  • throttle_up / throttle_down

You can assign keys or controller inputs. Analog stick inputs will work best.

Movement

To start the script, let’s handle the forward movement. Pressing the throttle buttons smoothly increases/decreases the speed.

extends CharacterBody
+

Arcade-style Spaceship

Problem

You want to make a 3D spaceship that flies in an arcade/cinematic way. You’re not looking for realistic physics, but more of a dog-fighting, “Star Wars”-style of spaceflight.

Solution

To accomplish this, we’ll use a CharacterBody3D for the ship. The three axis inputs (pitch, roll, and yaw) will rotate the body’s basis around the corresponding axis. The direction of motion will always point forward.

Note

You can do this with RigidBody3D and get the same results. See the example project linked below, which includes a rigid body version as well.

Assets

Spaceship models are from this asset pack:

Ultimate Spaceships Pack by Quaternius

I’ve chosen the “Executioner” ship model:

alt +alt

Feel free to choose your favorite design.

Setup

Select the gltf file of the ship you want, and click the Import tab. Change the Root Type to CharacterBody3D and click “Reimport”. Then double-click the gltf and you’ll have a new inherited scene with a CharacterBody3D root and a MeshInstance child. Add a CollisionShape3D to the body.

In Project Settings -> Input Map, set up the following inputs:

  • roll_right / roll_left
  • pitch_up / pitch_down
  • yaw_right / yaw_left
  • throttle_up / throttle_down

You can assign keys or controller inputs. Analog stick inputs will work best.

Movement

To start the script, let’s handle the forward movement. Pressing the throttle buttons smoothly increases/decreases the speed.

extends CharacterBody
 
 @export var max_speed = 50.0
 @export var acceleration = 0.6
@@ -19,8 +19,8 @@
     get_input(delta)
     velocity = -transform.basis.z * forward_speed
     move_and_collide(velocity * delta)
-

Make a test scene with a Camera3D to try it out. You can use a stationary camera or a chase camera. Check that the ship accelerates and slows before moving on to the next step.

alt -alt

Rotation

Now we can handle rotation in the three axes. Add the following variables at the top of the script:

@export var pitch_speed = 1.5
+

Make a test scene with a Camera3D to try it out. You can use a stationary camera or a chase camera. Check that the ship accelerates and slows before moving on to the next step.

alt +alt

Rotation

Now we can handle rotation in the three axes. Add the following variables at the top of the script:

@export var pitch_speed = 1.5
 @export var roll_speed = 1.9
 @export var yaw_speed = 1.25
 
@@ -37,16 +37,16 @@
 transform.basis = transform.basis.rotated(transform.basis.y,
     yaw_input * yaw_speed * delta)
 transform.basis = transform.basis.orthonormalized()
-

alt -alt

Improvements

Currently the rotations are a little to “sharp”. The ship starts and stops rotating instantly, which feels a bit too unnatural. We can solve this with lerp(), and by adding one more configuration variable to set how “floaty” we’d like the controls to be:

@export var input_response = 8.0
+

alt +alt

Improvements

Currently the rotations are a little to “sharp”. The ship starts and stops rotating instantly, which feels a bit too unnatural. We can solve this with lerp(), and by adding one more configuration variable to set how “floaty” we’d like the controls to be:

@export var input_response = 8.0
 

Change the three axis inputs in get_input() to the following:

pitch_input = lerp(pitch_input, Input.get_axis("pitch_down", "pitch_up"),
         input_response * delta)
 roll_input = lerp(roll_input, Input.get_axis("roll_right", "roll_left"),
         input_response * delta)
 yaw_input = lerp(yaw_input, Input.get_axis("yaw_right", "yaw_left"),
         input_response * delta)
-

Now when stopping or changing direction, there’s a little bit of inertia.

alt -alt

Linking roll/yaw

One problem with this control scheme is that it’s awkward. Having to use a separate stick for the yaw input makes it difficult to control, especially when also shooting and using other controls. Many games solve this by linking the roll input to also apply a small amount of yaw. To do this, change the yaw_speed to around 1/4 to 1/2 of the roll_speed.

In the get_input() function, change the line getting yaw_input to the following:

yaw_input = roll_input
+

Now when stopping or changing direction, there’s a little bit of inertia.

alt +alt

Linking roll/yaw

One problem with this control scheme is that it’s awkward. Having to use a separate stick for the yaw input makes it difficult to control, especially when also shooting and using other controls. Many games solve this by linking the roll input to also apply a small amount of yaw. To do this, change the yaw_speed to around 1/4 to 1/2 of the roll_speed.

In the get_input() function, change the line getting yaw_input to the following:

yaw_input = roll_input
 

This is another fun place to experiment by changing the roll and yaw speeds. For example, what if yaw was primary and roll smaller? What if other axes were linked? If your game has different ships, you can give them different values for variety in flight styles/performance.

Wrapping up

That’s it, now you can fly! This controller is a great start for whatever space-based game you might have in mind. Add some other ships, and a few effects, and you’re ready go:

Full script

Here’s the complete script:

extends CharacterBody3D
 
 @export var max_speed = 50.0
@@ -89,17 +89,17 @@
 

Download This Project

Download the project code here: https://github.com/godotrecipes/3d_spaceship

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/404.html b/docs/4.x/404.html index b75ea251..f04dd058 100644 --- a/docs/4.x/404.html +++ b/docs/4.x/404.html @@ -1,3 +1,3 @@ -404 Page not found :: Godot 4 Recipes - +404 Page not found :: Godot 4 Recipes +

Error

Woops. Looks like this page doesn't exist ¯\_(ツ)_/¯.

Go to homepage

Page not found!

\ No newline at end of file diff --git a/docs/4.x/ai/chasing/index.html b/docs/4.x/ai/chasing/index.html index dc56bbb7..45cd5401 100644 --- a/docs/4.x/ai/chasing/index.html +++ b/docs/4.x/ai/chasing/index.html @@ -1,10 +1,10 @@ -Chasing the player :: Godot 4 Recipes - +Chasing the player :: Godot 4 Recipes +

Chasing the player

Problem

You want an enemy to chase the player.

Solution

The first step in getting an enemy to chase the player is to determine what direction the enemy needs to move. To get the vector pointing from A to B, you subtract: B - A. Normalize the result and you have a direction vector.

This makes the solution quite straightforward. Every frame, set the enemy’s velocity to point in the direction of the player.

velocity = (player.position - position).normalized() * speed
 

Godot’s Vector2 object has a built-in helper for this:

velocity = position.direction_to(player.position) * speed
-

However, this would allow the enemy to chase the player from any distance, even if it’s far away. To fix this, we can add an Area2D to the enemy, and only chase the player when it’s inside this “detect radius”.

alt -alt

Here’s some example code:

extends CharacterBody2D
+

However, this would allow the enemy to chase the player from any distance, even if it’s far away. To fix this, we can add an Area2D to the enemy, and only chase the player when it’s inside this “detect radius”.

alt +alt

Here’s some example code:

extends CharacterBody2D
 
 var run_speed = 25
 var player = null
@@ -23,17 +23,17 @@
 

We’ve connected the body_entered and body_exited signals from the Area2D so that the enemy knows whether it’s in range or not.

Note

The above assumes that the player is the only body that will enter/exit, which is usually done by setting the appropriate collision layers/masks.

This concept can be extended to other types of games as well. The key is to find the direction vector from the enemy to the player:

If, for example, your game is a side-scroller or has other constraints in movement, you can use only the x component of the resulting vector to determine movement.

Limitations

Note that this method results in very simplistic straight-line movement. The enemy will not move around obstacles such as walls, nor will it stop if it gets too close to the player.

What to do when the enemy gets close to the player depends on your game. You could add a second, smaller area that causes the enemy to stop and attack, or you could knockback the player on contact.

Another problem is more apparent with fast-moving enemies. As the player moves, the enemies using this technique will change direction instantly. For a more natural-looking movement, you might want to use a steering behavior.

For more advanced behaviors, see the other recipes in this chapter.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/ai/homing_missile/index.html b/docs/4.x/ai/homing_missile/index.html index fa384342..b2f7e0e0 100644 --- a/docs/4.x/ai/homing_missile/index.html +++ b/docs/4.x/ai/homing_missile/index.html @@ -1,12 +1,12 @@ -Homing missile :: Godot 4 Recipes - +Homing missile :: Godot 4 Recipes +

Homing missile

Problem

You need a “homing missile” - a projectile that will seek a moving target.

Solution

For this example, we’ll use an Area2D node for the projectile. Areas are typically good choices for bullets because we need to detect when they contact something. If you also need a bullet that bounces/ricochets, one of the PhysicsBody type node might be a better choice.

The node setup and behavior of the missile is the same you would use for a “dumb” bullet. If you’re creating many bullet types, you can use inheritance to base all your projectiles on the same core setup.

The nodes we’ll use:

 Area2D: Missile
      Sprite2D
      CollisionShape2D
      Timer: Lifetime
-

For the texture, you can use any image you like. Here’s an example one:

alt -alt

Set up the nodes and configure the sprite’s texture and the collision shape. Make sure to rotate the Sprite2D node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.

Add a script and connect the Area2D’s body_entered signal and the Timer’s timeout signal.

Here’s the starting script:

extends Area2D
+

For the texture, you can use any image you like. Here’s an example one:

alt +alt

Set up the nodes and configure the sprite’s texture and the collision shape. Make sure to rotate the Sprite2D node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.

Add a script and connect the Area2D’s body_entered signal and the Timer’s timeout signal.

Here’s the starting script:

extends Area2D
 
 export var speed = 350
 
@@ -36,8 +36,8 @@
 func start(_transform, _target):
     target = _target
     ...
-

To change the missile’s direction to move toward the target, it needs to accelerate in that direction (acceleration is change in velocity). The missile “wants” to move straight towards the target, but its current velocity is pointing in a different direction. Using a little vector math, we can find that difference:

alt -alt

The green arrow represents the needed change in velocity (i.e. acceleration). However, if we turn instantly, that will look unnatural, so the “steering” vector’s length needs to be limited. This is the purpose of the steer_force variable.

This is the function to calculate that acceleration. Note that if there’s no target, there will be no steering, so the missile remains traveling in a straight line.

func seek():
+

To change the missile’s direction to move toward the target, it needs to accelerate in that direction (acceleration is change in velocity). The missile “wants” to move straight towards the target, but its current velocity is pointing in a different direction. Using a little vector math, we can find that difference:

alt +alt

The green arrow represents the needed change in velocity (i.e. acceleration). However, if we turn instantly, that will look unnatural, so the “steering” vector’s length needs to be limited. This is the purpose of the steer_force variable.

This is the function to calculate that acceleration. Note that if there’s no target, there will be no steering, so the missile remains traveling in a straight line.

func seek():
     var steer = Vector2.ZERO
     if target:
         var desired = (target.position - position).normalized() * speed
@@ -93,17 +93,17 @@
 
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/ai/index.html b/docs/4.x/ai/index.html index 04f13969..e5510d80 100644 --- a/docs/4.x/ai/index.html +++ b/docs/4.x/ai/index.html @@ -1,19 +1,19 @@ -AI/Behavior :: Godot 4 Recipes - +AI/Behavior :: Godot 4 Recipes +
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/ai/pet_following/index.html b/docs/4.x/ai/pet_following/index.html index c4b7a29c..5db3de11 100644 --- a/docs/4.x/ai/pet_following/index.html +++ b/docs/4.x/ai/pet_following/index.html @@ -1,8 +1,8 @@ -Pet Following :: Godot 4 Recipes - +Pet Following :: Godot 4 Recipes +

Pet Following

Problem

You need to have a game entity such as a pet or minion, follow a character.

Solution

We start by adding a Marker2D to the character. This will represent the place where the pet wants to “hang out” near the character.

alt -alt

In this example, we’ve made it a child of the Sprite2D, because the character’s code uses $Sprite2D.scale.x = -1 to flip the horizontal direction when the character moves left. Since the marker is a child of the sprite, it will flip too.

Pet script

Here’s the script for the pet.

extends CharacterBody2D
+

Pet Following

Problem

You need to have a game entity such as a pet or minion, follow a character.

Solution

We start by adding a Marker2D to the character. This will represent the place where the pet wants to “hang out” near the character.

alt +alt

In this example, we’ve made it a child of the Sprite2D, because the character’s code uses $Sprite2D.scale.x = -1 to flip the horizontal direction when the character moves left. Since the marker is a child of the sprite, it will flip too.

Pet script

Here’s the script for the pet.

extends CharacterBody2D
 
 @export var parent : CharacterBody2D
 
@@ -27,17 +27,17 @@
 

If it’s close to the target point, we stop the pet’s movement.

Depending on your world, you may find the pet gets stuck on obstacles. For more robust following, you can use navigation. See TileMap Navigation for an example.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/animation/index.html b/docs/4.x/animation/index.html index 802dbff1..848d8227 100644 --- a/docs/4.x/animation/index.html +++ b/docs/4.x/animation/index.html @@ -1,19 +1,19 @@ -Animation :: Godot 4 Recipes - +Animation :: Godot 4 Recipes +
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/animation/spritesheet_animation/index.html b/docs/4.x/animation/spritesheet_animation/index.html index 918f3315..92a3a3ea 100644 --- a/docs/4.x/animation/spritesheet_animation/index.html +++ b/docs/4.x/animation/spritesheet_animation/index.html @@ -1,30 +1,30 @@ -Spritesheet animation :: Godot 4 Recipes - +Spritesheet animation :: Godot 4 Recipes +

Spritesheet animation

Problem

You want to use a spritesheet containing 2D animations.

Solution

Spritesheets are a common way for 2D animations to be distributed. In a spritesheet, all of the animation frames are packed into a single image.

For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art athttps://elthen.itch.io/.

alt -alt

Warning

Make sure the images in your spritesheet are laid out in a constant-sized grid. This will enable Godot to automatically slice them. If they’re packed irregularly, you will not be able to use the following technique.

Node setup

This animation technique uses a Sprite2D node to display the texture, and then we animate the changing frames with AnimationPlayer. This can work with any 2D node, but for this demo, we’ll use a CharacterBody2D.

Add the following nodes to your scene:

CharacterBody2D: Player
+

Spritesheet animation

Problem

You want to use a spritesheet containing 2D animations.

Solution

Spritesheets are a common way for 2D animations to be distributed. In a spritesheet, all of the animation frames are packed into a single image.

For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art athttps://elthen.itch.io/.

alt +alt

Warning

Make sure the images in your spritesheet are laid out in a constant-sized grid. This will enable Godot to automatically slice them. If they’re packed irregularly, you will not be able to use the following technique.

Node setup

This animation technique uses a Sprite2D node to display the texture, and then we animate the changing frames with AnimationPlayer. This can work with any 2D node, but for this demo, we’ll use a CharacterBody2D.

Add the following nodes to your scene:

CharacterBody2D: Player
    Sprite2D
    CollisionShape2D
    AnimationPlayer
-

Drag the spritesheet texture into the Texture property of the Sprite2D. You’ll see the entire spritesheet displayed in the viewport. To slice it up into individual frames, expand the “Animation” section in the Inspector and set the Hframes to 13 and Vframes to 8. Hframes and Vframes are the number of horizontal and vertical frames in your spritesheet.

alt -alt

Try changing the Frame property to see the image change. This is the property we’ll be animating.

Adding animations

Select the AnimationPlayer and click the “Animation” button followed by “New" -. Name the new animation “idle”. Set the animation length to 2 and click the “Loop” button so that our animation will repeat (see below).

With the scrubber at time 0, select the Sprite2D node. Set its Animation/Frame to 0, then click the key icon next to the value.

alt -alt

If you try playing the animation, you’ll see it doesn’t appear to do anything. That’s because the last frame (12) looks the same as the first (0), but we’re not seeing any of the frames in-between (1-11). To fix this, change the “Update Mode” of the track from its default value of “Discrete” to “Continuous”. You can find this button at the end of the track on the right side.

alt -alt

Note that this will only work for spritesheets where the frames are already in order. If they are not, you’ll have to keyframe each Frame seperately along the timeline.

alt -alt

Feel free to add the other animations yourself. For example, the “jump” animation is on frames 65 through 70.

+ + \ No newline at end of file diff --git a/docs/4.x/animation/using_animation_sm/index.html b/docs/4.x/animation/using_animation_sm/index.html index 1de8a80a..3885dd09 100644 --- a/docs/4.x/animation/using_animation_sm/index.html +++ b/docs/4.x/animation/using_animation_sm/index.html @@ -1,13 +1,13 @@ -Using the AnimationTree StateMachine :: Godot 4 Recipes - +Using the AnimationTree StateMachine :: Godot 4 Recipes +

Using the AnimationTree StateMachine

Problem

A common situation: you have a large number of animations, and it’s becoming difficult to manage transitions between them. Your code has become full of if statements, and every time you change something, it all breaks.

Solution

Use an AnimationTree to create an animation state machine. This will allow us to organize our animations and most importantly, control the transitions between them.

Getting started

For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art at https://elthen.itch.io/.

alt -alt

We’ll also assume you’ve already set up the character’s animations using AnimationPlayer. Using the above spritesheet, we have the following animations: “idle”, “run”, “attack1”, “attack2”, “hurt”, and “die”.

AnimationTree

Add an AnimationTree node to the scene. In its Tree Root property, choose “New AnimationNodeStateMachine”.

alt -alt

An AnimationTree is a node that controls animations created in AnimationPlayer. To let it access the existing animations, click “Assign” in the Anim Player property and select your animation node.

Now we can begin to set up our state machine in the AnimationTree panel:

alt -alt

Note the warning. Set the Active property to “On” in the Inspector.

Right-click and choose “Add Animation”. Choose “idle”, and you’ll see a small box representing that animation. Press its “Play” button and you should see the animation play. Do the same to add boxes for the other animations.

Now we can add connections. Click the “Connect nodes” button and drag between nodes to connect them. As an example, let’s use the two attack animations:

alt -alt

When you select an animation, the tree will follow the connected path from the current node to the destination. However, in the configuration above, if you play “attack2” you won’t see “attack1” along the way. That’s because the default “switch mode” for a connection is “Immediate”. Click the “Move/select” button and then click on the connection between “attack1” and “attack2”. In the Inspector, change Switch Mode to “At End”. Do the same with “attack2” to “idle”. The connection icon changes from to .

Now, with “idle” playing, if you click “attack2”, you’ll see the two attacks play in sequence.

But now the animation stops on “attack2”. On its connection, set the Advance/Mode property to “Auto”. This will make the tree go back to “idle” after playing both animations. Note that the connection icon turns green to show this.

alt -alt

Now the animations are played in sequence whenever they’re triggered.

Calling states in code

Here is the full tree for all of the animations:

alt -alt

Now let’s set up the character to use these animations in a script.

extends CharacterBody2D
+

Using the AnimationTree StateMachine

Problem

A common situation: you have a large number of animations, and it’s becoming difficult to manage transitions between them. Your code has become full of if statements, and every time you change something, it all breaks.

Solution

Use an AnimationTree to create an animation state machine. This will allow us to organize our animations and most importantly, control the transitions between them.

Getting started

For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art at https://elthen.itch.io/.

alt +alt

We’ll also assume you’ve already set up the character’s animations using AnimationPlayer. Using the above spritesheet, we have the following animations: “idle”, “run”, “attack1”, “attack2”, “hurt”, and “die”.

AnimationTree

Add an AnimationTree node to the scene. In its Tree Root property, choose “New AnimationNodeStateMachine”.

alt +alt

An AnimationTree is a node that controls animations created in AnimationPlayer. To let it access the existing animations, click “Assign” in the Anim Player property and select your animation node.

Now we can begin to set up our state machine in the AnimationTree panel:

alt +alt

Note the warning. Set the Active property to “On” in the Inspector.

Right-click and choose “Add Animation”. Choose “idle”, and you’ll see a small box representing that animation. Press its “Play” button and you should see the animation play. Do the same to add boxes for the other animations.

Now we can add connections. Click the “Connect nodes” button and drag between nodes to connect them. As an example, let’s use the two attack animations:

alt +alt

When you select an animation, the tree will follow the connected path from the current node to the destination. However, in the configuration above, if you play “attack2” you won’t see “attack1” along the way. That’s because the default “switch mode” for a connection is “Immediate”. Click the “Move/select” button and then click on the connection between “attack1” and “attack2”. In the Inspector, change Switch Mode to “At End”. Do the same with “attack2” to “idle”. The connection icon changes from to .

Now, with “idle” playing, if you click “attack2”, you’ll see the two attacks play in sequence.

But now the animation stops on “attack2”. On its connection, set the Advance/Mode property to “Auto”. This will make the tree go back to “idle” after playing both animations. Note that the connection icon turns green to show this.

alt +alt

Now the animations are played in sequence whenever they’re triggered.

Calling states in code

Here is the full tree for all of the animations:

alt +alt

Now let’s set up the character to use these animations in a script.

extends CharacterBody2D
 
 var state_machine
 var run_speed = 80.0
@@ -35,21 +35,21 @@
     else:
         state_machine.travel("idle")
     move_and_slide()
-

Note that we’re using return after traveling to the attack animations. This is so that we won’t instead travel to the “run” or “idle” animations further down in the function.

alt -alt

You can use the AnimationTreeStateMachine to handle

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos

+ + \ No newline at end of file diff --git a/docs/4.x/audio/audio_manager/index.html b/docs/4.x/audio/audio_manager/index.html index 0fa7fc0d..0c79ca25 100644 --- a/docs/4.x/audio/audio_manager/index.html +++ b/docs/4.x/audio/audio_manager/index.html @@ -1,5 +1,5 @@ -Audio Manager :: Godot 4 Recipes - +Audio Manager :: Godot 4 Recipes +

Audio Manager

Problem

You’ve tried adding an AudioStreamPlayer to your mob/coin/etc. to play when the object dies or is collected. But the problem is that when you remove the object, the audio player goes with it, chopping off the sound. You need an easier way to manage playing audio.

Solution

We’ll solve this problem with a node that is available from anywhere in the SceneTree. This node manages a set of AudioStreamPlayer nodes and a queue of sound streams to play.

Create a new script in the script editor.

extends Node
 
@@ -35,24 +35,24 @@
         available[0].stream = load(queue.pop_front())
         available[0].play()
         available.pop_front()
-

Set this script as an autoload in Project Settings. Give it an easily recognizable name, such as “AudioStreamManager”.

alt -alt

Anywhere in your project that you want to play a sound, use:

AudioStreamManager.play("res://path/to/sound")
+

Set this script as an autoload in Project Settings. Give it an easily recognizable name, such as “AudioStreamManager”.

alt +alt

Anywhere in your project that you want to play a sound, use:

AudioStreamManager.play("res://path/to/sound")
 
Note

This audio manager is adapted with thanks from [SFXPlayer by TheDuriel] -(https://github.com/TheDuriel/DurielsGodotUtilities).

Example project

Below you can download an example project showing the use of the audio manager node. This project reads a folder full of audio files and generates a grid of buttons. Click the button to play the sound.

alt -alt

At the top, you can see the audio manager’s live statistics.

Download This Project

Download the project’s example code here: https://github.com/godotrecipes/audio_manager

+ + \ No newline at end of file diff --git a/docs/4.x/audio/index.html b/docs/4.x/audio/index.html index e12e8154..43ee8fa7 100644 --- a/docs/4.x/audio/index.html +++ b/docs/4.x/audio/index.html @@ -1,19 +1,19 @@ -Audio :: Godot 4 Recipes - +Audio :: Godot 4 Recipes +

 Audio

Helpful recipes for adding sound effects and music to your game.

In this section:

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/file_io/index.html b/docs/4.x/basics/file_io/index.html index 312a29d9..b1158a5a 100644 --- a/docs/4.x/basics/file_io/index.html +++ b/docs/4.x/basics/file_io/index.html @@ -1,5 +1,5 @@ -Saving/loading data :: Godot 4 Recipes - +Saving/loading data :: Godot 4 Recipes +

Saving/loading data

Problem

You need to save and load local data between game sessions.

Solution

Godot’s file I/O (input/output) system is based around the FileAccess object. You open a file by calling open().

var file = FileAccess.open("user://myfile.name", File.READ)
 
Warning

User data should only be stored in the user:// path. While res:// can be used when running from the editor, when your project is exported, the res:// path becomes read-only.

The second argument after the file path is the “Mode Flag”, which can be one of the following:

  • FileAccess.READ - Open for reading.
  • FileAccess.WRITE - Open for writing. Creates the file if it doesn’t exist and truncates if it does.
  • FileAccess.READ_WRITE - Open for reading and writing. Doesn’t truncate the file.
  • FileAccess.WRITE_READ - Open for reading/writing. Creates the file if it doesn’t exist and truncates if it does.

Storing data

You can save data using its specific data type (store_float(), store_string(), etc.), or using the generic store_var(), which will use Godot’s built-in serialization to encode your data, including complex data like objects (more on this later).

Let’s start with a small example: saving the player’s high score. We can write a function that we can call whenever the score needs to be saved:

var save_path = "user://score.save"
@@ -34,17 +34,17 @@
 

Resources can contain subresources, so you could have your player’s inventory Resource included as well, and so on.

What about JSON?

I see it very often (and some readers may be asking it already): “What if I want to use JSON to save my data?” This is my response:

Don’t use JSON for your save files!

While Godot has JSON support, saving game data is not what JSON is for. JSON is a data interchange format - its purpose is to allow systems using different data formats and/or languages to exchange data between each other.

This means JSON has limitations that are negatives for you when it comes to saving your game data. JSON doesn’t support many data types (no int vs. float, for example) so you have to do a lot of converting and validating to try and save/load your data. It’s cumbersome and time consuming.

Don’t waste your time. Using Godot’s built-in serialization, you can store native Godot objects - Nodes, Resources, even Scenes - without any effort, which means less code and fewer errors.

There’s a reason that Godot itself doesn’t use JSON for saving scenes and resources.

Wrapping up

This article just scratches the surface of what you can do with FileAccess. For the full list of available FileAccess methods, see the FileAccess documentation.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/getting_nodes/index.html b/docs/4.x/basics/getting_nodes/index.html index 576c999a..c323b955 100644 --- a/docs/4.x/basics/getting_nodes/index.html +++ b/docs/4.x/basics/getting_nodes/index.html @@ -1,11 +1,11 @@ -Understanding node paths :: Godot 4 Recipes - +Understanding node paths :: Godot 4 Recipes +

Understanding node paths

Problem

It’s probably the most common problem seen in the Godot help channels: an invalid node reference. Most often, it appears as the following error message:

Invalid get index ‘position’ (on base: ’null instance’).

Solution

It’s that last part, the “null instance”, that’s the source of this problem, and the main source of confusion for Godot beginners.

The way to avoid this problem is to understand the concept of node paths.

Understanding node paths

The scene tree is made of nodes, which are connected together in parent-child relationships. A node path is the path it takes to get from one node to another by moving through this tree.

As an example, let’s take a simple “Player” scene:

alt -alt

The script for this scene is on the Player node. If the script needs to call play() on the AnimatedSprite node, it needs a reference to that node:

get_node("AnimatedSprite").play()
+

Understanding node paths

Problem

It’s probably the most common problem seen in the Godot help channels: an invalid node reference. Most often, it appears as the following error message:

Invalid get index ‘position’ (on base: ’null instance’).

Solution

It’s that last part, the “null instance”, that’s the source of this problem, and the main source of confusion for Godot beginners.

The way to avoid this problem is to understand the concept of node paths.

Understanding node paths

The scene tree is made of nodes, which are connected together in parent-child relationships. A node path is the path it takes to get from one node to another by moving through this tree.

As an example, let’s take a simple “Player” scene:

alt +alt

The script for this scene is on the Player node. If the script needs to call play() on the AnimatedSprite node, it needs a reference to that node:

get_node("AnimatedSprite").play()
 

The argument of the get_node() function is a string representing the path to the desired node. In this case, it’s a child of the node the script is on. If the path you give it is invalid, you’ll get the dreaded null instance error (as well as “Node not found”).

Getting a node reference with get_node() is such a common situation that GDScript has a shortcut for it:

$AnimatedSprite.play()
-
Info

get_node() returns a reference to the desired node.

Let’s look at a more complex scene tree:

alt -alt

If the script on Main needs to access ScoreLabel it can do so with this path:

get_node("HUD/ScoreLabel").text = "0"
+
Info

get_node() returns a reference to the desired node.

Let’s look at a more complex scene tree:

alt +alt

If the script on Main needs to access ScoreLabel it can do so with this path:

get_node("HUD/ScoreLabel").text = "0"
 # or using the shortcut:
 $HUD/ScoreLabel.text = "0"
 
Tip

When using $ notation, the Godot editor will autocomplete paths for you. You can also right-click on a node in the Scene tab and choose “Copy Node Path”.

What if the node you want to access is higher in the tree? You can use get_parent() or ".." to reference the parent node. In the above example tree, to get the Player node from the ScoreLabel:

get_node("../../Player")
@@ -16,17 +16,17 @@
 

While this may work fine at first, it is brittle, meaning it can break easily. There are two main problems with this kind of arrangement:

  1. You can’t test the player scene independently. If you run the player scene by itself or in a test scene that doesn’t have a UI, the get_node() line will cause a crash.
  2. You can’t change your UI. If you decide to rearrange or redesign your UI, the path will no longer be valid and you have to change it.

For this reason, you should try to avoid using node paths that go up the scene tree. In the above situation, if the player instead emitted a signal when the health changed, the UI could listen for that signal to update itself. You could then rearrange and separate nodes without fear of breaking your game.

Wrapping up

Once you understand how to use node paths, you’ll see how easy it is to reference any node you need. And put a stop to seeing those null instance error messages.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/index.html b/docs/4.x/basics/index.html index 45c16398..dcfa3e92 100644 --- a/docs/4.x/basics/index.html +++ b/docs/4.x/basics/index.html @@ -1,19 +1,19 @@ -Basics :: Godot 4 Recipes - +Basics :: Godot 4 Recipes + - - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/migrating/index.html b/docs/4.x/basics/migrating/index.html index d6e4157f..02cef4a3 100644 --- a/docs/4.x/basics/migrating/index.html +++ b/docs/4.x/basics/migrating/index.html @@ -1,5 +1,5 @@ -Migrating from 3.x :: Godot 4 Recipes - +Migrating from 3.x :: Godot 4 Recipes +

Migrating from 3.x

This is an evolving list of the main changes and “gotchas” to look out for if you’re transitioning to 4.0.

New Names

One of the biggest changes in Godot 4 is a whole bunch of renaming - of nodes, functions, and property names. Most of it is done to make things consistent or clear. Here are a few of the biggest ones to watch out for:

  • 2D/3D nodes - In Godot 3.x, 2D nodes had the “2D” suffix, but 3D nodes had none. This has been made consistent - they all now have “2D” or “3D” suffixes. For example: RigidBody2D vs. RigidBody3D.

  • Also in the category of 3D, the Spatial node is renamed to Node3D to match.

  • One of the most popular nodes, KinematicBody, has been renamed to CharacterBody2D/CharacterBody3D. See below for further changes with this node’s API.

  • PackedScene’s instance() function has been renamed to instantiate().

  • The position and global_position properties replace translation and global_translation in 3D, making them consistent with 2D.

Signals and Callables

Working with signals is much more streamlined in 4.0. Signal is a native type now, so you’ll be using fewer strings, meaning you get autocomplete and error checking. This applies to functions as well, which can now be directly referenced rather than using strings.

Here’s an example of defining, connecting, and emitting a signal.

extends Node
 
@@ -22,17 +22,17 @@
 
- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/node_communication/index.html b/docs/4.x/basics/node_communication/index.html index a8d33e54..6355cbe4 100644 --- a/docs/4.x/basics/node_communication/index.html +++ b/docs/4.x/basics/node_communication/index.html @@ -1,32 +1,32 @@ -Node communication (the right way) :: Godot 4 Recipes - +Node communication (the right way) :: Godot 4 Recipes +

Node communication (the right way)

Info

Many thanks to @TheDuriel on the Godot Discord for the original diagram that inspired this article. Save this and keep it handy.

Problem

Your project has started getting complex. You have multiple scenes, instances, and a lot of nodes. You’ve probably found yourself writing code like the following:

get_node("../../SomeNode/SomeOtherNode")
 get_parent().get_parent().get_node("SomeNode")
 get_tree().get_root().get_node("SomeNode/SomeOtherNode")
-

If you do this, you’ll soon find that node references like this break easily. As soon as you change one thing about your scene tree, none of those references may be valid anymore.

Communication between nodes and scenes doesn’t have to be complicated. There is a better way.

Solution

As a general rule, nodes should manage their children, not the other way around. If you’re using get_parent() or get_node(".."), then you’re probably headed for trouble. Node paths like this are brittle, meaning they can break easily. The three main problems with this arrangement:

  1. You can’t test a scene independently. If you run the scene by itself or in a test scene that doesn’t have the exact same node setup, get_node() will cause a crash.

  2. You can’t change things easily. If you decide to rearrange or redesign your tree, paths will no longer be valid.

  3. Ready order is children-first, parent-last. This means that trying to access a parent’s property in a node’s _ready() can fail because the parent isn’t ready yet.

Tip

See Understanding tree order for an explanation of how nodes enter the tree and become ready.

Generally speaking, a node or scene should be able to be instanced anywhere in your game, and it should make no assumptions about what its parent is going to be.

We’ll go into detailed examples later in this tutorial, but for now, here’s the “golden rule” of node communication:

Call down, signal up.

If a node is calling a child (i.e. going “down” the tree), then get_node() is appropriate.

If a node needs to communicate “up” the tree, it should probably use a signal.

If you keep this rule in mind when designing your scene setup, you’ll be well on your way to a maintainable, well-organized project. And you’ll avoid using the cumbersome node paths that lead to problems.

Now, let’s look at each of these strategies along with some examples.

1. Using get_node()

get_node() traverses the scene tree using a given path to find the named node.

Tip

See Understanding node paths for a more detailed explanation of node paths.

get_node() example

Let’s consider the following common configuration:

alt -alt

The script in the Player node needs to notify the AnimatedSprite2D which animation to play, based on the player’s movement. In this situation, get_node() works well:

extends CharacterBody2D
+

If you do this, you’ll soon find that node references like this break easily. As soon as you change one thing about your scene tree, none of those references may be valid anymore.

Communication between nodes and scenes doesn’t have to be complicated. There is a better way.

Solution

As a general rule, nodes should manage their children, not the other way around. If you’re using get_parent() or get_node(".."), then you’re probably headed for trouble. Node paths like this are brittle, meaning they can break easily. The three main problems with this arrangement:

  1. You can’t test a scene independently. If you run the scene by itself or in a test scene that doesn’t have the exact same node setup, get_node() will cause a crash.

  2. You can’t change things easily. If you decide to rearrange or redesign your tree, paths will no longer be valid.

  3. Ready order is children-first, parent-last. This means that trying to access a parent’s property in a node’s _ready() can fail because the parent isn’t ready yet.

Tip

See Understanding tree order for an explanation of how nodes enter the tree and become ready.

Generally speaking, a node or scene should be able to be instanced anywhere in your game, and it should make no assumptions about what its parent is going to be.

We’ll go into detailed examples later in this tutorial, but for now, here’s the “golden rule” of node communication:

Call down, signal up.

If a node is calling a child (i.e. going “down” the tree), then get_node() is appropriate.

If a node needs to communicate “up” the tree, it should probably use a signal.

If you keep this rule in mind when designing your scene setup, you’ll be well on your way to a maintainable, well-organized project. And you’ll avoid using the cumbersome node paths that lead to problems.

Now, let’s look at each of these strategies along with some examples.

1. Using get_node()

get_node() traverses the scene tree using a given path to find the named node.

Tip

See Understanding node paths for a more detailed explanation of node paths.

get_node() example

Let’s consider the following common configuration:

alt +alt

The script in the Player node needs to notify the AnimatedSprite2D which animation to play, based on the player’s movement. In this situation, get_node() works well:

extends CharacterBody2D
 
 func _process(delta):
     if speed > 0:
         get_node("AnimatedSprite2D").play("run")
     else:
         get_node("AnimatedSprite2D").play("idle")
-
Tip

In GDScript you can use $ as a shorthand for get_node(), writing $AnimatedSprite2D instead.

2. Using signals

Signals should be used to call functions on nodes that are higher in the tree or at the same level (i.e. “siblings”).

You can connect a signal in the editor (most often for nodes that exist before the game starts) or in code (for nodes that you’re instancing at runtime). The syntax for connecting a signal is:

signal_name.connect(target_node.target_function)

Looking at this, you may be thinking “Wait, if I’m connecting to a sibling, won’t I need a node paths like ../Sibling?”. While you could do this, it breaks our rule above. The answer to this puzzle is to make sure that connections are made by the common parent.

Following the rule of calling down the tree, a node that’s a common parent to the signaling and receiving nodes will by definition know where they are and be ready after both of them.

Signal example

A very common use case for signals is updating your UI. Whenever the player’s health variable changes, you want to update a Label or ProgressBar display. However, your UI nodes are completely separated from your player (as they should be). The player knows nothing about where those nodes are and how to find them.

Here’s our example setup:

alt -alt

Note that the UI is an instanced scene, we’re just showing the contained nodes. This is where you often see things like get_node("../UI/VBoxContainer/HBoxContainer/Label).text = str(health), which is what we want to avoid.

Instead the player emits a health_changed signal whenever it adds/loses health. We need to send that signal to the UI’s update_health() function, which handles setting the Label value. In the Player script we use this code whenever the player’s health is changed:

health_changed.emit(health)
+
Tip

In GDScript you can use $ as a shorthand for get_node(), writing $AnimatedSprite2D instead.

2. Using signals

Signals should be used to call functions on nodes that are higher in the tree or at the same level (i.e. “siblings”).

You can connect a signal in the editor (most often for nodes that exist before the game starts) or in code (for nodes that you’re instancing at runtime). The syntax for connecting a signal is:

signal_name.connect(target_node.target_function)

Looking at this, you may be thinking “Wait, if I’m connecting to a sibling, won’t I need a node paths like ../Sibling?”. While you could do this, it breaks our rule above. The answer to this puzzle is to make sure that connections are made by the common parent.

Following the rule of calling down the tree, a node that’s a common parent to the signaling and receiving nodes will by definition know where they are and be ready after both of them.

Signal example

A very common use case for signals is updating your UI. Whenever the player’s health variable changes, you want to update a Label or ProgressBar display. However, your UI nodes are completely separated from your player (as they should be). The player knows nothing about where those nodes are and how to find them.

Here’s our example setup:

alt +alt

Note that the UI is an instanced scene, we’re just showing the contained nodes. This is where you often see things like get_node("../UI/VBoxContainer/HBoxContainer/Label).text = str(health), which is what we want to avoid.

Instead the player emits a health_changed signal whenever it adds/loses health. We need to send that signal to the UI’s update_health() function, which handles setting the Label value. In the Player script we use this code whenever the player’s health is changed:

health_changed.emit(health)
 

In the UI script we have:

onready var label = $VBoxContainer/HBoxContainer/Label
 
 func update_health(value):
     label.text = str(value)
 

Now we just need to connect the signal to the function. The perfect place to do that is in World, which is the common parent, and knows where both nodes are:

func _ready():
     $Player.health_changed.connect($UI.update_health)
-

3. Using groups

Groups are another way to decouple, especially when you have a lot of similar objects that need to do the same thing. A node can be added to any number of groups and membership can be changed dynamically at any time with add_to_group() and remove_from_group().

A common misconception about groups is that they are some kind of object or array that “contains” node references. Groups are a tagging system. A node is “in” a group if it has that tag assigned from it. The SceneTree keeps track of the tags and has functions like get_nodes_in_group() to help you find all nodes with a particular tag.

Group example

Let’s consider a Galaga-style space shooter where you have a lots of enemies flying around. These enemies may have different types and behaviors. You’d like to add a “smart bomb” upgrade that, when activated, destroys all enemies on the screen. Using groups, you can implement this with a minimal amount of code.

First, add all enemies to an “enemies” group. You can do this in the editor using the “Node” tab:

alt -alt

You can also add nodes to the group in your script:

func _ready():
+

3. Using groups

Groups are another way to decouple, especially when you have a lot of similar objects that need to do the same thing. A node can be added to any number of groups and membership can be changed dynamically at any time with add_to_group() and remove_from_group().

A common misconception about groups is that they are some kind of object or array that “contains” node references. Groups are a tagging system. A node is “in” a group if it has that tag assigned from it. The SceneTree keeps track of the tags and has functions like get_nodes_in_group() to help you find all nodes with a particular tag.

Group example

Let’s consider a Galaga-style space shooter where you have a lots of enemies flying around. These enemies may have different types and behaviors. You’d like to add a “smart bomb” upgrade that, when activated, destroys all enemies on the screen. Using groups, you can implement this with a minimal amount of code.

First, add all enemies to an “enemies” group. You can do this in the editor using the “Node” tab:

alt +alt

You can also add nodes to the group in your script:

func _ready():
     add_to_group("enemies")
 

Let’s assume every enemy has an explode() function that handles what happens when it dies (playing an animation, spawning dropped items, etc). Now that every enemy is in the group, we can implement our smart bomb function like this:

func activate_smart_bomb():
     get_tree().call_group("enemies", "explode")
-

4. Using owner

owner is a Node property that’s set automatically when you save a scene. Every node in that scene will have its owner set to the scene’s root node. This makes for a convenient way to connect child signals up to the main node.

owner example

In a complex UI, you often find yourself with a very deep, nested hierarchy of containers and controls. Nodes that the user interacts with, such as Button, emit signals, and you may want to connect those signals to the script on the UI’s root node.

Here’s an example setup:

alt -alt

The script on the root CenterContainer has the following function, which we want to call whenever any button is pressed:

extends CenterContainer
+

4. Using owner

owner is a Node property that’s set automatically when you save a scene. Every node in that scene will have its owner set to the scene’s root node. This makes for a convenient way to connect child signals up to the main node.

owner example

In a complex UI, you often find yourself with a very deep, nested hierarchy of containers and controls. Nodes that the user interacts with, such as Button, emit signals, and you may want to connect those signals to the script on the UI’s root node.

Here’s an example setup:

alt +alt

The script on the root CenterContainer has the following function, which we want to call whenever any button is pressed:

extends CenterContainer
 
 func _on_button_pressed(button_name):
     print(button_name, " was pressed")
@@ -37,17 +37,17 @@
 

No matter where you place the buttons in the tree - if you add more containers, for example - the CenterContainer remains the owner.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/tree_ready_order/index.html b/docs/4.x/basics/tree_ready_order/index.html index 5630098c..9a927661 100644 --- a/docs/4.x/basics/tree_ready_order/index.html +++ b/docs/4.x/basics/tree_ready_order/index.html @@ -1,8 +1,8 @@ -Understanding tree order :: Godot 4 Recipes - +Understanding tree order :: Godot 4 Recipes +

Understanding tree order

Problem

You need to understand in what order Godot handles nodes in the scene tree.

Solution

“Tree order” is mentioned often in the Godot docs and in tutorials. However, it is not always obvious to a beginner what is meant by this. Generally speaking, the order in which nodes are handled in the tree is in top-down fashion, starting at the root and going down each branch in turn.

Scene tree order is something that can cause a great deal of confusion for Godot beginners. In this example, we’ll illustrate in what order things happen.

Here’s our sample node setup:

alt -alt

On each node, we have the following script attached:

extends Node
+

Understanding tree order

Problem

You need to understand in what order Godot handles nodes in the scene tree.

Solution

“Tree order” is mentioned often in the Godot docs and in tutorials. However, it is not always obvious to a beginner what is meant by this. Generally speaking, the order in which nodes are handled in the tree is in top-down fashion, starting at the root and going down each branch in turn.

Scene tree order is something that can cause a great deal of confusion for Godot beginners. In this example, we’ll illustrate in what order things happen.

Here’s our sample node setup:

alt +alt

On each node, we have the following script attached:

extends Node
 
 func _init():
     # Note: a Node doesn't have a "name" yet here.
@@ -46,17 +46,17 @@
 

As you can see, all of these nodes printed their messages in tree order, from top to bottom, following branches first - with the exception of the _ready() code.

Here’s a quote from the Node reference:

Called when the node is “ready”, i.e. when both the node and its children have entered the scene tree. If the node has children, their _ready callbacks get triggered first, and the parent node will receive the ready notification afterwards.

This leads to an important rule-of-thumb to remember when setting up your node structure:

Tip

Parent nodes should manage their children, not vice-versa.

This means any code in the parent must be able to fully access any data in its children. For that reason, _ready() must be processed in reverse tree order.

Remember this when trying to access other nodes in _ready(). If you need to go up the tree to a parent (or grandparent), you should probably run that code in the parent rather than the child.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/basics/understanding_delta/index.html b/docs/4.x/basics/understanding_delta/index.html index 2afe11f3..0aff5d2c 100644 --- a/docs/4.x/basics/understanding_delta/index.html +++ b/docs/4.x/basics/understanding_delta/index.html @@ -1,5 +1,5 @@ -Understanding 'delta' :: Godot 4 Recipes - +Understanding 'delta' :: Godot 4 Recipes +

Understanding 'delta'

Problem

The delta or “delta time” parameter is a frequently-misunderstood concept in game development. In this tutorial, we’ll explain how it’s used, the importance of frame-rate independent movement, and practical examples of its use in Godot.

Solution

To illustrate the problem, let’s consider a Sprite node moving across the screen. If our screen is 600 pixels wide and we want the sprite to take 5 seconds to cross the screen, we can use the following calculation to find the necessary speed:

600 pixels / 5 seconds = 120 pixels/second
 

We’ll move the sprite every frame using the _process() function. If the game is running at 60 frames per second, we can find the per-frame movement like so:

120 pixels/second * 1/60 second/frame = 2 pixels/frame
@@ -10,9 +10,9 @@
 
 func _process(delta):
     $Sprite.position += movement
-

Run this code and you’ll see the sprite takes 5 seconds to cross the screen.

alt -alt

Maybe. The trouble begins if there is something else occupying the computer’s time. This is called lag and can come from a variety of sources - the cause could be your code or even other applications running on your computer. If this happens, then the length of a frame might increase. As an extreme example, imagine that the frame rate is halved - each frame took 1/30 instead of 1/60 of a second. Moving at 2 px/frame, it’s now going to take twice as long for the sprite to reach the edge.

alt -alt

Even small frame rate fluctuations will result in inconsistent movement speed. If this were a bullet or other fast-moving object, we wouldn’t want it slowing down like this. We need the movement to be frame rate independent.

Fixing the frame rate problem

When using the _process() function, it automatically includes a parameter called delta that’s passed in from the engine (so does _physics_process(), which is used for physics-related code). This is a floating point value representing the length of time since the previous frame. Typically, this will be approximately 1/60 or 0.0167 seconds.

With this information, we can stop thinking about how much to move each frame, and only consider our desired speed in pixels/second (120 from the above calculation).

Multiplying the engine’s delta value by this number will give us how many pixels to move each frame. The number will automatically adjust if the frame time fluctuates.

# 60 frames/second
+

Run this code and you’ll see the sprite takes 5 seconds to cross the screen.

alt +alt

Maybe. The trouble begins if there is something else occupying the computer’s time. This is called lag and can come from a variety of sources - the cause could be your code or even other applications running on your computer. If this happens, then the length of a frame might increase. As an extreme example, imagine that the frame rate is halved - each frame took 1/30 instead of 1/60 of a second. Moving at 2 px/frame, it’s now going to take twice as long for the sprite to reach the edge.

alt +alt

Even small frame rate fluctuations will result in inconsistent movement speed. If this were a bullet or other fast-moving object, we wouldn’t want it slowing down like this. We need the movement to be frame rate independent.

Fixing the frame rate problem

When using the _process() function, it automatically includes a parameter called delta that’s passed in from the engine (so does _physics_process(), which is used for physics-related code). This is a floating point value representing the length of time since the previous frame. Typically, this will be approximately 1/60 or 0.0167 seconds.

With this information, we can stop thinking about how much to move each frame, and only consider our desired speed in pixels/second (120 from the above calculation).

Multiplying the engine’s delta value by this number will give us how many pixels to move each frame. The number will automatically adjust if the frame time fluctuates.

# 60 frames/second
 120 pixels/second * 1/60 second/frame = 2 pixels/frame
 
 # 30 frames/second
@@ -24,9 +24,9 @@
 
 func _process(delta):
     $Sprite.position += movement * delta
-

Now when running at 30 frames per second, the travel time is consistent:

alt -alt

If the frame rate gets very low, the movement is no longer smooth, but the time remains the same.

alt -alt

Using delta with motion equations

What if your movement is more complex? The concept remains the same. Keep your units in seconds, not frames, and multiply by delta each frame.

Tip

Working in pixels and seconds is much easier to conceptualize too, since it relates to how we measure these quantities in the real world. “Gravity is 100 pixels/second/second, so after the ball falls for 2 seconds, it’s traveling at 200 pixels/second.” If you’re working with frames, then you have to think about acceleration in units of pixels/frame/frame. Go ahead and try - it’s not very natural.

For example, if you are applying a gravity, that’s an acceleration - each frame it will increase the velocity by some amount. As in the above example, the velocity then changes the node’s position.

Try adjusting delta and target_fps in the following code to see the effect:

extends Node2D
+

Now when running at 30 frames per second, the travel time is consistent:

alt +alt

If the frame rate gets very low, the movement is no longer smooth, but the time remains the same.

alt +alt

Using delta with motion equations

What if your movement is more complex? The concept remains the same. Keep your units in seconds, not frames, and multiply by delta each frame.

Tip

Working in pixels and seconds is much easier to conceptualize too, since it relates to how we measure these quantities in the real world. “Gravity is 100 pixels/second/second, so after the ball falls for 2 seconds, it’s traveling at 200 pixels/second.” If you’re working with frames, then you have to think about acceleration in units of pixels/frame/frame. Go ahead and try - it’s not very natural.

For example, if you are applying a gravity, that’s an acceleration - each frame it will increase the velocity by some amount. As in the above example, the velocity then changes the node’s position.

Try adjusting delta and target_fps in the following code to see the effect:

extends Node2D
 
 # Acceleration in pixels/sec/sec.
 var gravity = Vector2(0, 120)
@@ -59,17 +59,17 @@
 

If you don’t use delta when applying acceleration to your velocity, then your acceleration will be subject to fluctuations in frame rate. This can have a_much more subtle effect on movement - it will be inconsistent, but much more difficult to diagnose.

Tip

When using move_and_slide() you still need to apply delta to any other quantities such as gravity, friction, etc.

- - \ No newline at end of file +
+ + \ No newline at end of file diff --git a/docs/4.x/categories/index.html b/docs/4.x/categories/index.html index 2bb88e82..c415cdb3 100644 --- a/docs/4.x/categories/index.html +++ b/docs/4.x/categories/index.html @@ -1,19 +1,19 @@ -Categories :: Godot 4 Recipes - +Categories :: Godot 4 Recipes +

Categories

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/3d/101_3d_01/index.html b/docs/4.x/g101/3d/101_3d_01/index.html index 2e28a7e3..7175b6e7 100644 --- a/docs/4.x/g101/3d/101_3d_01/index.html +++ b/docs/4.x/g101/3d/101_3d_01/index.html @@ -1,5 +1,5 @@ -The 3D Editor :: Godot 4 Recipes - +The 3D Editor :: Godot 4 Recipes +

    The 3D Editor

    In this tutorial, we’ll look at how to start working in 3D in Godot. You’ll learn how to navigate in the 3D editor, how to create and manipulate 3D objects, @@ -15,8 +15,8 @@ much of what you’ve learned working on 2D projects (nodes, scenes, signals, etc.) applies equally well in 3D, there is also a whole new layer of complexity and capabilities. First, you’ll find that there are some additional features -available in the 3D editor window, so we’ll start there:

    Orienting in 3D Space

    When you first open a new project in Godot, you will see the 3D project view:

    alt -alt

    The first thing you should notice is the three colored lines in the center. +available in the 3D editor window, so we’ll start there:

    Orienting in 3D Space

    When you first open a new project in Godot, you will see the 3D project view:

    alt +alt

    The first thing you should notice is the three colored lines in the center. These are the x (red), y (green), and z (blue) axes. The point where they meet is the origin, which has the coordinates (0, 0, 0). You’ll find that this color scheme will also apply elsewhere in the Inspector.

    Note

    Different 3D applications follow different conventions for orientation. @@ -28,12 +28,12 @@ mode, which you can toggle on/off using Shift+F. In this mode, you can use the WASD keys to fly around the scene while aiming with the mouse.

    You can also alter the camera’s view by clicking on the [Perspective] label in the upper-left corner. Here, you can snap the camera to a particular -orientation.

    alt -alt

    Adding 3D Objects

    Now let’s add our first 3D node. Just as all 2D nodes inherit from Node3D, +orientation.

    alt +alt

    Adding 3D Objects

    Now let’s add our first 3D node. Just as all 2D nodes inherit from Node3D, which provides properties such as position and rotation, 3D nodes inherit from Node3D, which provides 3D versions of the same properties. Add one to your scene and you’ll see the following object -appear at the origin:

    alt -alt

    This object is not the node. It is something called a 3D gizmo. Gizmos are +appear at the origin:

    alt +alt

    This object is not the node. It is something called a 3D gizmo. Gizmos are tools that allow you to move and rotate objects in space. The three rings control rotation, while the three arrows move (translate) the object along the three axes. Note that the rings and arrows are color-coded to match the @@ -41,27 +41,27 @@ you find yourself getting lost.

    Tip

    Sometimes you may feel the gizmos are getting in your way. You can click on the mode icons to restrict yourself to only one type of transformation: move, rotate, or scale: -alt -alt

    Global vs. Local Space

    By default, the gizmo controls operate in global space. When you rotate the +alt +alt

    Global vs. Local Space

    By default, the gizmo controls operate in global space. When you rotate the object, the gizmo’s arrows still point along the axes. However, if you click the Use Local Space button, the gizmo will switch to moving the body in -local space.

    alt -alt

    Now when you rotate the object, the gizmo arrows point along the object’s +local space.

    alt +alt

    Now when you rotate the object, the gizmo arrows point along the object’s axes and not the world’s. Switching back and forth between Local and World space can make it much easier to place an object exactly where you want it.

    Transforms

    Look at the Inspector for the Node3D node. In the Transform section, you’ll see properties for Position, Rotation, and Scale. Drag the object around with the gizmo and observe how these values change. Just like in 2D, these properties are relative to the node’s parent.

    Together, these properties make up the node’s transform. When changing the node’s spatial properties in code, you’ll access the transform property, which is a Godot Transform3D object. It has two properties: origin and basis. The origin represents the body’s position, while the basis contains three vectors that define the body’s local coordinate axes - think of the three axis arrows in the gizmo when you’re in Local Space mode.

    You’ll see how to use these properties later in this section.

    Meshes

    Just like a Node2D, a Node3D has no size or appearance of its own. In 2D, you would use a Sprite2D to add a texture to the node. In 3D, you need to add a mesh. A mesh is a mathematical description of a shape. It consists of a collection of points, called vertices. These vertices are connected by lines, -called edges, and multiple edges (at least three) together make a face.

    alt -alt

    For example, a cube is made up of 8 vertices, 12 edges, and 6 faces.

    Adding Meshes

    Typically, meshes are created by using 3D modeling software, such as Blender. +called edges, and multiple edges (at least three) together make a face.

    alt +alt

    For example, a cube is made up of 8 vertices, 12 edges, and 6 faces.

    Adding Meshes

    Typically, meshes are created by using 3D modeling software, such as Blender. You can also find many collections of 3D models available for download, if you’re unable to create your own. However, often you just need a basic shape such as a cube or sphere. In this case, Godot provides a way to create -simple meshes called primitives.

    Add a MeshInstance3D node as a child of the Node3D and in the Inspector, click its Mesh property:

    alt -alt

    Here you can see the list of available primitives. They represent a handy +simple meshes called primitives.

    Add a MeshInstance3D node as a child of the Node3D and in the Inspector, click its Mesh property:

    alt +alt

    Here you can see the list of available primitives. They represent a handy collection of common useful shapes. Select “New BoxMesh” and you’ll see a plain cube appear on the screen.

    Cameras

    Try running the scene with your cube object. Did you see anything? In 3D, you -won’t see anything in the game viewport without adding a Camera3D. Add one to the root node and use the camera’s gizmo to position it pointing towards the cube:

    alt -alt

    The pinkish-purple pyramid shape on the camera is called the fustrum and +won’t see anything in the game viewport without adding a Camera3D. Add one to the root node and use the camera’s gizmo to position it pointing towards the cube:

    alt +alt

    The pinkish-purple pyramid shape on the camera is called the fustrum and represents the camera’s view. Notice the small triangular arrow which represents the camera’s “up” orientation. As you’re moving the camera around, try pressing the Preview button in the upper-left to see what the camera sees. Play the @@ -70,17 +70,17 @@ and how to use more of Godot’s 3D nodes.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/3d/101_3d_02/index.html b/docs/4.x/g101/3d/101_3d_02/index.html index 6278816a..61e55bae 100644 --- a/docs/4.x/g101/3d/101_3d_02/index.html +++ b/docs/4.x/g101/3d/101_3d_02/index.html @@ -1,27 +1,27 @@ -Importing 3D Objects :: Godot 4 Recipes - +Importing 3D Objects :: Godot 4 Recipes +

    Importing 3D Objects

    In the last part, we started a 3D project and looked at how to navigate and create 3D objects. In this part, you’ll learn how to import existing 3D objects that you’ve made or downloaded and how to use more of Godot’s 3D nodes.

    Importing 3D Objects

    If you’re familiar with 3D modeling software such as Blender, you can make your own models to use in your game. If not, there are many sources where you can download objects or even collections of objects for particular game types. One of our favorite makers of free game art is Kenney.nl.

    For our tutorials, we’re going to use Kenney’s Platformer Kit, which you can download here: https://kenney.nl/assets/platformer-kit

    This kit has a wide selection of objects that we can use to practice our Godot -3D skills. Here’s a sample showing what the kit looks like:

    alt -alt

    Once you’ve downloaded the kit, you’ll find that the objects inside are provided +3D skills. Here’s a sample showing what the kit looks like:

    alt +alt

    Once you’ve downloaded the kit, you’ll find that the objects inside are provided in a variety of different formats. Godot is able to use several of these, but since GLTF is available in this pack, it’s preferred over the others. Drop the GLTF format folder into your Godot project’s folder and rename it to “platformer_kit”.

    3D file formats

    Whether you create your own models or download the, you’ll need them to be saved in a format that Godot can use. Godot supports the following 3D file formats:

    • glTF - supported in both text (.gltf) and binary (.glb) versions
    • DAE (Collada) - an older format that is still supported
    • OBJ (Wavefront) - an older format that is supported, but the format is limited compared to modern options
    • FBX - a commercial format that has limited support

    glTF is the recommended format - it has the most features and is very well supported in Godot.

    When you switch back to your Godot window, you’ll see progress bar while Godot scans the folder and imports all of the objects. Let’s click on one of them to -see what’s going on. In the FileSystem tab, double-click on crate.glb:

    alt -alt

    Here you can see the object will be imported as a scene, with its root type +see what’s going on. In the FileSystem tab, double-click on crate.glb:

    alt +alt

    Here you can see the object will be imported as a scene, with its root type set to Node3D and named “Scene Root”. Let’s change these: set the root type to RigidBody3D and the root name to “Crate”, then click the “Reimport” button.

    Now right-click on “crate.glb” and choose New Inherited Scene. Here we have a classic game object: the crate. The root node of the scene is a RigidBody3D named “Crate” just as we wanted.

    Finally, we need to add a collision shape to the body. While we could do this by adding a CollionShape3D, as you would typically do in 2D, but there’s a quicker way.

    Select the crate2 mesh and you’ll see a Mesh menu appear at the top of the viewport. Click it and select Create Single Convex Collision Sibling. Godot will automatically add a CollionShape3D with a collision shape that matches the mesh.

    Now we’re finished setting up the object. Save your Crate scene and let’s see how we can use it.

    Building a 3D Scene

    Create a new scene with a Node3D root. The first child we’ll add is one to give us a “ground” to stack some crates on. Add a StaticBody3D called “Ground”, and to that add a MeshInstance3D. In the Mesh property, select “New BoxMesh” and then click it to open its properties. Set Size to (10, 0.1, 10) so that we have a nice large surface. However, it would look better if it weren’t plain white.

    Also in the mesh properties is a Material property. Materials are how you define the appearance of an object. Select “New StandardMaterial3D” and then click it to open a large list of properties. To set the color of the mesh, we need the Albedo/Color property. Choose a color, such as brown or dark green.

    If we add a crate, it will fall right through the mesh, so we also need to give it a collision shape. Add a CollisionShape3D to the Ground and choose “New BoxShape3D”. Set the collision box to the same size as the mesh.

    Now instance a few crates in the scene and arrange them in a rough stack. Add a Camera and place it where it has a good view of the crates. Run the scene -and watch your crates go tumbling!

    alt -alt

    Why is the scene so dark? Because there’s no light! By default, Godot doesn’t add any lighting or environment to your scenes, like it does in the editor viewport. This is great when you want to set up your own specific lighting, but for a quick example scene like this, there’s a shortcut.

    Lighting

    There are multiple light nodes available in 3D, which you can use to create a variety of lighting effects. But we’re going to start with DirectionalLight3D. However, instead of adding one manually, we’re going to have Godot use the same one it’s using in the editor window. At the top ove the viewport, there are two icons that control the preview lighting and preview environment. If you click the three dots next to them, you can see their settings.

    alt -alt

    Click the Add Sun to Scene button, and Godot will add a DirectionalLight3D to your scene. Click Add Environment to Scene and it will do the same with the preview sky by adding a WorldEnvironment node.

    Run the scene again, and you’ll be able to see your crates falling.

    Rotating Camera

    Let’s make the camera a little more dynamic by having it slowly orbit around the +and watch your crates go tumbling!

    alt +alt

    Why is the scene so dark? Because there’s no light! By default, Godot doesn’t add any lighting or environment to your scenes, like it does in the editor viewport. This is great when you want to set up your own specific lighting, but for a quick example scene like this, there’s a shortcut.

    Lighting

    There are multiple light nodes available in 3D, which you can use to create a variety of lighting effects. But we’re going to start with DirectionalLight3D. However, instead of adding one manually, we’re going to have Godot use the same one it’s using in the editor window. At the top ove the viewport, there are two icons that control the preview lighting and preview environment. If you click the three dots next to them, you can see their settings.

    alt +alt

    Click the Add Sun to Scene button, and Godot will add a DirectionalLight3D to your scene. Click Add Environment to Scene and it will do the same with the preview sky by adding a WorldEnvironment node.

    Run the scene again, and you’ll be able to see your crates falling.

    Rotating Camera

    Let’s make the camera a little more dynamic by having it slowly orbit around the scene. Select the root node and add a Node3D, which will be located at (0, 0, 0) and name it “CameraHub”. In the scene tree, drag the camera to make it a child of this new node. Now, if the CameraHub rotates around the y axis, it will drag the camera along with it.

    Add a script to the root node and add the following:

    extends Node3D
     
    @@ -33,17 +33,17 @@
     a player-controlled character.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/3d/101_3d_03/index.html b/docs/4.x/g101/3d/101_3d_03/index.html index 92820604..26a66350 100644 --- a/docs/4.x/g101/3d/101_3d_03/index.html +++ b/docs/4.x/g101/3d/101_3d_03/index.html @@ -1,5 +1,5 @@ -Creating a 3D Character :: Godot 4 Recipes - +Creating a 3D Character :: Godot 4 Recipes +

    Creating a 3D Character

    In the last part, we covered how to import 3D objects and how to arrange them in a scene. In this installment, we’ll add more objects to the scene, including a user-controlled character.

    Building the Scene

    We’re going to continue using the Kenney Platformer Kit we downloaded in Part 2. Select all the block*.glb files and in the Import tab set their Root Type to StaticBody3D. Uncheck the Root Name property and click Reimport. Select blockLarge.glb and make a new inherited scene. Use the Create Single Convex Collision Sibling option on the mesh using the menu as you did in the last tutorial. Now you can save the scene - I recommend making a separate folder for this, as soon you’re going to have a bunch of scenes representing the differently shaped platform parts.

    Open the scene from the previous step with the “Ground” plane and the crates. Delete the crates and add an instance of the large block. We want to be able @@ -7,12 +7,12 @@ from the “Transform” menu at the top of the Viewport and set Translate Snap to 0.5. Then click on the “Snap Mode” button (or press the Y key). Now duplicate the block a few times and drag them to arrange.

    If you like, go ahead and add scenes for some of the other platform blocks and -arrange them into a pleasing level. Be creative!

    alt -alt

    Adding a Character

    Now we’re going to make a character so we can walk around on the platforms. +arrange them into a pleasing level. Be creative!

    alt +alt

    Adding a Character

    Now we’re going to make a character so we can walk around on the platforms. Open a new scene and start with a CharacterBody3D named “Character”. This PhysicsBody node behaves very much like its 2D equivalent (you’ve already done the 2D tutorials, right?). It has a move_and_slide() method that we’ll use to perform the movement and collision detection.

    Add a capsule-shaped MeshInstance3D and a matching CollionShape3D. Remember, you can add a StandardMaterial3D to the mesh and set its Albedo/Color property to change the color.

    The capsule is nice, but it’s going to be hard to tell what direction it’s facing. Let’s add another mesh, this time with a CylinderMesh3D shape. -Set its Top Radius to 0.2, its Bottom Radius to 0.001 and its Height to 0.5, then its x rotation to -90 degrees. Now you have a nice cone shape. Arrange it so it’s pointing out from the body along the negative z axis. (You can tell which way is negative because the gizmo arrows point in the positive direction).

    alt -alt

    In this picture, we’ve also added two sphere meshes for eyes to give a little more character. Feel free to add whatever details you like.

    Let’s also add a Camera3D to the scene, so it will follow the player around. Position the camera behind and above the character, angling it down a bit. Click the “Preview” button to check the camera’s view.

    Before we add a script, open the “Project Settings” and add the following inputs +Set its Top Radius to 0.2, its Bottom Radius to 0.001 and its Height to 0.5, then its x rotation to -90 degrees. Now you have a nice cone shape. Arrange it so it’s pointing out from the body along the negative z axis. (You can tell which way is negative because the gizmo arrows point in the positive direction).

    alt +alt

    In this picture, we’ve also added two sphere meshes for eyes to give a little more character. Feel free to add whatever details you like.

    Let’s also add a Camera3D to the scene, so it will follow the player around. Position the camera behind and above the character, angling it down a bit. Click the “Preview” button to check the camera’s view.

    Before we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:

    Input ActionKey
    move_forwardW
    move_backS
    strafe_rightD
    strafe_leftA
    jumpSpace

    Now let’s add a script to the body.

    extends CharacterBody3D
     
     var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
    @@ -34,13 +34,13 @@
     accelerate in the positive Y direction (downward), call get_input() to
     check for input, and then use move_and_slide() to move in the direction
     of the velocity vector.

    In get_input() we check to see which key is pressed and then move in that -direction. Run the program and test:

    alt -alt

    This is all good, but we need to be able to rotate using the mouse. Add the following code to the character’s script:

    func _unhandled_input(event):
    +direction. Run the program and test:

    alt +alt

    This is all good, but we need to be able to rotate using the mouse. Add the following code to the character’s script:

    func _unhandled_input(event):
         if event is InputEventMouseMotion:
             rotate_y(-event.relative.x * mouse_sensitivity)
     

    This will convert any mouse motion in the x direction into a rotation around -the y axis.

    Run the scene and confirm that moving the mouse rotates the character:

    alt -alt

    However, there’s a problem. No matter which way we’re facing, pressing W +the y axis.

    Run the scene and confirm that moving the mouse rotates the character:

    alt +alt

    However, there’s a problem. No matter which way we’re facing, pressing W moves us along the Z axis of the world. Our movement is using global coordinates, but we need to move in the object’s forward direction.

    The Power of Transforms

    This is where transforms come in. A transform is a mathematical matrix that contains the object’s translation, rotation, and scale information all in one. In Godot it’s stored in the Transform data type. The position information is called the transform.origin and the orientation information is in the transform.basis.

    Remember how the 3D gizmo can be set to “Local Space Mode”? When in this mode, @@ -49,24 +49,24 @@ var movement_dir = transform.basis * Vector3(input.x, 0, input.y) velocity.x = movement_dir.x * speed velocity.z = movement_dir.z * speed -

    By multiplying the input vector by the transform.basis, we apply that transformation to the vector. Since the basis represents the object’s rotation, we’ve now converted forward and back to point along the object’s Z axis, and the strafe keys along its X.

    alt -alt

    Jumping

    Let’s add one more movement to the player: jumping.

    Add these lines to the end of _unhandled_input():

    if event.is_action_pressed("jump") and is_on_floor():
    +

    By multiplying the input vector by the transform.basis, we apply that transformation to the vector. Since the basis represents the object’s rotation, we’ve now converted forward and back to point along the object’s Z axis, and the strafe keys along its X.

    alt +alt

    Jumping

    Let’s add one more movement to the player: jumping.

    Add these lines to the end of _unhandled_input():

    if event.is_action_pressed("jump") and is_on_floor():
         velocity.y = jump_speed
     

    Improving the camera

    You may have noticed that the if the character stands near an obstacle, the camera can “clip” inside the object, which doesn’t look nice. While coding a good 3D camera can be a complex topic on its own, we can use a built-in Godot node to get a pretty good solution.

    Delete the Camera3D from the character scene and add a SpringArm3D. This node can act as a moving arm that holds the camera while detecting collisions. It will move the camera closer if there’s an obstacle.

    In its properties, set Spring Length to 5, and set its Position to (0, 1, 0), which is at the character’s head. Note the yellow line indicating the Spring Length. The camera will move along this line - at its end whenever possible, but moving closer if an obstacle is there.

    Add back a Camera3D as a child of the SpringArm3D, and try running the game again. You can experiment with rotating the spring arm (around its x axis to point down slightly, for example) until you find something you like.

    What about first person?

    If you’re curious how you would do this in first person, see the Basic FPS Character recipe. You’ll notice several similarities with the 3rd person script we wrote above.

    Wrapping Up

    In this tutorial you learned how to build a more complex scene, and how to write movement code for a user-controlled character. You also learned about transforms, which are a very important concept in 3D - you’re going to be using a lot in the future.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/3d/index.html b/docs/4.x/g101/3d/index.html index a3c5c6cd..54eaccc4 100644 --- a/docs/4.x/g101/3d/index.html +++ b/docs/4.x/g101/3d/index.html @@ -1,19 +1,19 @@ -Intro to 3D :: Godot 4 Recipes - +Intro to 3D :: Godot 4 Recipes +
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/gdscript/gdscript_01/index.html b/docs/4.x/g101/gdscript/gdscript_01/index.html index a716dac5..8a4dc86a 100644 --- a/docs/4.x/g101/gdscript/gdscript_01/index.html +++ b/docs/4.x/g101/gdscript/gdscript_01/index.html @@ -1,10 +1,10 @@ -Getting started :: Godot 4 Recipes - +Getting started :: Godot 4 Recipes +

    Getting started

    Overview

    Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. For example, a Sprite2D node automatically displays an image, but to move it across the screen, you’ll add a script that tells it how fast, in what direction, and so on.

    You can think of it as the coding version of using the Inspector - GDScript knows all about Godot nodes and how to access them, plus it allows you to change them dynamically.

    GDScript is Godot’s built-in language for scripting and interacting with nodes. The GDScript documentation on the Godot website is a great place to get an overview of the language, and I highly recommend taking the time to read through it.

    Is GDScript Python?

    You’ll often read comments to the effect that “GDScript is based on Python”. That’s somewhat misleading; GDScript uses a syntax that’s modeled on Python’s, but it’s a distinct language that’s optimized for and integrated into the Godot engine. That said, if you already know some Python, you’ll find GDScript looks very familiar.

    Warning

    Many tutorials (and Godot in general) assume that you have at least some programming experience already. If you’ve never coded before, you’ll likely find learning Godot to be a challenge. Learning a game engine is a large task on its own; learning to code at the same time means you’re taking on a lot. If -you find yourself struggling with the code in this section, you may find that working through an introductory programming lesson (Python is a good option) will help you grasp the basics.

    Structure of a script

    The first line of any GDScript file must be extends <Class>, where <Class> is some existing built-in or user-defined class. For example, if you’re attaching a script to a CharacterBody2D node, then your script would start with extends CharacterBody2D. This states that your script is taking all the functionality of the built-in CharacterBody2D object and extending it with additional functionality created by you.

    In the rest of the script, you can define any number of variables (aka “class properties”) and functions (aka “class methods”).

    Creating a script

    Let’s make our first script. Remember, any node can have a script attached to it.

    Open the editor and add a Sprite2D node to empty scene. Right-click on the new node, and choose “Attach Script”. You can also click the button next to the search box.

    alt -alt

    Next you need to decide where you want the script saved and what to call it. If you’ve named the node, the script will automatically be named to match it (so unless you’ve changed anything this script will likely be called “sprite2d.gd”).

    Now the script editor window opens up, and this is your new, empty sprite script. Godot has automatically included some lines of code, as well as some comments describing what they do.

    extends Sprite2D
    +you find yourself struggling with the code in this section, you may find that working through an introductory programming lesson (Python is a good option) will help you grasp the basics.

    Structure of a script

    The first line of any GDScript file must be extends <Class>, where <Class> is some existing built-in or user-defined class. For example, if you’re attaching a script to a CharacterBody2D node, then your script would start with extends CharacterBody2D. This states that your script is taking all the functionality of the built-in CharacterBody2D object and extending it with additional functionality created by you.

    In the rest of the script, you can define any number of variables (aka “class properties”) and functions (aka “class methods”).

    Creating a script

    Let’s make our first script. Remember, any node can have a script attached to it.

    Open the editor and add a Sprite2D node to empty scene. Right-click on the new node, and choose “Attach Script”. You can also click the button next to the search box.

    alt +alt

    Next you need to decide where you want the script saved and what to call it. If you’ve named the node, the script will automatically be named to match it (so unless you’ve changed anything this script will likely be called “sprite2d.gd”).

    Now the script editor window opens up, and this is your new, empty sprite script. Godot has automatically included some lines of code, as well as some comments describing what they do.

    extends Sprite2D
     
     # Called when the node enters the scene tree for the first time.
     func _ready():
    @@ -13,25 +13,25 @@
     # Called every frame. 'delta' is the elapsed time since the previous frame.
     func _process(delta):
         pass
    -

    Since the script was added to a Sprite2D, the first line is automatically set to extends Sprite2D. Because this script extends the Sprite2D class, it will be able to access and manipulate all the properties and methods that a Sprite2D node provides.

    Properties and methods

    Properties and methods are two terms which specifically mean variables and functions that are defined in an object. Programmers tend to use the terms interchangeably.

    After that is where you’re going to define all the variables you will use in the script, the “member variables”. You define variables with the ‘var’ keyword - as you can see by the comment examples.

    Go ahead and delete the comments and let’s talk about this next piece.

    Now we see a function called _ready(). In GDScript you define a function with the keyword “func”. The _ready() function is a special one that Godot looks for and runs whenever a node is added to the tree, for example when we hit “Play”.

    Let’s say that when the game starts, we want to make sure the sprite goes to a particular location. In the Inspector, we want to set the Position property. Notice that it’s in the section called “Node2D” - that means this is a property that any Node2D type node will have, not just Sprite2Ds.

    How do we set the property in code? One way to find the name of the property is by hovering over it in the Inspector.

    alt -alt

    Godot has a great built-in help/reference tool. Click on “Classes” at the top of the Script window and search for Node2D and you’ll see a help page showing you all the properties and methods the class has available. Looking down a bit you can see position in the “Member Variables” section - that’s the one we want. It also tells us the property is of the type “Vector2”.

    alt -alt

    Let’s go back to the script and use that property:

    func _ready():
    +

    Since the script was added to a Sprite2D, the first line is automatically set to extends Sprite2D. Because this script extends the Sprite2D class, it will be able to access and manipulate all the properties and methods that a Sprite2D node provides.

    Properties and methods

    Properties and methods are two terms which specifically mean variables and functions that are defined in an object. Programmers tend to use the terms interchangeably.

    After that is where you’re going to define all the variables you will use in the script, the “member variables”. You define variables with the ‘var’ keyword - as you can see by the comment examples.

    Go ahead and delete the comments and let’s talk about this next piece.

    Now we see a function called _ready(). In GDScript you define a function with the keyword “func”. The _ready() function is a special one that Godot looks for and runs whenever a node is added to the tree, for example when we hit “Play”.

    Let’s say that when the game starts, we want to make sure the sprite goes to a particular location. In the Inspector, we want to set the Position property. Notice that it’s in the section called “Node2D” - that means this is a property that any Node2D type node will have, not just Sprite2Ds.

    How do we set the property in code? One way to find the name of the property is by hovering over it in the Inspector.

    alt +alt

    Godot has a great built-in help/reference tool. Click on “Classes” at the top of the Script window and search for Node2D and you’ll see a help page showing you all the properties and methods the class has available. Looking down a bit you can see position in the “Member Variables” section - that’s the one we want. It also tells us the property is of the type “Vector2”.

    alt +alt

    Let’s go back to the script and use that property:

    func _ready():
         position = Vector2(100, 150)
    -

    Notice how the editor is making suggestions as you type. Godot uses vectors for lots of things, and we’ll talk more about them later. For now, let’s type Vector2, and the hint tells us to put two floats for x and y.

    Now we have a script that says “When this sprite starts, set its position to (100, 150)”. We can try this out by pressing the “Play Scene” button.

    alt -alt

    Learning tip

    When first learning to code, beginners often ask “How do you memorize all these commands?” Just like any other skill, it’s not a matter of memorization, it’s about practice. As you use things more, the things you do frequently will “stick” and become automatic. Until then, it’s a great idea to keep the reference docs handy. Use the search function whenever you see something you don’t recognize. If you have multiple monitors, keep a copy of the web docs open on the side for quick reference.

    Wrapping up

    Congratulations on making your first script in GDScript! Before moving on, make sure you understand everything we did in this step. In the next part, we’ll add some more code to move the sprite around the screen.

    + + \ No newline at end of file diff --git a/docs/4.x/g101/gdscript/index.html b/docs/4.x/g101/gdscript/index.html index 27acf3b5..1ed9d400 100644 --- a/docs/4.x/g101/gdscript/index.html +++ b/docs/4.x/g101/gdscript/index.html @@ -1,20 +1,20 @@ -Introduction to GDScript :: Godot 4 Recipes - +Introduction to GDScript :: Godot 4 Recipes +

     GDScript

    GDScript is Godot’s built-in scripting language. Its syntax is based on Python, so if you’re familiar with that language, you’ll feel right at home. In this chapter, we’ll introduce the language and get you up to speed with how it works.

    Updating to Godot 4.0

    We’re working on a new version of Godot 101 for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.

    In this section:

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/index.html b/docs/4.x/g101/index.html index ad6f6bc5..db4e6d3c 100644 --- a/docs/4.x/g101/index.html +++ b/docs/4.x/g101/index.html @@ -1,21 +1,21 @@ -Godot 101 :: Godot 4 Recipes - -

     Godot 101

    alt -alt

    Your introduction to the Godot game engine. If you’ve never used a game engine +Godot 101 :: Godot 4 Recipes + +

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/start/101_01/index.html b/docs/4.x/g101/start/101_01/index.html index c56cc7cc..a7b233d1 100644 --- a/docs/4.x/g101/start/101_01/index.html +++ b/docs/4.x/g101/start/101_01/index.html @@ -1,5 +1,5 @@ -What is Godot? :: Godot 4 Recipes - +What is Godot? :: Godot 4 Recipes +

    What is Godot?

    Game Engines

    Game development is complex and involves a wide variety of knowledge and skills. In order to build a modern game, you need a lot of underlying technology before @@ -27,8 +27,8 @@ be free to download, but the will require some kind of licensing or royalty agreement if you plan to release your game (and especially if your game makes money). You need to carefully read and understand what you’re agreeing to and -what you are and are not allowed to do with the engine.

    Why use Godot?

    alt -alt +what you are and are not allowed to do with the engine.

    Why use Godot?

    alt +alt Click here to download Godot

    In contrast to the above, Godot is completely free and open source, released under the very permissive MIT license. This means there are no fees, hidden costs, or royalties you need to pay. This is in addition to being a fully @@ -40,17 +40,17 @@ free to modify the engine itself - no permission required.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/start/101_02/index.html b/docs/4.x/g101/start/101_02/index.html index 46774ad7..780b8ef7 100644 --- a/docs/4.x/g101/start/101_02/index.html +++ b/docs/4.x/g101/start/101_02/index.html @@ -1,30 +1,30 @@ -The Godot Editor: Finding your way around :: Godot 4 Recipes - +The Godot Editor: Finding your way around :: Godot 4 Recipes +

    The Godot Editor: Finding your way around

    Project Manager

    The Project Manager is the first thing you’ll see when opening Godot.

    alt -alt

    In this window you can see a list of your Godot projects. You can choose an existing project and click “Run” to play the game or click “Edit” to work on it in the Godot editor. Since you probably don’t have any projects yet, let’s start by clicking the “New Project” -button.

    alt -alt

    Here you can give the project a name and create a folder to store it in.

    Note

    Every Godot project is contained in its own folder. This has many benefits, including making it easy to move, share, and backup +

    The Godot Editor: Finding your way around

    Project Manager

    The Project Manager is the first thing you’ll see when opening Godot.

    alt +alt

    In this window you can see a list of your Godot projects. You can choose an existing project and click “Run” to play the game or click “Edit” to work on it in the Godot editor. Since you probably don’t have any projects yet, let’s start by clicking the “New Project” +button.

    alt +alt

    Here you can give the project a name and create a folder to store it in.

    Note

    Every Godot project is contained in its own folder. This has many benefits, including making it easy to move, share, and backup projects. It also means that all the project’s files (images, sounds, etc.) must be in the project folder.

    When you’re naming your project, try to choose a name that describes the project. “New Game Project #23” is not going to help you remember what that project was. You should also think about compatibility: some operating systems are case-sensitive, and some are not. This can lead to problems if you move or share your project from one computer to another. For this reason, many -programmers develop a standardized naming scheme. For example: “No spaces, use ‘_’ between words.”

    Let’s name this new project “getting_started”. Type this name, click Create Folder, and then click Create & Edit.

    You’re now looking at the Godot editor window. This is where you’ll spend most of your time when working in Godot. The editor is divided into sections.

    alt -alt

    • Viewport: This is where you’ll see the parts of your game as you’re working on them.
    • Workspaces: At the center-top, you can switch between working in the 2D, 3D, or Script workspaces. You start in 3D.
    • Playtest Buttons: These buttons let you launch and control your game when testing.
    • Docks/Tabs: On both sides are a number of docks where you can view game items and set their properties.
    • Bottom Panel: Here, you’ll see context-specific information for various tools. The most important one to note first is the Output panel, where you’ll see any error or informational messages when your game is running.

    Project Settings

    Now we’ve talked about the main parts of the Godot window and how they work, let’s spend a little time talking about our Project settings. Usually one of the first tasks when starting a new project is make sure it’s all set up correctly.

    So let’s click on Project in the menu and select Project Settings.

    alt -alt

    This is the Project settings window. On the left is a list of categories. For most projects, the default settings will be fine, and you shouldn’t worry about changing them unless you have a very specific need. For now, we’re just going to look at two of the sections. First, Application/Config.

    In here, you can set your game’s title, choose which scene is the “main scene” (more about that in a bit), and change the icon.

    Second, let’s look at the Display section. This is where you set up your game’s display. width & height let you set the size of the game window. If, for example, you were making a mobile game, you’d want to set this to the resolution and proportions of your target device. There are also settings for scaling, stretching, fullscreen mode, and more. For now, we’ll leave the default size - later on we’ll talk about how to adjust these to get our game running on different devices.

    alt -alt

    There are also some tabs across the top. We’ve been looking at the General tab. I’ll also point out briefly, the Input Map. This is where you can define different input actions for keyboard control, gamepad, mouse, and so on. In your game, you’ll just worry about the action, not what individual key or button was pressed. This is a very powerful and flexible way of handling player input.

    We also have localization options, if you plan to support multiple languages. Autoloading, which we’ll get to later, and plugins. The Godot community has created a variety of useful plugins that you can download and add to supply more features, different tools, and so on.

    We’ll come back to the project settings window later. Let’s close it for now and we’re ready to move on to the next step: working with nodes.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/g101/start/101_03/index.html b/docs/4.x/g101/start/101_03/index.html index a1585a0f..3f66e19a 100644 --- a/docs/4.x/g101/start/101_03/index.html +++ b/docs/4.x/g101/start/101_03/index.html @@ -1,27 +1,27 @@ -Nodes: Godot's building blocks :: Godot 4 Recipes - +Nodes: Godot's building blocks :: Godot 4 Recipes +

    Nodes: Godot's building blocks

    Nodes are the basic building blocks for creating games in Godot. A node is an object that can represent some kind of specialized game function. A given type of node might display graphics, play an animation, or represent a 3D model of an object. The node also contains a collection of properties, allowing you to customize its behavior. Which nodes you add to your project will depend on what functionality you need. It’s a modular system designed to give you flexibility in building your game objects.

    Working with Nodes

    Nodes are objects, in the programming sense. They encapsulate data and behavior, and they can inherit properties from other nodes. Rather than use one of the default suggestions, let’s click the “Add/Create a New Node” button in the scene dock.

    alt -alt

    Here you’ll see the whole hierarchy of node types available in the engine. For example, the nodes with the bluish icons all fall under the “Node2D” category, meaning they will all have the properties of a Node2D. More about that in a moment.

    alt -alt

    The list is long, and it would be frustrating to have to drill down every time to find the node you need. Instead, you can use the search function to find it using a small number of characters. We’re looking for the Sprite2D node, so I’ll just type “sp” and we’ll jump right to it. Click “Create” to add the node.

    alt -alt

    Now we have this Sprite2D node in our Scene dock. Make sure it’s selected, and then look at the Inspector dock on the right side. Over here, you’ll see all the properties of whatever node you have selected. Notice that the properties are organized by where they come from. The Sprite2D node inherits from Node2D, which inherits from CanvasItem, which inherits from the plain old Node.

    alt -alt

    Over in the viewport, the sprite doesn’t look like much. A sprite’s purpose is to display an image, or texture. As you can see in the Inspector, the Texture property is currently empty. Fortunately, every new Godot project comes with an image we can use: the Godot icon. Drag the icon from the Filesystem dock and drop it in the texture property.

    In the Inspector, click to expand the “Transform” section, and type (50, 50) in the Position property.

    alt -alt

    You can also click and drag the sprite around in the viewport, and you’ll see the Position values changing as you move.

    One important property of nodes is that they can be arranged in a parent-child hierarchy. Make sure you have the Sprite2D selected and press the add button again. Add another Sprite2D and also drag the icon into its texture.

    This new sprite is a child of the first. This means that it’s “attached” to its parent. If the parent sprite moves, so will the child. Click on the child sprite and set its Position to (50, 50). Now click and drag the parent sprite to move it around the screen.

    Notice that the Position of the parent is changing as you move it around. Now check the child: it’s still (50, 50). That’s because its “Transform” properties are relative to its parent.

    alt -alt

    Scenes

    Grouping nodes together like this is a powerful tool, enabling you to construct complex objects out of node “building blocks”. For example, a “Player” node in your game might have many child nodes attached to it: a Sprite2D for display, an AnimationPlayer to animate it, a Camera2D to follow it around, and so on.

    alt -alt

    A group of nodes arranged in a “tree” structure like this is called a Scene. In the next part, we’ll look at how you can use scenes to organize your game’s objects into independent parts that all work together. You’ll see this in practice was you work through the examples in later lessons.

    + + \ No newline at end of file diff --git a/docs/4.x/g101/start/index.html b/docs/4.x/g101/start/index.html index 8c2d761b..fd789a2e 100644 --- a/docs/4.x/g101/start/index.html +++ b/docs/4.x/g101/start/index.html @@ -1,21 +1,21 @@ -Getting Started :: Godot 4 Recipes - +Getting Started :: Godot 4 Recipes +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_01/index.html b/docs/4.x/games/first_2d/first_2d_01/index.html index f701f3fd..b1cba533 100644 --- a/docs/4.x/games/first_2d/first_2d_01/index.html +++ b/docs/4.x/games/first_2d/first_2d_01/index.html @@ -1,26 +1,26 @@ -Project Setup :: Godot 4 Recipes - +Project Setup :: Godot 4 Recipes +

    Project Setup

    This first game project will guide you through making your first Godot Engine game. While you don’t need any previous experience, it’s expected that you’ve at least read through the Godot 101: Getting Started section. There, you’ll learn about the editor interface and how to get around the Godot UI.

    Why start with 2D?

    In a nutshell, 3D games are much more complex than 2D ones. However, many of the underlying game engine features you’ll need to know are the same. You should stick to 2D until you have a good understanding of Godot’s workflow. At that point, the jump to 3D will feel much easier.

    Open Godot and start a new project. You can name it anything you’d like - we’re going with “Classic Shmup”, since this is a traditional shoot-em-up style game.

    Downloading the art

    You can download the art we’ll be using for the game from itch.io: -Mini Pixel Pack by Grafxkid

    Unzip the art pack and copy it into your project by dropping the folder in the FileSystem tab.

    alt -alt

    Project settings

    Next, we need to set up some project-wide settings. Open Project Settings and check the “Advanced Settings” toggle in the upper-right.

    • In the Display/Window section:

      • Viewport Width & Viewport Height to 240, 320.
      • Window Width Override & Window Height Override to 480, 640.
      • Stretch/Mode to canvas_items.

    These settings will ensure the game is the right size. Because we’re using pixel art, the images themselves are very small, so an old-school resolution like 240x320 is perfect. However, on a modern monitor, that’s a fairly small window, so the other settings let us scale that up proportionally. If you have a 1080p monitor, you can make the override values 720x960 instead. You’ll also be able to resize the window when the game is running.

    • In the Rendering/Textures section under Canvas Textures, set Default Texture Filter to Nearest. This will ensure that our beautiful pixel art stays nice and crisp, looking like the image on the right, not the one on the left:

    alt -alt

    • Click the Input Map tab at the top of the Project Settings window. This is where we can set up the inputs we want to use in the game. In the “Add New Action” box, type the following, hitting <enter> after each to add it to the list of actions: right, left, up, down, shoot. To assign key(s) to each named input, click the + button to its right and press the key on your keyboard. When you’re done, you should have something like this:

    alt -alt

    Feel free to use other keys if you’d rather use a different setup.

    Next steps

    That takes care of setting up - now we’re ready to get started! In the next section, we’ll create the player-controlled spaceship.

    +Mini Pixel Pack by Grafxkid

    Unzip the art pack and copy it into your project by dropping the folder in the FileSystem tab.

    alt +alt

    Project settings

    Next, we need to set up some project-wide settings. Open Project Settings and check the “Advanced Settings” toggle in the upper-right.

    • In the Display/Window section:

      • Viewport Width & Viewport Height to 240, 320.
      • Window Width Override & Window Height Override to 480, 640.
      • Stretch/Mode to canvas_items.

    These settings will ensure the game is the right size. Because we’re using pixel art, the images themselves are very small, so an old-school resolution like 240x320 is perfect. However, on a modern monitor, that’s a fairly small window, so the other settings let us scale that up proportionally. If you have a 1080p monitor, you can make the override values 720x960 instead. You’ll also be able to resize the window when the game is running.

    • In the Rendering/Textures section under Canvas Textures, set Default Texture Filter to Nearest. This will ensure that our beautiful pixel art stays nice and crisp, looking like the image on the right, not the one on the left:

    alt +alt

    • Click the Input Map tab at the top of the Project Settings window. This is where we can set up the inputs we want to use in the game. In the “Add New Action” box, type the following, hitting <enter> after each to add it to the list of actions: right, left, up, down, shoot. To assign key(s) to each named input, click the + button to its right and press the key on your keyboard. When you’re done, you should have something like this:

    alt +alt

    Feel free to use other keys if you’d rather use a different setup.

    Next steps

    That takes care of setting up - now we’re ready to get started! In the next section, we’ll create the player-controlled spaceship.

    PrevNext
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_02/index.html b/docs/4.x/games/first_2d/first_2d_02/index.html index 0afa1574..3be66436 100644 --- a/docs/4.x/games/first_2d/first_2d_02/index.html +++ b/docs/4.x/games/first_2d/first_2d_02/index.html @@ -1,31 +1,31 @@ -Designing the Player Scene :: Godot 4 Recipes - +Designing the Player Scene :: Godot 4 Recipes +

    Designing the Player Scene

    In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.

    Setting up the Ship Scene

    A common part of the Godot workflow is creating scenes. As discussed earlier, a scene in Godot is nothing more than a collection of nodes. In most Godot projects, each game object is configured as a scene, with nodes that provide it with the desired functionality, and optionally some code to customize its behavior.

    Choosing nodes

    The first step is to decide what kind of node to start with. The first node you add to the scene is called the root node. A scene’s root node should generally be the one that primarily defines the game object’s behavior. Then you attach child nodes to add additional functionality.

    So what should our game’s ship be? Let’s break down the requirements, and look at what nodes might be useful to meet them.

    The ship needs to:

    • Move in 2D space. For this, a basic Node2D would suffice, as that’s the node that has position, rotation, and other 2D-related properties. However, it has no appearance.

    • Display an image. Sprite2D is the node for this. Since it’s also a Node2D, we’d still be able to move it around.

    • Detect getting hit. The enemies will be shooting and flying around on the screen, so we’ll need to know when the ship is hit. We don’t have a need for solid objects - they’re not going to bounce off each other or transfer momentum - we just need to know when they touch. For this, an Area2D would be perfect. It can detect touching other objects, has positional properties, but it has no appearance of its own.

    Looking at this list, the Area2D provides the main functionality. We can attach a Sprite2D to display the ship image, and then we’ll have everything we need.

    Building the scene

    In the Scene tab, click the + button or the + Other Node button to add the first node. Start typing Area2D and choose it from the list. Once it’s in the Scene tab, click the node’s name to rename it to Player, and press <Ctrl+S> to save the scene.

    Displaying the ship

    With the Player node selected, add another node: a Sprite2D. To keep things organized, let’s rename this node to Ship.

    From the FileSystem tab, drag the Player_ship (16x16).png file from the art pack and drop it in the Texture property of the Inspector.

    alt -alt

    The first thing you’ll notice is that there seem to be three ships! The image from the art pack also includes versions of the ship going to the left/right. We can use this - in the Animation section of the Inspector, set Hframes to 3. Now, changing the Frame property will move between the three different versions. Leave it at 1 for now.

    alt -alt

    Adding a collision shape

    You may also have noticed the yellow warning triangle on the Area2D node. If you click it, you’ll see the warning is telling us that the area doesn’t have a shape. We need to define its shape, and we can do that by adding a CollisionShape2D node as a child of the Player.

    In the Inspector for this node, you’ll see a Shape property that currently shows <empty>. If you click in this box, you’ll see a dropdown that allows you to select from a variety of shapes. Choose New RectangleShape2D and you’ll see a light blue square appear over the ship. You can adjust the size of the shape by dragging the orange circles, or you can click on the shape in the Shape property to expand it and fill in the Size manually.

    alt -alt

    Exhaust

    The ship will look much more dynamic with a little animation. Included in the art pack are some animations of exhaust flames named “Boosters”. There are three: one for each version of the ship (left, forward, and right).

    To display these, select the Ship node and add a child AnimatedSprite2D node and name it “Boosters”.

    In the Inspector, under the Animation section, you’ll find a property called Sprite Frames, which is currently <empty>. Click it to create a New SpriteFrames, then click the SpriteFrames item to open the animation panel at the bottom of the editor window.

    alt -alt

    Double-click the “default” animation to rename it to “forward”. Then, to add the animation images, click the Add frames from sprite sheet button:

    alt -alt

    Choose the Boosters (16 x 16).png image and you’ll see the Select Frames window, allowing you to choose the frames you want.

    alt -alt

    There are only two frames in this animation, but the grid isn’t correct. Change the Size values to match the image sizes: 16 x 16. Then, click both frames to select them and click the Add 2 Frame(s) button.

    alt -alt

    Now that you’ve added the two frames, press the Play button to run the animation. You can also toggle the Autoplay on Load button so that the animation will start automatically.

    alt -alt

    It’s a little slow, so change the speed to 10 FPS.

    Add two more animations by clicking the Add Animation button, naming them left and right.

    alt -alt

    Repeat the process, adding the left and right “Booster” sprite sheets.

    Gun cooldown

    The last node we’ll need to complete the player setup is a Timer to control how fast the player can shoot. Add the Timer as a child of Player and name it GunCooldown. Set its One Shot property to “On”. This means that when the timer ends, it won’t automatically restart. In the player’s code, we’ll start the timer when the player shoots, and they won’t be able to shoot again until the timer runs out.

    Next steps

    That completes the player scene setup. We’ve added the nodes to give the player ship the functionality it will need in the game. In the next section, we’ll add some code to enable the player to control the ship, make it shoot, and detect when it collides with things.

    +

    Designing the Player Scene

    In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.

    Setting up the Ship Scene

    A common part of the Godot workflow is creating scenes. As discussed earlier, a scene in Godot is nothing more than a collection of nodes. In most Godot projects, each game object is configured as a scene, with nodes that provide it with the desired functionality, and optionally some code to customize its behavior.

    Choosing nodes

    The first step is to decide what kind of node to start with. The first node you add to the scene is called the root node. A scene’s root node should generally be the one that primarily defines the game object’s behavior. Then you attach child nodes to add additional functionality.

    So what should our game’s ship be? Let’s break down the requirements, and look at what nodes might be useful to meet them.

    The ship needs to:

    • Move in 2D space. For this, a basic Node2D would suffice, as that’s the node that has position, rotation, and other 2D-related properties. However, it has no appearance.

    • Display an image. Sprite2D is the node for this. Since it’s also a Node2D, we’d still be able to move it around.

    • Detect getting hit. The enemies will be shooting and flying around on the screen, so we’ll need to know when the ship is hit. We don’t have a need for solid objects - they’re not going to bounce off each other or transfer momentum - we just need to know when they touch. For this, an Area2D would be perfect. It can detect touching other objects, has positional properties, but it has no appearance of its own.

    Looking at this list, the Area2D provides the main functionality. We can attach a Sprite2D to display the ship image, and then we’ll have everything we need.

    Building the scene

    In the Scene tab, click the + button or the + Other Node button to add the first node. Start typing Area2D and choose it from the list. Once it’s in the Scene tab, click the node’s name to rename it to Player, and press <Ctrl+S> to save the scene.

    Displaying the ship

    With the Player node selected, add another node: a Sprite2D. To keep things organized, let’s rename this node to Ship.

    From the FileSystem tab, drag the Player_ship (16x16).png file from the art pack and drop it in the Texture property of the Inspector.

    alt +alt

    The first thing you’ll notice is that there seem to be three ships! The image from the art pack also includes versions of the ship going to the left/right. We can use this - in the Animation section of the Inspector, set Hframes to 3. Now, changing the Frame property will move between the three different versions. Leave it at 1 for now.

    alt +alt

    Adding a collision shape

    You may also have noticed the yellow warning triangle on the Area2D node. If you click it, you’ll see the warning is telling us that the area doesn’t have a shape. We need to define its shape, and we can do that by adding a CollisionShape2D node as a child of the Player.

    In the Inspector for this node, you’ll see a Shape property that currently shows <empty>. If you click in this box, you’ll see a dropdown that allows you to select from a variety of shapes. Choose New RectangleShape2D and you’ll see a light blue square appear over the ship. You can adjust the size of the shape by dragging the orange circles, or you can click on the shape in the Shape property to expand it and fill in the Size manually.

    alt +alt

    Exhaust

    The ship will look much more dynamic with a little animation. Included in the art pack are some animations of exhaust flames named “Boosters”. There are three: one for each version of the ship (left, forward, and right).

    To display these, select the Ship node and add a child AnimatedSprite2D node and name it “Boosters”.

    In the Inspector, under the Animation section, you’ll find a property called Sprite Frames, which is currently <empty>. Click it to create a New SpriteFrames, then click the SpriteFrames item to open the animation panel at the bottom of the editor window.

    alt +alt

    Double-click the “default” animation to rename it to “forward”. Then, to add the animation images, click the Add frames from sprite sheet button:

    alt +alt

    Choose the Boosters (16 x 16).png image and you’ll see the Select Frames window, allowing you to choose the frames you want.

    alt +alt

    There are only two frames in this animation, but the grid isn’t correct. Change the Size values to match the image sizes: 16 x 16. Then, click both frames to select them and click the Add 2 Frame(s) button.

    alt +alt

    Now that you’ve added the two frames, press the Play button to run the animation. You can also toggle the Autoplay on Load button so that the animation will start automatically.

    alt +alt

    It’s a little slow, so change the speed to 10 FPS.

    Add two more animations by clicking the Add Animation button, naming them left and right.

    alt +alt

    Repeat the process, adding the left and right “Booster” sprite sheets.

    Gun cooldown

    The last node we’ll need to complete the player setup is a Timer to control how fast the player can shoot. Add the Timer as a child of Player and name it GunCooldown. Set its One Shot property to “On”. This means that when the timer ends, it won’t automatically restart. In the player’s code, we’ll start the timer when the player shoots, and they won’t be able to shoot again until the timer runs out.

    Next steps

    That completes the player scene setup. We’ve added the nodes to give the player ship the functionality it will need in the game. In the next section, we’ll add some code to enable the player to control the ship, make it shoot, and detect when it collides with things.

    PrevNext
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_03/index.html b/docs/4.x/games/first_2d/first_2d_03/index.html index dfc719a2..16491010 100644 --- a/docs/4.x/games/first_2d/first_2d_03/index.html +++ b/docs/4.x/games/first_2d/first_2d_03/index.html @@ -1,19 +1,19 @@ -Coding the Player :: Godot 4 Recipes - +Coding the Player :: Godot 4 Recipes +

    Coding the Player

    In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.

    Adding a script

    Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. Our Player scene displays the ship, defines its collision hitbox, etc., but it can’t move, and nothing would happen if it collided. We’ll write code to add this functionality to the ship.

    Select the Player node and click the Attach script button:

    alt -alt

    You don’t need to change any of the options on the Attach Node Script window, so just click Create and you’ll be taken to the script editor.

    Let’s look at the first line of the script, which has automatically been added.

    extends Area2D
    +

    Coding the Player

    In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.

    Adding a script

    Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. Our Player scene displays the ship, defines its collision hitbox, etc., but it can’t move, and nothing would happen if it collided. We’ll write code to add this functionality to the ship.

    Select the Player node and click the Attach script button:

    alt +alt

    You don’t need to change any of the options on the Attach Node Script window, so just click Create and you’ll be taken to the script editor.

    Let’s look at the first line of the script, which has automatically been added.

    extends Area2D
     

    This line defines what type of object this script should be attached to. It means that the script will have access to all the functionality that an Area2D provides.

    Your extends line should always match the type of node the script is attached to.

    Accessing scripts

    A script on its own doesn’t do much of anything. Scripts define additional functionality for whatever object they’re attached to. You will never be accessing a variable in some script, you’ll be accessing a property of an object, which is defined by that script. This is a very important distinction.

    Movement

    We’ll start by making the ship move around the screen. Let’s start with some code that does the following:

    • Detect what input(s) the player is pressing
    • Move the ship in the direction of the input
    @export var speed = 150
     
     func _process(delta):
         var input = Input.get_vector("left", "right", "up", "down")
         position += input * speed * delta
    -

    Let’s break this down line-by-line:

    • Adding @export in front of a variable allows you to adjust its value in the Inspector.

    alt -alt

    • The _process() function is called once every frame by the engine. Any code we place in this function will be executed every frame.
    • Input.get_vector() checks the pressed state of the four given inputs and produces a vector pointing in that direction.
    • Finally, we move the ship’s position by adding that input vector, scaling it to the desired speed, and multipling by delta.
    +

    Let’s break this down line-by-line:

    • Adding @export in front of a variable allows you to adjust its value in the Inspector.

    alt +alt

    • The _process() function is called once every frame by the engine. Any code we place in this function will be executed every frame.
    • Input.get_vector() checks the pressed state of the four given inputs and produces a vector pointing in that direction.
    • Finally, we move the ship’s position by adding that input vector, scaling it to the desired speed, and multipling by delta.

    Run the scene by clicking the Run Current Scene button, and try moving around.

    alt -alt

    Staying on screen

    One problem we have is that if you keep moving, you’ll go off the screen. We need to lock the player’s position property inside the bounds of the screen rectangle. Add this line at the top of the script:

    @onready var screensize = get_viewport_rect().size
    +Links to more information

    Run the scene by clicking the Run Current Scene button, and try moving around.

    alt +alt

    Staying on screen

    One problem we have is that if you keep moving, you’ll go off the screen. We need to lock the player’s position property inside the bounds of the screen rectangle. Add this line at the top of the script:

    @onready var screensize = get_viewport_rect().size
     

    The @onready here tells Godot not to set the value of the screensize variable until the Player node has entered the scene tree. Effectively, it means “wait until the game starts”, because there’s no window to get the size of until the game is running.

    The next step is to clamp the position within the bounds of that screensize rectangle. Vector2, which is what position is, has a clamp() method we can use. Put this line right after setting the position:

    func _process(delta):
         var input = Input.get_vector("left", "right", "up", "down")
         position += input * speed * delta
    @@ -37,17 +37,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_04/index.html b/docs/4.x/games/first_2d/first_2d_04/index.html index 5ec54f89..1ba754e3 100644 --- a/docs/4.x/games/first_2d/first_2d_04/index.html +++ b/docs/4.x/games/first_2d/first_2d_04/index.html @@ -1,5 +1,5 @@ -Bullet Scene :: Godot 4 Recipes - +Bullet Scene :: Godot 4 Recipes +

    Bullet Scene

    Now that the player can move around the screen, our next step will be to implement shooting

    Reusable objects

    The player will fire many “bullets” during the game, but all of them will be identical. A bullet needs to do the following:

    • Appear just ahead of the player
    • Travel forward until going off the screen
    • Detect collisions with enemies

    Since all bullets will do these same things, we can save ourselves a great deal of work by designing one “prototype” bullet, and using that as the blueprint for creating as many duplicates as we need. Godot’s scene system is ideal for this.

    Bullet scene

    Create a new scene by selecting Scene -> New Scene in the menu, or by clicking the + in the tabs on the top of the viewport.

    Just like we did with the Player scene, we need to consider what nodes we’ll need to make the bullet work. We can again use an Area2D, since that will allow us to detect the bullet hitting things. This means we’ll need a collision shape, and a sprite to display the bullet image. Finally, we need a way to detect when the bullet goes offscreen so we can automatically remove it.

    Here’s the node setup:

    • Area2D - name this Bullet
      • Sprite2D
      • CollisionShape2D
      • VisibleOnScreenNotifier2D

    From the asset pack folder, drop the Player_charged_beam (16 x 16).png image on the Texture of the Sprite2D.

    As with the ship image, there are multiple versions here, so set the *Hframes to 2 so we’ll only see one at a time.

    Set the shape of the CollisionShape2D just like you did earlier in the Player scene.

    Bullet script

    Attach a script to the Bullet node and let’s start with the movement:

    extends Area2D
     
    @@ -10,8 +10,8 @@
     
     func _process(delta):
         position.y += speed * delta
    -

    This should look fairly familiar, as it’s similar to the player script. We’re only changing the position.y since the bullet should travel straight up.

    Note the start() function we defined. That will let us set the bullet’s starting position, since the player will move around and spawn the bullets at different locations.

    Connecting signals

    Now select the Bullet node and then click the Node tab next to the Inspector.

    alt -alt

    This is a list of all the signals this node can emit. Signals are how Godot lets you know that something has happened. In this case, we can use the area_entered signal to tell us whenever this bullet touches another Area2D node.

    Select the area_entered signal and click the Connect… button (you can also double-click the signal name). In the dialog that opens up, just click Connect - we don’t need to change anything there.

    You’ll notice that you’re back in the script editor, looking at bullet.gd, and a new function as been added. It has a green “connected” icon next to its name to show that a signal is connected to it. This function will be called whenever the area touches something, so let’s add some code here:

    func _on_area_entered(area):
    +

    This should look fairly familiar, as it’s similar to the player script. We’re only changing the position.y since the bullet should travel straight up.

    Note the start() function we defined. That will let us set the bullet’s starting position, since the player will move around and spawn the bullets at different locations.

    Connecting signals

    Now select the Bullet node and then click the Node tab next to the Inspector.

    alt +alt

    This is a list of all the signals this node can emit. Signals are how Godot lets you know that something has happened. In this case, we can use the area_entered signal to tell us whenever this bullet touches another Area2D node.

    Select the area_entered signal and click the Connect… button (you can also double-click the signal name). In the dialog that opens up, just click Connect - we don’t need to change anything there.

    You’ll notice that you’re back in the script editor, looking at bullet.gd, and a new function as been added. It has a green “connected” icon next to its name to show that a signal is connected to it. This function will be called whenever the area touches something, so let’s add some code here:

    func _on_area_entered(area):
         if area.is_in_group("enemies"):
             area.explode()
             queue_free()
    @@ -22,17 +22,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_05/index.html b/docs/4.x/games/first_2d/first_2d_05/index.html index 9a5e695b..04a46902 100644 --- a/docs/4.x/games/first_2d/first_2d_05/index.html +++ b/docs/4.x/games/first_2d/first_2d_05/index.html @@ -1,5 +1,5 @@ -Shooting :: Godot 4 Recipes - +Shooting :: Godot 4 Recipes +

    Shooting

    The Bullet scene provides us with a reusable object we can instantiate whenever the player shoots.

    Adding to the player

    Let’s head back to the Player script and add a few new variables:

    @export var cooldown = 0.25
     @export var bullet_scene : PackedScene
    @@ -22,23 +22,23 @@
         shoot()
     

    We’ll also need to connect the timeout signal of GunCooldown.

    func _on_gun_cooldown_timeout():
         can_shoot = true
    -

    When the cooldown ends, we can allow shooting again.

    Go ahead and run the scene and try pressing the shoot action.

    alt -alt

    Adding instances to the tree

    Notice that we’ve added the new bullets as children of the SceneTree root (get_tree().root), and not to the player ship. This is important because if we made the bullets children of the ship, then they would be “attached” to it when it moves.

    Next steps

    Shooting’s no fun without something to shoot at. We’ll start making the enemies soon, but first we need a scene where we can bring the player, enemies, and other game objects together.

    +

    When the cooldown ends, we can allow shooting again.

    Go ahead and run the scene and try pressing the shoot action.

    alt +alt

    Adding instances to the tree

    Notice that we’ve added the new bullets as children of the SceneTree root (get_tree().root), and not to the player ship. This is important because if we made the bullets children of the ship, then they would be “attached” to it when it moves.

    Next steps

    Shooting’s no fun without something to shoot at. We’ll start making the enemies soon, but first we need a scene where we can bring the player, enemies, and other game objects together.

    PrevNext
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_06/index.html b/docs/4.x/games/first_2d/first_2d_06/index.html index aaaae496..00d73b4e 100644 --- a/docs/4.x/games/first_2d/first_2d_06/index.html +++ b/docs/4.x/games/first_2d/first_2d_06/index.html @@ -1,24 +1,24 @@ -Main Scene :: Godot 4 Recipes - +Main Scene :: Godot 4 Recipes +

    Main Scene

    Before we can make enemies, powerups, or any other game objects, we need a place where they can all exist together with the player. In most games, this would be called a “level” or “main” scene, and that’s what we’ll call it here.

    Start the scene with a Node2D called “Main” and save it.

    Creating the background

    Add a Sprite2D child. Name this sprite “Background” and add the Space_BG (2 frames) (64 x 64).png as its texture.

    This image has two frames, each 64x64 pixels in size. We’d like the image to tile across the full size of the screen, so start with the following settings:

    • Under Offset set Centered to “off”. This makes the image’s top left corner start at the origin rather than its center.

    • Under Region, turn Enabled “on”, and then set the Rect to a width of 240 and a height of 320. This makes the image stretch to the size of the screen.

    • Under Texture change Repeat to Enabled. This causes the image to repeat over the full size of the screen.

    Now add the player to the scene by selecting the Main node and clicking the Instantiate Child Scene button.

    alt -alt

    Animating the background

    We can make the scene more dynamic by animating the background. While we could do this in code by changing the region_rect property every frame, we’ll use an AnimationPlayer node instead; add one as a child of Main.

    At the bottom of the editor window, you’ll see the Animation panel. There’s a lot of information there, so let’s look at how it’s laid out:

    alt -alt

    Click the Animation button and choose New Animation. You can name the new animation scroll. Set its Length to 2 and toggle the Looping and Autoplay buttons.

    Animations work by adding tracks that represent properties that you want the AnimationPlayer to control. In the timeline of the player, you’ll add keyframes that define what value you want the property to have at that particular time.

    We can add keyframes to the animation by clicking the key icon that now appears next to every property in the Inspector. Make sure the scrubber (the blue indicator on the timeline) is at time 0, then select the Background and click the key next to Region/Rect. You’ll be asked if you want to create a new track and then you’ll see the new track added to the animation panel, with a small dot representing the keyframe you’ve just added. Drag the scrubber to time 2 and then change the y value of the Region/Rect property to 64. Click the key to add another keyframe.

    Now when you press Play on the animation, you should see the background slowly scrolling behind the player.

    Next steps

    The main scene is now ready for us to add enemies. In the next step we’ll make a single enemy scene, as we did with the bullets, and then instantiate that multiple times.

    +

    Main Scene

    Before we can make enemies, powerups, or any other game objects, we need a place where they can all exist together with the player. In most games, this would be called a “level” or “main” scene, and that’s what we’ll call it here.

    Start the scene with a Node2D called “Main” and save it.

    Creating the background

    Add a Sprite2D child. Name this sprite “Background” and add the Space_BG (2 frames) (64 x 64).png as its texture.

    This image has two frames, each 64x64 pixels in size. We’d like the image to tile across the full size of the screen, so start with the following settings:

    • Under Offset set Centered to “off”. This makes the image’s top left corner start at the origin rather than its center.

    • Under Region, turn Enabled “on”, and then set the Rect to a width of 240 and a height of 320. This makes the image stretch to the size of the screen.

    • Under Texture change Repeat to Enabled. This causes the image to repeat over the full size of the screen.

    Now add the player to the scene by selecting the Main node and clicking the Instantiate Child Scene button.

    alt +alt

    Animating the background

    We can make the scene more dynamic by animating the background. While we could do this in code by changing the region_rect property every frame, we’ll use an AnimationPlayer node instead; add one as a child of Main.

    At the bottom of the editor window, you’ll see the Animation panel. There’s a lot of information there, so let’s look at how it’s laid out:

    alt +alt

    Click the Animation button and choose New Animation. You can name the new animation scroll. Set its Length to 2 and toggle the Looping and Autoplay buttons.

    Animations work by adding tracks that represent properties that you want the AnimationPlayer to control. In the timeline of the player, you’ll add keyframes that define what value you want the property to have at that particular time.

    We can add keyframes to the animation by clicking the key icon that now appears next to every property in the Inspector. Make sure the scrubber (the blue indicator on the timeline) is at time 0, then select the Background and click the key next to Region/Rect. You’ll be asked if you want to create a new track and then you’ll see the new track added to the animation panel, with a small dot representing the keyframe you’ve just added. Drag the scrubber to time 2 and then change the y value of the Region/Rect property to 64. Click the key to add another keyframe.

    Now when you press Play on the animation, you should see the background slowly scrolling behind the player.

    Next steps

    The main scene is now ready for us to add enemies. In the next step we’ll make a single enemy scene, as we did with the bullets, and then instantiate that multiple times.

    PrevNext
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_07/index.html b/docs/4.x/games/first_2d/first_2d_07/index.html index 86e51be8..4b1e2c14 100644 --- a/docs/4.x/games/first_2d/first_2d_07/index.html +++ b/docs/4.x/games/first_2d/first_2d_07/index.html @@ -1,5 +1,5 @@ -Enemies :: Godot 4 Recipes - +Enemies :: Godot 4 Recipes +

    Enemies

    Now that our player can shoot, let’s give them something to shoot at.

    Setting up the scene

    We’ll use an Area2D for the enemy, since we need it to detect overlap - either with the player’s bullets, or with the player itself.

    Here’s are the nodes we’ll need:

    Enemy:  Area2D
          Sprite2D
    @@ -7,8 +7,8 @@
          AnimationPlayer
         MoveTimer:  Timer
         ShootTimer:  Timer
    -

    Select the area node and click the Node tab next to the Inspector. Under Groups, type “enemies” an click Add. Remember the code we wrote on the bullet? It looks for objects in the “enemies” group.

    In the sprite’s Texture, add Bon_Bon (16 x 16).png and set its Animation/Hframes to 4.

    As you’ve done before, add a rectangular collision shape and size it to fit. Enable One Shot on both timer nodes.

    In the AnimationPlayer, add an animation called “bounce” and set it to looping and autoplay. Set the Snap at the bottom of the animation panel to 0.05.

    Select the sprite node and press the key icons next to Texture and Hframes to create tracks for them. We’re doing this because later we’ll add an “explosion” animation that will use different values for these properties.

    Now we’ll key the individual Frames values we want. Start with keying Frames each .1 seconds to values in this order2, 1, 0, 3. Finally, key 0 again and put it immediately after. This will make a “pulsing” animation where the sprite grows and then bounces a little at the end. The animation setup should look like this:

    alt -alt

    Press the play button to see it in action. Feel free to adjust it if you’d like.

    Now add another animation called “explode”. Set its length to 0.4 seconds.

    Change the sprite’s Texture to Explosion (16 x 16).png and keyframe that property. Since this image has a different number of frames than the enemy image, we also need to change Hframes to 6 and keyframe that.

    Now keyframe Frame to 0 at time 0 and to 5 at time 0.4. Play the animation to see it in action.

    Enemy script

    The enemies will spawn at the top of the screen in a grid. After a random amount of time, they’ll descend toward the player and then return to the top if they weren’t destroyed. Periodically, they’ll also shoot at the player.

    Add a script, and start with the variables:

    extends Area2D
    +

    Select the area node and click the Node tab next to the Inspector. Under Groups, type “enemies” an click Add. Remember the code we wrote on the bullet? It looks for objects in the “enemies” group.

    In the sprite’s Texture, add Bon_Bon (16 x 16).png and set its Animation/Hframes to 4.

    As you’ve done before, add a rectangular collision shape and size it to fit. Enable One Shot on both timer nodes.

    In the AnimationPlayer, add an animation called “bounce” and set it to looping and autoplay. Set the Snap at the bottom of the animation panel to 0.05.

    Select the sprite node and press the key icons next to Texture and Hframes to create tracks for them. We’re doing this because later we’ll add an “explosion” animation that will use different values for these properties.

    Now we’ll key the individual Frames values we want. Start with keying Frames each .1 seconds to values in this order2, 1, 0, 3. Finally, key 0 again and put it immediately after. This will make a “pulsing” animation where the sprite grows and then bounces a little at the end. The animation setup should look like this:

    alt +alt

    Press the play button to see it in action. Feel free to adjust it if you’d like.

    Now add another animation called “explode”. Set its length to 0.4 seconds.

    Change the sprite’s Texture to Explosion (16 x 16).png and keyframe that property. Since this image has a different number of frames than the enemy image, we also need to change Hframes to 6 and keyframe that.

    Now keyframe Frame to 0 at time 0 and to 5 at time 0.4. Play the animation to see it in action.

    Enemy script

    The enemies will spawn at the top of the screen in a grid. After a random amount of time, they’ll descend toward the player and then return to the top if they weren’t destroyed. Periodically, they’ll also shoot at the player.

    Add a script, and start with the variables:

    extends Area2D
     
     var start_pos = Vector2.ZERO
     var speed = 0
    @@ -66,17 +66,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_08/index.html b/docs/4.x/games/first_2d/first_2d_08/index.html index 736fb630..54381190 100644 --- a/docs/4.x/games/first_2d/first_2d_08/index.html +++ b/docs/4.x/games/first_2d/first_2d_08/index.html @@ -1,5 +1,5 @@ -Enemy Shooting :: Godot 4 Recipes - +Enemy Shooting :: Godot 4 Recipes +

    Enemy Shooting

    Now that our enemy can shoot, let’s give them something to shoot at.

    Enemy bullet scene

    Make a new EnemyBullet scene just like you made the player bullet earlier. We won’t go into all the steps here, but you can refer back to that part if you’re stuck. The only difference here is that you can use the Enemy_projectile (16 x 16).png image instead.

    The script will be a little bit different:

    extends Area2D
     
    @@ -28,17 +28,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_09/index.html b/docs/4.x/games/first_2d/first_2d_09/index.html index 6bf24b9b..620f5710 100644 --- a/docs/4.x/games/first_2d/first_2d_09/index.html +++ b/docs/4.x/games/first_2d/first_2d_09/index.html @@ -1,14 +1,14 @@ -UI and Score :: Godot 4 Recipes - +UI and Score :: Godot 4 Recipes +

    UI and Score

    The last main piece of our game is the user interface (UI). We need a way to show the player the score and other information. To do this, we’ll use a variety of Control nodes - the nodes Godot provides for building UIs.

    UI scene

    Start the scene with a MarginContainer and name it UI.

    Containers are Control nodes that are designed to control the size and position of their children. Using them makes it easier to position and move Control nodes without having to do it manually. The MarginContainer makes sure its children don’t get too close to the edge.

    In the Inspector under Theme Overrides/Constants set all four Margin values to 10. Then, in the menu bar at the top of the viewport, set the anchors to the Top Wide preset.

    alt -alt

    Next, we’ll add an HBoxContainer. This type of container organizes its children horizontally. Under that, add a TextureProgressBar, which will represent our ship’s shield level. Name it ShieldBar.

    Unfortunately, there’s not a good image in the art pack to use for a progress bar (there is one, but it isn’t formatted in an easy way to work with). Instead, we’ll use the two images below. One is a green bar and the other is a white outline. Save them in your project folder.

    alt -alt -alt -alt

    In the Texture section, drag the foreground image to the Progress and the background image to the Under texture. The first thing you’ll notice is that it’s very small. Let’s first under Layout set Custom Minimum Size to (80, 16). You’ll notice that the orange selection rectangle got bigger, but the image didn’t. Well, we don’t want the image to just stretch, or it would look bad. Instead we’ll check the Nine Patch Stretch box, and then set the four Stretch Margin values to 3.

    You should now see a long, unfilled bar. To see what it looks like when filled, change the Value property in the Range section to anything between 0 and 100.

    alt -alt

    On the right side, we’d like to show the score. Now, we could just use a Label node and add a font, but that’s not very fun. The art pack includes a lovely pixel set of digits that we could use instead. We’ll just need to do a little coding to chop it up and show the corect digit(s).

    Score counter

    Start a new scene and add an HBoxContainer. Name it ScoreCounter then set it to Top Wide and set the Alignment to “End”. Also, set the Theme Overrides/Constants/Separation to 0 (you need to check the box next to the property).

    In this container, we’ll have a string of TextureRect nodes showing each digit. We’ll start by adding one and then duplicating it.

    Name the TextureRect Digit0. Under Texture, select “New AtlasTexture”, then click the box to open it. Drag Number_font (8 x 8).png into the Atlas property, then set the Region to (32, 8, 8, 8). Set Stretch Mode to “Keep Aspect Centered”.

    Select the Digit0 node and press Ctrl-D 7 times to create duplicates of the node. The picture below shows what you should see after this step:

    alt -alt

    We now have an issue, though. Even though we’ve duplicated the TextureRect to create 8 unique copies, they are all using the same AtlasTexture in the Texture property. This means that when we change the Region to show a different digit, it will change on all the digits.

    This is because Resource objects (such as Texture) are loaded into memory and then shared - there’s really only one texture. While this is very efficient, because you don’t waste memory loading the same image multiple times, it means that when we do want things to be unique, we have to specify it.

    On each of the nodes, click the down arrow next to the AtlasTexture and select “Make Unique”.

    alt -alt

    Now we’ll add a script to ScoreCounter that will choose the correct Region values for whichever digit it needs to display.

    extends HBoxContainer
    +

    UI and Score

    The last main piece of our game is the user interface (UI). We need a way to show the player the score and other information. To do this, we’ll use a variety of Control nodes - the nodes Godot provides for building UIs.

    UI scene

    Start the scene with a MarginContainer and name it UI.

    Containers are Control nodes that are designed to control the size and position of their children. Using them makes it easier to position and move Control nodes without having to do it manually. The MarginContainer makes sure its children don’t get too close to the edge.

    In the Inspector under Theme Overrides/Constants set all four Margin values to 10. Then, in the menu bar at the top of the viewport, set the anchors to the Top Wide preset.

    alt +alt

    Next, we’ll add an HBoxContainer. This type of container organizes its children horizontally. Under that, add a TextureProgressBar, which will represent our ship’s shield level. Name it ShieldBar.

    Unfortunately, there’s not a good image in the art pack to use for a progress bar (there is one, but it isn’t formatted in an easy way to work with). Instead, we’ll use the two images below. One is a green bar and the other is a white outline. Save them in your project folder.

    alt +alt +alt +alt

    In the Texture section, drag the foreground image to the Progress and the background image to the Under texture. The first thing you’ll notice is that it’s very small. Let’s first under Layout set Custom Minimum Size to (80, 16). You’ll notice that the orange selection rectangle got bigger, but the image didn’t. Well, we don’t want the image to just stretch, or it would look bad. Instead we’ll check the Nine Patch Stretch box, and then set the four Stretch Margin values to 3.

    You should now see a long, unfilled bar. To see what it looks like when filled, change the Value property in the Range section to anything between 0 and 100.

    alt +alt

    On the right side, we’d like to show the score. Now, we could just use a Label node and add a font, but that’s not very fun. The art pack includes a lovely pixel set of digits that we could use instead. We’ll just need to do a little coding to chop it up and show the corect digit(s).

    Score counter

    Start a new scene and add an HBoxContainer. Name it ScoreCounter then set it to Top Wide and set the Alignment to “End”. Also, set the Theme Overrides/Constants/Separation to 0 (you need to check the box next to the property).

    In this container, we’ll have a string of TextureRect nodes showing each digit. We’ll start by adding one and then duplicating it.

    Name the TextureRect Digit0. Under Texture, select “New AtlasTexture”, then click the box to open it. Drag Number_font (8 x 8).png into the Atlas property, then set the Region to (32, 8, 8, 8). Set Stretch Mode to “Keep Aspect Centered”.

    Select the Digit0 node and press Ctrl-D 7 times to create duplicates of the node. The picture below shows what you should see after this step:

    alt +alt

    We now have an issue, though. Even though we’ve duplicated the TextureRect to create 8 unique copies, they are all using the same AtlasTexture in the Texture property. This means that when we change the Region to show a different digit, it will change on all the digits.

    This is because Resource objects (such as Texture) are loaded into memory and then shared - there’s really only one texture. While this is very efficient, because you don’t waste memory loading the same image multiple times, it means that when we do want things to be unique, we have to specify it.

    On each of the nodes, click the down arrow next to the AtlasTexture and select “Make Unique”.

    alt +alt

    Now we’ll add a script to ScoreCounter that will choose the correct Region values for whichever digit it needs to display.

    extends HBoxContainer
     
     var digit_coords = {
         1: Vector2(0, 0),
    @@ -63,23 +63,23 @@
         if area.name == "Player":
             queue_free()
             area.shield -= 1
    -

    Finally, we need to connect the player’s shield_changed signal to the function in the UI that updates the shield bar. You can do this in the Inspector by selecting the Player node in the Main scene. Under the Node tab, double-click the shield_changed signal to open the “Connect a Signal” window. In this window, select the UI node and type update_shield in the Receiver Method box.

    alt -alt

    Run the game again and check that your shield depletes when you get hit by a bullet or an enemy.

    Next steps

    We’re almost done with the basic functionality. We just need a way to start and end the game.

    +

    Finally, we need to connect the player’s shield_changed signal to the function in the UI that updates the shield bar. You can do this in the Inspector by selecting the Player node in the Main scene. Under the Node tab, double-click the shield_changed signal to open the “Connect a Signal” window. In this window, select the UI node and type update_shield in the Receiver Method box.

    alt +alt

    Run the game again and check that your shield depletes when you get hit by a bullet or an enemy.

    Next steps

    We’re almost done with the basic functionality. We just need a way to start and end the game.

    PrevNext
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_10/index.html b/docs/4.x/games/first_2d/first_2d_10/index.html index 23a74317..71801419 100644 --- a/docs/4.x/games/first_2d/first_2d_10/index.html +++ b/docs/4.x/games/first_2d/first_2d_10/index.html @@ -1,5 +1,5 @@ -Starting and Ending the Game :: Godot 4 Recipes - +Starting and Ending the Game :: Godot 4 Recipes +

    Starting and Ending the Game

    Our last step is to add a start button and a “game over” state to the game.

    Starting the game

    Currently when we run the game, it starts immediately. Let’s add a button to start it.

    In Main as a child of the CanvasLayer, add a CenterContainer and set its layout to Full Rect. Then add a TextureButton child. Name this button Start and add the START (48 x 8).png image as its Normal texture.

    Add a reference at the top of the script:

    @onready var start_button = $CanvasLayer/CenterContainer/Start
     

    Connect this button’s pressed texture to Main and add this code:

    func _on_start_pressed():
    @@ -25,17 +25,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/first_2d_end/index.html b/docs/4.x/games/first_2d/first_2d_end/index.html index ec6d41df..3c4d0613 100644 --- a/docs/4.x/games/first_2d/first_2d_end/index.html +++ b/docs/4.x/games/first_2d/first_2d_end/index.html @@ -1,20 +1,20 @@ -Wrapping up :: Godot 4 Recipes - +Wrapping up :: Godot 4 Recipes +

    Wrapping up

    If you’ve been following along, you’ve learned a lot of the fundamentals of building games in Godot. We’re going to end the tutorial here, since we’ve completed the basic game.

    The secret to learning effectively

    Here’s my big secret for getting the most out of tutorials like this and others you may find online. At the end, once you’ve finished building the project, immediately delete it and start over. This time, try and re-create it without looking at the tutorial. If you get stuck, look at just that part, then close it again.

    It may sound repetitive, but that is how we learn: by doing things repeatedly. If you follow this tip, you’ll be amazed at how quickly you level up your gamedev skills.

    Adding to the game

    If you’re feeling comfortable with the techniques used to make this game, then you’re ready to branch out. Try adding a single new feature to this game.

    If you’re stuck coming up with an idea, here are some suggestions:

    • Additional enemy types - there is art for other enemies in the art pack. How do they move and shoot?

    • Waves - make more enemies spawn every time you clear the screen

    • Boss enemies - what if a big enemy appears?

    • Boosts - powerups could appear for the player to collect. There’s some art for those too.

      • Shield recharge - collect these to power up the shield
      • Weapon upgrades - shoot more bullets, patterns, etc.
    • Sound and music - give everything a lot more personality with some sound effects and background music.

    Learning more

    Ready for more? Here are some suggestions for your next learning adventure:

    • Godot 101: Getting started in 3D - if you’re interested in making things in 3D, check out this introduction to Godot’s 3D features.

    • Check out the rest of the content on this website. There are lots of examples, tutorials, and code snippets to help you learn how to make your dream game.

    Download This Project on GitHub

    Download the project code here:

    https://github.com/godotrecipes/8_direction_animation

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/games/first_2d/index.html b/docs/4.x/games/first_2d/index.html index 1e6f8ed1..b0daa436 100644 --- a/docs/4.x/games/first_2d/index.html +++ b/docs/4.x/games/first_2d/index.html @@ -1,21 +1,21 @@ -Your First 2D Game :: Godot 4 Recipes - +Your First 2D Game :: Godot 4 Recipes +

     Your First 2D Game

    Get started with Godot by building a 2D shooter.

    In this series, we’ll start with the basics and build a classic, old-school space shooter.

    Here’s a screenshot of the finished game:

    alt -alt

    In each part of the series, we’ll build a piece of the game, adding features and explaining the process along the way.

    Background

    If you find that you’re struggling with the programming side of things, see these resources:

    Download This Project on GitHub

    Download the project code here:

    https://github.com/godotrecipes/classic_shmup

    + + \ No newline at end of file diff --git a/docs/4.x/games/index.html b/docs/4.x/games/index.html index 8a8c331e..da9f290f 100644 --- a/docs/4.x/games/index.html +++ b/docs/4.x/games/index.html @@ -1,19 +1,19 @@ -Game Tutorials :: Godot 4 Recipes - +Game Tutorials :: Godot 4 Recipes +

     Games

    Demo games and tutorials.

    Updating to Godot 4.0

    We’re working on new content for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.

    In this section:

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/index.html b/docs/4.x/index.html index 20570510..66e0673f 100644 --- a/docs/4.x/index.html +++ b/docs/4.x/index.html @@ -1,22 +1,22 @@ -Home :: Godot 4 Recipes - +Home :: Godot 4 Recipes +

     Godot Recipes

    Godot’s nodes are your ingredients. What can you cook up?

    On this site you’ll find a collection of solutions and examples to help you make whatever game system you need.

    Godot 4.0

    Godot 4.0 has been released!
    Godot 4.0 is the latest stable release version of the engine.
    There is a limited amount of learning material available, so if you’re looking to make a game or learn the engine, we recommend you stick with 3.x for now. Don’t worry - what you learn will still apply when you’re ready to move to the newer version!
    This site has lots of learning material for Godot 3 - but not all of it has been updated for version 4 yet. You can click the ribbon in the top-right to toggle the Godot Recipes version, or click the button below:

    -Godot 3 Recipes

    Are you ready to learn game development? Whether it’s as a hobby or working towards your dream career, there’s never been a better time to get started. Modern programming languages and tools have made it easier than ever to build high-quality games and distribute them to the world. One of these tools is the Godot game engine. For beginners, it offers a friendly way to learn gamedev techniques. For experienced developers, it’s a powerful, customizable and open tool for bringing your visions to life.

    alt -alt

    On this site you’ll find a gentle introduction to the Godot game engine, as well as a wide variety of gamedev tips and techniques. Feel free to browse the categories in the sidebar and see what catches your interest.

    If you’re new to Godot, start here: What is Godot?.

    How to use this site

    Beginners

    If you’re new to game development, start with the “Godot 101: Basics” section. There you’ll find an introduction to the Godot application, and a step-by-step guide to creating your first project. There is a lot of material to absorb here. Don’t feel discouraged if you feel you don’t get it at first. Repetition is the key to learning complex topics; the more you work with Godot’s features, the more familiar and easy they will start to feel.

    Info

    It’s assumed that you have at least some general programming experience. If you’re completely new to programming, click here for tips on how to get started.

    Experienced Developers

    If you’re an experienced developer and/or you’re familiar with other modern game engine(s), feel free to explore the menu on the left. You’ll find a number of useful guides and tutorials to show you how to do things the “Godot Way”. Code samples and example projects are available for all articles.

    + + \ No newline at end of file diff --git a/docs/4.x/index.json b/docs/4.x/index.json index 0081d953..7b30aaa9 100644 --- a/docs/4.x/index.json +++ b/docs/4.x/index.json @@ -1 +1 @@ -[{"content":" Godot 101 Your introduction to the Godot game engine. If you’ve never used a game engine before, or if you’re just new to Godot, this is the place to start.\nIn this section: Getting Started Introduction to GDScript Intro to 3D See also: Game Tutorials/Your First 2D Game ","description":"","tags":null,"title":"Godot 101","uri":"/godot_recipes/4.x/g101/index.html"},{"content":"Problem You’ve tried adding an AudioStreamPlayer to your mob/coin/etc. to play when the object dies or is collected. But the problem is that when you remove the object, the audio player goes with it, chopping off the sound. You need an easier way to manage playing audio.\nSolution We’ll solve this problem with a node that is available from anywhere in the SceneTree. This node manages a set of AudioStreamPlayer nodes and a queue of sound streams to play.\nCreate a new script in the script editor.\nextends Node var num_players = 8 var bus = \"master\" var available = [] # The available players. var queue = [] # The queue of sounds to play. func _ready(): # Create the pool of AudioStreamPlayer nodes. for i in num_players: var p = AudioStreamPlayer.new() add_child(p) available.append(p) p.finished.connect(_on_stream_finished.bind(p)) p.bus = bus func _on_stream_finished(stream): # When finished playing a stream, make the player available again. available.append(stream) func play(sound_path): queue.append(sound_path) func _process(delta): # Play a queued sound if any players are available. if not queue.empty() and not available.empty(): available[0].stream = load(queue.pop_front()) available[0].play() available.pop_front() Set this script as an autoload in Project Settings. Give it an easily recognizable name, such as “AudioStreamManager”.\nAnywhere in your project that you want to play a sound, use:\nAudioStreamManager.play(\"res://path/to/sound\") Note This audio manager is adapted with thanks from [SFXPlayer by TheDuriel] (https://github.com/TheDuriel/DurielsGodotUtilities).\nExample project Below you can download an example project showing the use of the audio manager node. This project reads a folder full of audio files and generates a grid of buttons. Click the button to play the sound.\nAt the top, you can see the audio manager’s live statistics.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/audio_manager\n","description":"","tags":null,"title":"Audio Manager","uri":"/godot_recipes/4.x/audio/audio_manager/index.html"},{"content":"Problem You want an enemy to chase the player.\nSolution The first step in getting an enemy to chase the player is to determine what direction the enemy needs to move. To get the vector pointing from A to B, you subtract: B - A. Normalize the result and you have a direction vector.\nThis makes the solution quite straightforward. Every frame, set the enemy’s velocity to point in the direction of the player.\nvelocity = (player.position - position).normalized() * speed Godot’s Vector2 object has a built-in helper for this:\nvelocity = position.direction_to(player.position) * speed However, this would allow the enemy to chase the player from any distance, even if it’s far away. To fix this, we can add an Area2D to the enemy, and only chase the player when it’s inside this “detect radius”.\nHere’s some example code:\nextends CharacterBody2D var run_speed = 25 var player = null func _physics_process(delta): velocity = Vector2.ZERO if player: velocity = position.direction_to(player.position) * run_speed move_and_slide() func _on_DetectRadius_body_entered(body): player = body func _on_DetectRadius_body_exited(body): player = null We’ve connected the body_entered and body_exited signals from the Area2D so that the enemy knows whether it’s in range or not.\nNote The above assumes that the player is the only body that will enter/exit, which is usually done by setting the appropriate collision layers/masks.\nThis concept can be extended to other types of games as well. The key is to find the direction vector from the enemy to the player:\nIf, for example, your game is a side-scroller or has other constraints in movement, you can use only the x component of the resulting vector to determine movement.\nLimitations Note that this method results in very simplistic straight-line movement. The enemy will not move around obstacles such as walls, nor will it stop if it gets too close to the player.\nWhat to do when the enemy gets close to the player depends on your game. You could add a second, smaller area that causes the enemy to stop and attack, or you could knockback the player on contact.\nAnother problem is more apparent with fast-moving enemies. As the player moves, the enemies using this technique will change direction instantly. For a more natural-looking movement, you might want to use a steering behavior.\nFor more advanced behaviors, see the other recipes in this chapter.\nRelated recipes Top-down movement Homing missile ","description":"","tags":null,"title":"Chasing the player","uri":"/godot_recipes/4.x/ai/chasing/index.html"},{"content":"Problem You want to detect when an object enters or exits the screen.\nSolution The engine provides a node for this: VisibleOnScreenNotifier2D. Attach this node to your object, and you’ll be able to use its screen_entered and screen_exited signals. *\nExample 1 Consider a projectile that travels in a straight line after it’s fired. If we continue firing, eventually we’ll have a large number of objects for the engine to track, event though they’re offscreen, which can cause lag.\nHere’s the movement code for the projectile:\nextends Area2D var velocity = Vector2(500, 0) func _process(delta): position += velocity * delta To have the projectile automatically deleted when it moves offscreen, add a VisibleOnScreenNotifier2D and connect its screen_exited signal.\nfunc _on_VisibleOnScreenNotifier2D_screen_exited(): queue_free() Example 2 We have an enemy that performs some actions, such as moving along a path or playing an animation. On a large map with many enemies, only a few of them will be onscreen at the same time. We can disable the enemy’s actions while it’s offscreen using VisibleOnScreenNotifier2D.\nPartial code:\nvar active = false func _process(delta): if active: play_animation() move() func _on_VisibleOnScreenNotifier2D_screen_entered(): active = true func _on_VisibleOnScreenNotifier2D_screen_exited(): active = false ","description":"","tags":null,"title":"Entering/Exiting the screen","uri":"/godot_recipes/4.x/2d/enter_exit_screen/index.html"},{"content":"Here you can find the most recently added recipes:\nMultitarget Camera Character to Rigid Body Interaction CharacterBody3D: Align with Surface CharacterBody3D: Movement Arcade-style Car Pathfinding on a 2D Grid Migrating from 3.x Shooting with Raycasts Basic FPS Character RigidBody2D: Drag and Drop 2D Car Steering 3D Healthbars Grid-based Movement Arcade-style 3D Spaceship Interpolated Camera Platform Character ","description":"","tags":null,"title":"Fresh Recipes","uri":"/godot_recipes/4.x/recent/index.html"},{"content":"Overview Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. For example, a Sprite2D node automatically displays an image, but to move it across the screen, you’ll add a script that tells it how fast, in what direction, and so on.\nYou can think of it as the coding version of using the Inspector - GDScript knows all about Godot nodes and how to access them, plus it allows you to change them dynamically.\nGDScript is Godot’s built-in language for scripting and interacting with nodes. The GDScript documentation on the Godot website is a great place to get an overview of the language, and I highly recommend taking the time to read through it.\nIs GDScript Python?\nYou’ll often read comments to the effect that “GDScript is based on Python”. That’s somewhat misleading; GDScript uses a syntax that’s modeled on Python’s, but it’s a distinct language that’s optimized for and integrated into the Godot engine. That said, if you already know some Python, you’ll find GDScript looks very familiar.\nWarning Many tutorials (and Godot in general) assume that you have at least some programming experience already. If you’ve never coded before, you’ll likely find learning Godot to be a challenge. Learning a game engine is a large task on its own; learning to code at the same time means you’re taking on a lot. If you find yourself struggling with the code in this section, you may find that working through an introductory programming lesson (Python is a good option) will help you grasp the basics.\nStructure of a script The first line of any GDScript file must be extends \u003cClass\u003e, where \u003cClass\u003e is some existing built-in or user-defined class. For example, if you’re attaching a script to a CharacterBody2D node, then your script would start with extends CharacterBody2D. This states that your script is taking all the functionality of the built-in CharacterBody2D object and extending it with additional functionality created by you.\nIn the rest of the script, you can define any number of variables (aka “class properties”) and functions (aka “class methods”).\nCreating a script Let’s make our first script. Remember, any node can have a script attached to it.\nOpen the editor and add a Sprite2D node to empty scene. Right-click on the new node, and choose “Attach Script”. You can also click the button next to the search box.\nNext you need to decide where you want the script saved and what to call it. If you’ve named the node, the script will automatically be named to match it (so unless you’ve changed anything this script will likely be called “sprite2d.gd”).\nNow the script editor window opens up, and this is your new, empty sprite script. Godot has automatically included some lines of code, as well as some comments describing what they do.\nextends Sprite2D # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass Since the script was added to a Sprite2D, the first line is automatically set to extends Sprite2D. Because this script extends the Sprite2D class, it will be able to access and manipulate all the properties and methods that a Sprite2D node provides.\nProperties and methods Properties and methods are two terms which specifically mean variables and functions that are defined in an object. Programmers tend to use the terms interchangeably.\nAfter that is where you’re going to define all the variables you will use in the script, the “member variables”. You define variables with the ‘var’ keyword - as you can see by the comment examples.\nGo ahead and delete the comments and let’s talk about this next piece.\nNow we see a function called _ready(). In GDScript you define a function with the keyword “func”. The _ready() function is a special one that Godot looks for and runs whenever a node is added to the tree, for example when we hit “Play”.\nLet’s say that when the game starts, we want to make sure the sprite goes to a particular location. In the Inspector, we want to set the Position property. Notice that it’s in the section called “Node2D” - that means this is a property that any Node2D type node will have, not just Sprite2Ds.\nHow do we set the property in code? One way to find the name of the property is by hovering over it in the Inspector.\nGodot has a great built-in help/reference tool. Click on “Classes” at the top of the Script window and search for Node2D and you’ll see a help page showing you all the properties and methods the class has available. Looking down a bit you can see position in the “Member Variables” section - that’s the one we want. It also tells us the property is of the type “Vector2”.\nLet’s go back to the script and use that property:\nfunc _ready(): position = Vector2(100, 150) Notice how the editor is making suggestions as you type. Godot uses vectors for lots of things, and we’ll talk more about them later. For now, let’s type Vector2, and the hint tells us to put two floats for x and y.\nNow we have a script that says “When this sprite starts, set its position to (100, 150)”. We can try this out by pressing the “Play Scene” button.\nLearning tip When first learning to code, beginners often ask “How do you memorize all these commands?” Just like any other skill, it’s not a matter of memorization, it’s about practice. As you use things more, the things you do frequently will “stick” and become automatic. Until then, it’s a great idea to keep the reference docs handy. Use the search function whenever you see something you don’t recognize. If you have multiple monitors, keep a copy of the web docs open on the side for quick reference.\nWrapping up Congratulations on making your first script in GDScript! Before moving on, make sure you understand everything we did in this step. In the next part, we’ll add some more code to move the sprite around the screen.\n","description":"","tags":null,"title":"Getting started","uri":"/godot_recipes/4.x/g101/gdscript/gdscript_01/index.html"},{"content":"Getting Started Have you downloaded Godot yet? You can get it here:\nhttps://godotengine.org\nUpdating to Godot 4.0 We’re working on a new version of Godot 101 for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: What is Godot? The Godot Editor: Finding your way around Nodes: Godot's building blocks ","description":"","tags":null,"title":"Getting Started","uri":"/godot_recipes/4.x/g101/start/index.html"},{"content":"Problem You’ve downloaded (or created) a set of 3D assets, including rigged and animated characters, and you want to import it into Godot.\nSolution For this example, we’ll assume you’ve downloaded the art packs linked in the section description and unzipped them.\nBefore copying the files into your Godot project, notice that there are multiple versions of the assets in different file formats: OBJ, FBX, and GLTF. There are also some extra files such as examples and separate textures in case you want to modify them. We don’t need all of that, and GLTF is the preferred import format for Godot. So make sure you’re only dragging the gltf folder or .gltf files (or .glb, which is the binary version of the same) into your project folder.\nHere, I’ve taken the gltf folder from the “Dungeon” pack and the characters folder from the “Adventurers” pack and dragged them into my project.\nNote There are a lot of files in the Dungeon pack - Godot may take a little time to read them all!\nImporting a Character Select the knight.glb file in the FileSystem tab, then click the Import tab at the top left.\nHere you’ll find some basic import settings, but we can go into more detail. Click Advanced button and you’ll see a new window appear:\nOne the left you’ll see all the data that is contained in the GLTF scene, including textures and animations. Note all the weapon options attached to the character and the extensive list of animations.\nThere’s a preview of the character in the middle, and a set of options on the right side where you can adjust how the selected item is configured.\nSince we will code our player as a CharacterBody3D, we can go ahead and specify that node type here. Click on the Scene Root and on the right set the Root Type to CharacterBody3D.\nAnimations Scroll down to the list of animations. You’ll see that there are many, but while some we’ll only want to play once, such as attacks, others like “Idle” and “Running”, we’d like to be looping. For any animation like this, select the animation name and set the Loop Mode to “Linear”. Do this for all of the “Walking”, “Running”, and “Idle” variations. When you’re done, click the Reimport button at the bottom.\nSetting Loop Automatically If you are making your own characters, you can skip this step by ensuring that your animations’ names end with \"-loop\". For details on this and other import hints, see Import Hints in the Godot documentation.\nRight click knight.glb in the FileSystem and choose New Inherited Scene.\nIn this scene you’ll see all the models and the AnimationPlayer where you can test out the animations.\nImporting World Items Importing objects for the environment will be a similar process. As an example, let’s use one of the dungeon walls. There are a lot of files in the dungeon pack, so type “wall” in the file filter to help find it:\nWe’ll want our dungeon walls to be solid, and it would be painful to manually create a StaticBody3D and collision shape for each one. Fortunately, when importing, Godot can do this for us.\nIn the import window, select the mesh object. On the right side, check the Physics box, and set the Shape Type to “Simple Convex” (feel free to check out the other options too).\nClick Reimport. Now when using this in the game, Godot will automatically create a StaticBody3D with a collision shape to match.\nAutomating Collision Shapes As above, there is an import hint for collision shapes as well. In your Blender project, appending -col (or some other variations) will let the importer know to do this step automatically. See the import hints link for details.\nAutomating Imports While adding import hints is the preferred method when making your own assets, it’s not something you can do when downloading an asset pack like the one we’re using.\nIt is possible to write an import script that can run on every imported node of a particular type. For example, we could automate the creation of the static collision we did above.\nAs an example, the following script will loop through all the nodes of the imported object and create a static collision on each mesh it finds.\n@tool extends EditorScenePostImport func _post_import(scene): iterate(scene) return scene func iterate(node): if node != null: if node is MeshInstance3D: node.create_trimesh_collision() for child in node.get_children(): iterate(child) In the Import tab, you can set this as the Import Script, and when you click Reimport, the collisions will be created.\nWrapping up That concludes the overview of importing 3D assets into Godot.\nSee the section description for examples of working with the 3D assets you’ve imported.\nCompanion Video ","description":"","tags":null,"title":"Importing Assets","uri":"/godot_recipes/4.x/3d/assets/importing_assets/index.html"},{"content":"Linear Interpolation, or its commonly-used abbreviation lerp, is a term that comes up often in game development. If you’ve never come across it before it can seem mysterious and highly-technical, but as you’ll see in this tutorial, it’s actually a straightforward concept with a wide variety of applications in game programming.\nNumeric Interpolation The core formula for linear interpolation is this:\nfunc lerp(a, b, t): return (1 - t) * a + t * b In this formula, a and b represent the two values and t is the amount of interpolation, typically expressed as a value between 0 (which returns a), and 1 (which returns b). The function finds a value the given amount between the two. For example:\nx = lerp(0, 1, 0.75) # x is 0.75 x = lerp(0, 100, 0.5) # x is 50 x = lerp(10, 75, 0.3) # x is 29.5 x = lerp(30, 2, 0.75) # x is 9 It’s called linear interpolation because the path between the two points is a straight line.\nYou can animate a node’s properties with lerp(). For example, if you divide the elapsed time by the desired duration, you’ll get a value between zero and one you can use to alter a property smoothly over time. This script scales a sprite up to five times its starting size while fading it out (using modulate.a) over two seconds:\nextends Sprite2D var time = 0 var duration = 2 # length of the effect func _process(delta): if time \u003c duration: time += delta modulate.a = lerp(1, 0, time / duration) scale = Vector2.ONE * lerp(1, 5, time / duration) Vector interpolation You can also interpolate between vectors. Both Vector2 and Vector3 provide linear_interpolate() methods for this.\nFor example, to find a vector that’s halfway between a Spatial node’s forward and left direction vectors:\nvar forward = -transform.basis.z var left = transform.basis.x var forward_left = forward.linear_interpolate(left, 0.5) The following example moves a Sprite node towards the mouse click position. Each frame the node moves 10% of the way to the target. This results in an “approach” effect, where the object’s speed becomes slower the closer it gets to the target.\nextends Sprite2D var target func _input(event): if event is InputEventMouseButton and event.pressed: target = event.position func _process(delta): if target: position = position.linear_interpolate(target, 0.1) For more advanced applications of interpolation, see Tween.\n","description":"","tags":null,"title":"Interpolation","uri":"/godot_recipes/4.x/math/interpolation/index.html"},{"content":"Problem You need to make a 2D platform-style character.\nSolution New developers are often surprised at how complex a platform character can be to program. Godot provides some built-in tools to assist, but there are as many solutions as there are games. In this tutorial, we won’t be going in-depth with features like double-jumps, crouching, wall-jumps, or animation. Here we’ll discuss the fundamentals of platformer movement. See the rest of the recipes for other solutions.\nTip While it’s possible to use RigidBody2D to make a platform character, we’ll be focusing on CharacterBody2D. Kinematic bodies are well-suited for platformers, where you are less interested in realistic physics than in responsive, arcade feel.\nStart with a CharacterBody2D node, and add a Sprite2D and CollisionShape2D to it.\nAttach the following script to the root node of the character. Note that we’re using input actions we’ve defined in the InputMap: \"walk_right\", \"walk_left\", and \"jump\". See InputActions.\nextends CharacterBody2D @export var speed = 1200 @export var jump_speed = -1800 @export var gravity = 4000 func _physics_process(delta): # Add gravity every frame velocity.y += gravity * delta # Input affects x axis only velocity.x = Input.get_axis(\"walk_left\", \"walk_right\") * speed move_and_slide() # Only allow jumping when on the ground if Input.is_action_just_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed The values used for speed, gravity, and jump_speed depend greatly on the size of your player sprite. The player’s texture in this example is 108x208 pixels. If your sprite is smaller, you’ll want to use smaller values. We also want high values so that everything feels fast and responsive. A low gravity results in a floaty-feeling game while a high value means you’re quickly back on the ground and ready to jump again.\nNote that we’re checking is_on_floor() after using move_and_slide(). The move_and_slide() function sets the value of this method, so it’s important not to check it before, or you’ll be getting the value from the previous frame.\nFriction and acceleration The above code is a great start, and you can use it as the foundation for a wide variety of platform controllers. One problem it has, though, is the instantaneous movement. For a more natural feel, it’s better if the character has to accelerate up to its max speed and that it coasts to a stop when there is no input.\nOne way to add this behavior is to use linear interpolation (“lerp”). When moving, we will lerp between the current speed and the max speed and while stopping we’ll lerp between the current speed and 0. Adjusting the lerp amount will give us a variety of movement styles.\nTip For an overview of linear interpolation, see Gamedev Math: Interpolation.\nextends CharacterBody2D @export var speed = 1200 @export var jump_speed = -1800 @export var gravity = 4000 @export_range(0.0, 1.0) var friction = 0.1 @export_range(0.0 , 1.0) var acceleration = 0.25 func _physics_process(delta): velocity.y += gravity * delta var dir = Input.get_axis(\"walk_left\", \"walk_right\") if dir != 0: velocity.x = lerp(velocity.x, dir * speed, acceleration) else: velocity.x = lerp(velocity.x, 0.0, friction) move_and_slide() if Input.is_action_just_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed Try changing the values for friction and acceleration to see how they affect the game’s feel. An ice level, for example, could use very low values, making it harder to maneuver.\nConclusion This code gives you a starting point for building your own platformer controller. For more advanced platforming features such as wall jumps, see the other recipes in this section.\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_platform_basic\n","description":"","tags":null,"title":"Platform character","uri":"/godot_recipes/4.x/2d/platform_character/index.html"},{"content":"This first game project will guide you through making your first Godot Engine game. While you don’t need any previous experience, it’s expected that you’ve at least read through the Godot 101: Getting Started section. There, you’ll learn about the editor interface and how to get around the Godot UI.\nWhy start with 2D? In a nutshell, 3D games are much more complex than 2D ones. However, many of the underlying game engine features you’ll need to know are the same. You should stick to 2D until you have a good understanding of Godot’s workflow. At that point, the jump to 3D will feel much easier.\nOpen Godot and start a new project. You can name it anything you’d like - we’re going with “Classic Shmup”, since this is a traditional shoot-em-up style game.\nDownloading the art You can download the art we’ll be using for the game from itch.io: Mini Pixel Pack by Grafxkid\nUnzip the art pack and copy it into your project by dropping the folder in the FileSystem tab.\nProject settings Next, we need to set up some project-wide settings. Open Project Settings and check the “Advanced Settings” toggle in the upper-right.\nIn the Display/Window section:\nViewport Width \u0026 Viewport Height to 240, 320. Window Width Override \u0026 Window Height Override to 480, 640. Stretch/Mode to canvas_items. These settings will ensure the game is the right size. Because we’re using pixel art, the images themselves are very small, so an old-school resolution like 240x320 is perfect. However, on a modern monitor, that’s a fairly small window, so the other settings let us scale that up proportionally. If you have a 1080p monitor, you can make the override values 720x960 instead. You’ll also be able to resize the window when the game is running.\nIn the Rendering/Textures section under Canvas Textures, set Default Texture Filter to Nearest. This will ensure that our beautiful pixel art stays nice and crisp, looking like the image on the right, not the one on the left: Click the Input Map tab at the top of the Project Settings window. This is where we can set up the inputs we want to use in the game. In the “Add New Action” box, type the following, hitting \u003center\u003e after each to add it to the list of actions: right, left, up, down, shoot. To assign key(s) to each named input, click the + button to its right and press the key on your keyboard. When you’re done, you should have something like this: Feel free to use other keys if you’d rather use a different setup.\nNext steps That takes care of setting up - now we’re ready to get started! In the next section, we’ll create the player-controlled spaceship.\nPrev Next ","description":"","tags":null,"title":"Project Setup","uri":"/godot_recipes/4.x/games/first_2d/first_2d_01/index.html"},{"content":"Problem You want to allow the player to “wrap around” the screen, teleporting from one side of the screen to the other. This is a common feature, especially in old-school 2D games (think Pac-man).\nSolution Get your screen (viewport) size\n@onready var screen_size = get_viewport_rect().size get_viewport_rect() is available to any CanvasItem derived node.\nCompare your player’s position\nif position.x \u003e screen_size.x: position.x = 0 if position.x \u003c 0: position.x = screen_size.x if position.y \u003e screen_size.y: position.y = 0 if position.y \u003c 0: position.y = screen_size.y Note that this is using the node’s position, which is usually the center of your sprite and/or body.\nSimplifying with wrapf()\nThe above code can be simplified using GDScript’s wrapf() function, which “loops” a value between the given limits.\nposition.x = wrapf(position.x, 0, screen_size.x) position.y = wrapf(position.y, 0, screen_size.y) ","description":"","tags":null,"title":"Screen wrap","uri":"/godot_recipes/4.x/2d/screen_wrap/index.html"},{"content":"Problem You want to use a spritesheet containing 2D animations.\nSolution Spritesheets are a common way for 2D animations to be distributed. In a spritesheet, all of the animation frames are packed into a single image.\nFor this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art athttps://elthen.itch.io/.\nWarning Make sure the images in your spritesheet are laid out in a constant-sized grid. This will enable Godot to automatically slice them. If they’re packed irregularly, you will not be able to use the following technique.\nNode setup This animation technique uses a Sprite2D node to display the texture, and then we animate the changing frames with AnimationPlayer. This can work with any 2D node, but for this demo, we’ll use a CharacterBody2D.\nAdd the following nodes to your scene:\nCharacterBody2D: Player Sprite2D CollisionShape2D AnimationPlayer Drag the spritesheet texture into the Texture property of the Sprite2D. You’ll see the entire spritesheet displayed in the viewport. To slice it up into individual frames, expand the “Animation” section in the Inspector and set the Hframes to 13 and Vframes to 8. Hframes and Vframes are the number of horizontal and vertical frames in your spritesheet.\nTry changing the Frame property to see the image change. This is the property we’ll be animating.\nAdding animations Select the AnimationPlayer and click the “Animation” button followed by “New\" . Name the new animation “idle”. Set the animation length to 2 and click the “Loop” button so that our animation will repeat (see below).\nWith the scrubber at time 0, select the Sprite2D node. Set its Animation/Frame to 0, then click the key icon next to the value.\nIf you try playing the animation, you’ll see it doesn’t appear to do anything. That’s because the last frame (12) looks the same as the first (0), but we’re not seeing any of the frames in-between (1-11). To fix this, change the “Update Mode” of the track from its default value of “Discrete” to “Continuous”. You can find this button at the end of the track on the right side.\nNote that this will only work for spritesheets where the frames are already in order. If they are not, you’ll have to keyframe each Frame seperately along the timeline.\nFeel free to add the other animations yourself. For example, the “jump” animation is on frames 65 through 70.\nRelated recipes Platform character ","description":"","tags":null,"title":"Spritesheet animation","uri":"/godot_recipes/4.x/animation/spritesheet_animation/index.html"},{"content":"In this tutorial, we’ll look at how to start working in 3D in Godot. You’ll learn how to navigate in the 3D editor, how to create and manipulate 3D objects, and how to work with some of Godot’s essential 3D nodes, such as cameras and lighting.\nAre you ready? A word of warning: 3D development can be quite a bit more complex than working in 2D. While many of the same principles apply - such as working with nodes, writing scripts, and handling logic/data - 3D brings with it a number of other considerations. For this reason, it’s a good idea to stick to 2D for your first few projects, moving to 3D once you have a good understanding of the game development process. This tutorial will assume you have completed at least an introductory Godot 2D project, such as the one in the [official Godot tutorial] (https://docs.godotengine.org/en/stable/getting_started/step_by_step/your_first_game.html).\nGetting Started in 3D One of Godot’s strengths is its ability to handle both 2D and 3D games. While much of what you’ve learned working on 2D projects (nodes, scenes, signals, etc.) applies equally well in 3D, there is also a whole new layer of complexity and capabilities. First, you’ll find that there are some additional features available in the 3D editor window, so we’ll start there:\nOrienting in 3D Space When you first open a new project in Godot, you will see the 3D project view:\nThe first thing you should notice is the three colored lines in the center. These are the x (red), y (green), and z (blue) axes. The point where they meet is the origin, which has the coordinates (0, 0, 0). You’ll find that this color scheme will also apply elsewhere in the Inspector.\nNote Different 3D applications follow different conventions for orientation. Godot uses Y-Up orientation, so that when looking at the axes, if x is pointing to the left/right, then y is up/down, and z is forward/back. Some other popular 3D software uses Z-UP. It’s good to keep this in mind when moving between applications.\nNavigation in 3D is performed using the mouse and keyboard. Here are the basic controls for the view camera:\nMousewheel up/down: zoom in/out Middle button + drag: orbit camera around current target Shift + middle button + drag: pan camera Right-click + drag: rotate camera in place In addition, if you’re familiar with popular 3D games, you might prefer Freelook mode, which you can toggle on/off using Shift+F. In this mode, you can use the WASD keys to fly around the scene while aiming with the mouse.\nYou can also alter the camera’s view by clicking on the [Perspective] label in the upper-left corner. Here, you can snap the camera to a particular orientation.\nAdding 3D Objects Now let’s add our first 3D node. Just as all 2D nodes inherit from Node3D, which provides properties such as position and rotation, 3D nodes inherit from Node3D, which provides 3D versions of the same properties. Add one to your scene and you’ll see the following object appear at the origin:\nThis object is not the node. It is something called a 3D gizmo. Gizmos are tools that allow you to move and rotate objects in space. The three rings control rotation, while the three arrows move (translate) the object along the three axes. Note that the rings and arrows are color-coded to match the axis colors.\nTake a few minutes to experiment and get familiar with the gizmo. Use Undo if you find yourself getting lost.\nTip Sometimes you may feel the gizmos are getting in your way. You can click on the mode icons to restrict yourself to only one type of transformation: move, rotate, or scale: Global vs. Local Space By default, the gizmo controls operate in global space. When you rotate the object, the gizmo’s arrows still point along the axes. However, if you click the Use Local Space button, the gizmo will switch to moving the body in local space.\nNow when you rotate the object, the gizmo arrows point along the object’s axes and not the world’s. Switching back and forth between Local and World space can make it much easier to place an object exactly where you want it.\nTransforms Look at the Inspector for the Node3D node. In the Transform section, you’ll see properties for Position, Rotation, and Scale. Drag the object around with the gizmo and observe how these values change. Just like in 2D, these properties are relative to the node’s parent.\nTogether, these properties make up the node’s transform. When changing the node’s spatial properties in code, you’ll access the transform property, which is a Godot Transform3D object. It has two properties: origin and basis. The origin represents the body’s position, while the basis contains three vectors that define the body’s local coordinate axes - think of the three axis arrows in the gizmo when you’re in Local Space mode.\nYou’ll see how to use these properties later in this section.\nMeshes Just like a Node2D, a Node3D has no size or appearance of its own. In 2D, you would use a Sprite2D to add a texture to the node. In 3D, you need to add a mesh. A mesh is a mathematical description of a shape. It consists of a collection of points, called vertices. These vertices are connected by lines, called edges, and multiple edges (at least three) together make a face.\nFor example, a cube is made up of 8 vertices, 12 edges, and 6 faces.\nAdding Meshes Typically, meshes are created by using 3D modeling software, such as Blender. You can also find many collections of 3D models available for download, if you’re unable to create your own. However, often you just need a basic shape such as a cube or sphere. In this case, Godot provides a way to create simple meshes called primitives.\nAdd a MeshInstance3D node as a child of the Node3D and in the Inspector, click its Mesh property:\nHere you can see the list of available primitives. They represent a handy collection of common useful shapes. Select “New BoxMesh” and you’ll see a plain cube appear on the screen.\nCameras Try running the scene with your cube object. Did you see anything? In 3D, you won’t see anything in the game viewport without adding a Camera3D. Add one to the root node and use the camera’s gizmo to position it pointing towards the cube:\nThe pinkish-purple pyramid shape on the camera is called the fustrum and represents the camera’s view. Notice the small triangular arrow which represents the camera’s “up” orientation. As you’re moving the camera around, try pressing the Preview button in the upper-left to see what the camera sees. Play the scene to verify everything is working as expected.\nWrapping Up In this tutorial you learned how to use Godot’s 3D editor, how to add 3D nodes such as Node3D, MeshInstance3D, and Camera3D, and how to use gizmos to place your objects. You also learned a bunch of new terminology. Hopefully you’re not overwhelmed.\nIn the next part, we’ll look at how to build a 3D scene by importing 3D assets and how to use more of Godot’s 3D nodes.\n","description":"","tags":null,"title":"The 3D Editor","uri":"/godot_recipes/4.x/g101/3d/101_3d_01/index.html"},{"content":"Problem You’re making a 2D top-down game, and you want to control a character’s movement.\nSolution For this solution, we’ll assume you have the following input actions defined:\nAction Name Key(s) \"up\" W,↑ \"down\" S,↓ \"right\" D,→ \"left\" A,← \"click\" Mouse button 1 We will also assume you’re using a CharacterBody2D node.\nWe can solve this problem in many ways, depending on what type of behavior you’re looking for.\nOption 1: 8-way movement In this scenario, the player uses the four directional keys to move (including diagonals).\nextends CharacterBody2D var speed = 400 # speed in pixels/sec func _physics_process(delta): var direction = Input.get_vector(\"left\", \"right\", \"up\", \"down\") velocity = direction * speed move_and_slide() Option 2: Rotate and move In this scenario, the left/right actions rotate the character and up/down move the character forward and back in whatever direction it’s facing. This is sometimes referred to as “Asteroids-style” movement.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec var rotation_speed = 1.5 # turning speed in radians/sec func _physics_process(delta): var move_input = Input.get_axis(\"down\", \"up\") var rotation_direction = Input.get_axis(\"left\", \"right\") velocity = transform.x * move_input * speed rotation += rotation_direction * rotation_speed * delta move_and_slide() Note Godot considers an angle of 0 degrees to be pointing along the x axis. This means that a node’s forward direction (transform.x) is to the right. You should ensure that your character’s sprite is also drawn pointing to the right.\nOption 3: Aim with mouse Similar to option 2, but this time the character rotation is controlled with the mouse (ie the character always points towards the mouse). Forward/back movement is done with the keys as before.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec func _physics_process(delta): look_at(get_global_mouse_position()) var move_input = Input.get_axis(\"down\", \"up\") velocity = transform.x * move_input * speed move_and_slide() Option 4: Click and move In this option, the character moves to the clicked location.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec var target = null func _input(event): if event.is_action_pressed(\"click\"): target = get_global_mouse_position() func _physics_process(delta): if target: # look_at(target) velocity = position.direction_to(target) * speed if position.distance_to(target) \u003c 10: velocity = Vector2.ZERO move_and_slide() Note that we stop moving if we get close to the target position. If you don’t do this, the character will “jiggle” back and forth as it moves a little bit past the target, moves back, goes a little past it, and so on. Optionally, you can use look_at() to face in the direction of movement.\nDownload This Project Download the project code here: https://github.com/godotrecipes/topdown_movement\n","description":"","tags":null,"title":"Top-down movement","uri":"/godot_recipes/4.x/2d/topdown_movement/index.html"},{"content":"Problem You need to understand in what order Godot handles nodes in the scene tree.\nSolution “Tree order” is mentioned often in the Godot docs and in tutorials. However, it is not always obvious to a beginner what is meant by this. Generally speaking, the order in which nodes are handled in the tree is in top-down fashion, starting at the root and going down each branch in turn.\nScene tree order is something that can cause a great deal of confusion for Godot beginners. In this example, we’ll illustrate in what order things happen.\nHere’s our sample node setup:\nOn each node, we have the following script attached:\nextends Node func _init(): # Note: a Node doesn't have a \"name\" yet here. print(\"TestRoot init\") func _enter_tree(): print(name + \" enter tree\") func _ready(): print(name + \" ready\") # This ensures we only print *once* in process(). var test = true func _process(delta): if test: print(name + \" process\") test = false Before we talk about the results, let’s review what each of these callback functions represents:\n_init() is called when the object is first created. It now exists in the computer’s memory.\n_enter_tree() is called when the node first enters the tree. This can be when instancing or when add_child() is used, for example.\n_ready() is called when the node and its children have all been added to the tree and are ready.\n_process() is called every frame (typically 60 times per second) on every node in the tree.\nIf we ran this on a single node all by itself, the order would be as you might expect:\nTestRoot init TestRoot enter tree TestRoot ready TestRoot process Once we add children to the mix, it becomes a bit more complex, and probably needs some clarification:\nTestRoot init TestChild1 init TestChild3 init TestChild2 init TestRoot enter tree TestChild1 enter tree TestChild3 enter tree TestChild2 enter tree TestChild3 ready TestChild1 ready TestChild2 ready TestRoot ready TestRoot process TestChild1 process TestChild3 process TestChild2 process As you can see, all of these nodes printed their messages in tree order, from top to bottom, following branches first - with the exception of the _ready() code.\nHere’s a quote from the Node reference:\nCalled when the node is “ready”, i.e. when both the node and its children have entered the scene tree. If the node has children, their _ready callbacks get triggered first, and the parent node will receive the ready notification afterwards.\nThis leads to an important rule-of-thumb to remember when setting up your node structure:\nTip Parent nodes should manage their children, not vice-versa.\nThis means any code in the parent must be able to fully access any data in its children. For that reason, _ready() must be processed in reverse tree order.\nRemember this when trying to access other nodes in _ready(). If you need to go up the tree to a parent (or grandparent), you should probably run that code in the parent rather than the child.\nRelated recipes Understanding node paths ","description":"","tags":null,"title":"Understanding tree order","uri":"/godot_recipes/4.x/basics/tree_ready_order/index.html"},{"content":"Game Engines Game development is complex and involves a wide variety of knowledge and skills. In order to build a modern game, you need a lot of underlying technology before you can make the actual game itself. Imagine if you had to build your own computer and write your own operating system before you could even start programming. Game development would be a lot like that if you truly had to start from scratch and build everything you needed.\nIn addition, there are a number of common needs every game has. For example, no matter what your game is, it’s going to need to draw things on the screen. If the code to do that has already been written, it makes more sense to reuse it that to create it all over again for every game. This is where game engines come in.\nA game engine is a collection of tools and technologies designed to assist in developing games. This allows you to focus more on building your game, and less on reinventing the wheel. Here are some of the features a good game engine will provide:\nRendering (2D/3D) “Rendering” is the process of displaying your game on the player’s screen. A good rendering pipeline needs to work with modern GPU features, high resolution displays, and effects like lighting and perspective, while maintaining a high frame rate.\nPhysics Building an accurate and usable physics engine is an enormous task. Most games require some sort of collision detection and response, and many need simulated physics (ie. friction, inertia, etc.), but few developers want to take on the task of writing one.\nPlatform Support In today’s market, you want to be able to release your game on multiple platforms, such as mobile, web, PC, and/or console. A game engine lets you build your game once and export it to one or more platforms.\nDevelopment Environment All of these tools are brought together in a single application, combining everything into one environment so you don’t have to learn a new workflow for every new project.\nThere are dozens of popular game engines to choose from today, such as Unity, Unreal, and GameMaker Studio, to name a few. It is important to remember that the majority of popular engines are commercial products. They may or may not be free to download, but the will require some kind of licensing or royalty agreement if you plan to release your game (and especially if your game makes money). You need to carefully read and understand what you’re agreeing to and what you are and are not allowed to do with the engine.\nWhy use Godot? Click here to download Godot\nIn contrast to the above, Godot is completely free and open source, released under the very permissive MIT license. This means there are no fees, hidden costs, or royalties you need to pay. This is in addition to being a fully featured modern game engine.\nAs a developer, the benefits are great. Because it’s unencumbered by commercial licensing, you have complete control over exactly how and where your game is distributed. In addition, Godot’s open source nature also means there is a much greater level of transparency than you’ll find with commercial engines. For example, if you find a particular feature doesn’t quite meet your needs, you’re free to modify the engine itself - no permission required.\n","description":"","tags":null,"title":"What is Godot?","uri":"/godot_recipes/4.x/g101/start/101_01/index.html"},{"content":" Working with 3D Assets Detailed recipes for importing and working with 3D assets including models, animations, and materials.\nFor these examples, we’ll be using the following 3d assets from Kay Lousberg:\nAdventurers Character Pack Dungeon Asset Pack In this section: Importing Assets Character Animation Character Controller ","description":"","tags":null,"title":"Working with 3D Assets","uri":"/godot_recipes/4.x/3d/assets/index.html"},{"content":" Your First 2D Game Get started with Godot by building a 2D shooter. In this series, we’ll start with the basics and build a classic, old-school space shooter.\nHere’s a screenshot of the finished game:\nIn each part of the series, we’ll build a piece of the game, adding features and explaining the process along the way.\nBackground If you find that you’re struggling with the programming side of things, see these resources:\nGodot 101: Introduction to GDScript - tutorial on this website. Godot Official Documentation - official tutorial resources Download This Project on GitHub Download the project code here:\nhttps://github.com/godotrecipes/classic_shmup\n","description":"","tags":null,"title":"Your First 2D Game","uri":"/godot_recipes/4.x/games/first_2d/index.html"},{"content":"Problem You need to make a first-person shooter (FPS) character.\nSolution Start with a CharacterBody3D node, and add a CollisionShape3D to it. The CapsuleShape3D collision shape is the most common choice. Depending on your world setup, you may want to add additional shapes here, but for the purposes of this example, we’ll stick to the basics.\nWe’ll leave all the sizing at the default values, meaning the capsule will be 2 meters high. Move it up by 1.0 m to align its bottom with the ground.\nNext, add a Camera3D as a child of the body and move it up about 1.6 m.\nWhere’s the body? For this example, we’ll leave the character “bodyless” - meaning we’re not adding a mesh to display for the player’s body. Depending on your setup, you may or may not need to see the player’s body.\nAttach a script to the body and start by defining some properties:\nextends CharacterBody3D var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var speed = 5 var jump_speed = 5 var mouse_sensitivity = 0.002 The _physics_process() function is the place to handle movement. Note that Input.get_vector() returns a 2-dimensional vector based on the combination of the forward/back/left/right keys. We want to use this vector to set the x and z components of the body’s velocity (because y is handled by gravity). Multiplying this vector by the body’s basis ensures we account for rotation - forward should always be the body’s forward vector.\nfunc _physics_process(delta): velocity.y += -gravity * delta var input = Input.get_vector(\"left\", \"right\", \"forward\", \"back\") var movement_dir = transform.basis * Vector3(input.x, 0, input.y) velocity.x = movement_dir.x * speed velocity.z = movement_dir.z * speed move_and_slide() if is_on_floor() and Input.is_action_just_pressed(\"jump\"): velocity.y = jump_speed Don’t forget to add the input actions to your Input Map using the keys/inputs you prefer (W/A/S/D is typical, or you can use joystick axes if you prefer a controller).\nAdd the player to a “World” scene where you’ve created some StaticBody3D nodes for the floor and some walls.\nWhen you try to move, you’ll notice you can move forward/back and left/right, but you can’t rotate. That’s what we’ll handle next.\nMouse control in 3D First, we need the player to rotate left/right when we move the mouse the same way. Mouse input is represented in 2D, relative to the screen, so we need the x movement of the mouse to rotate the player’s body around its y (vertical) axis. The mouse_sensitivity property we defined above lets us adjust how many pixels of mouse movement translate to a degree of rotation.\nfunc _input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) Try the code again, and you’ll see that you can now rotate with the mouse. However, you may find your mouse running outside the game window. This is the perfect time to add some code to capture your mouse. See Input: Capturing the Mouse for details.\nOur updated code then becomes\nfunc _input(event): if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * mouse_sensitivity) Finally, to look up/down, we’ll use the y motion of the mouse to tilt the camera. We don’t want it to turn completely upside-down, though, so we’ll clamp() the rotation to a reasonable value of 70 degrees.\nfunc _input(event): if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * mouse_sensitivity) $Camera3D.rotate_x(-event.relative.y * mouse_sensitivity) $Camera3D.rotation.x = clampf($Camera3D.rotation.x, -deg_to_rad(70), deg_to_rad(70)) Holding a weapon An FPS character typically has a 3D mesh of a weapon positioned in front. Setting this up can be easy with a couple of Godot editor tricks.\nAdd your weapon mesh as a child of the Camera3D. Then, in the editor view menu, choose “2 Viewports” and set one of them to preview the camera. Then, you can move around the weapon and easily see how it will look from the player’s perspective.\nTo add a little personality, try using an AnimationPlayer to animate the weapon’s position from side-to-side as the player moves.\nRelated recipes Input: Capturing the Mouse Download This Project Download the project code here: https://github.com/godotrecipes/basic_fps\n","description":"","tags":[],"title":"Basic FPS Character","uri":"/godot_recipes/4.x/3d/basic_fps/index.html"},{"content":" Basics Basic Godot tips and tricks that apply to any project.\nIn this section: Understanding tree order Node communication (the right way) Understanding node paths Understanding 'delta' Saving/loading data Migrating from 3.x ","description":"","tags":null,"title":"Basics","uri":"/godot_recipes/4.x/basics/index.html"},{"content":"Problem You need a camera controller, using mouse or keyboard, that remains level while rotating and following a target.\nSolution Try this: take a Camera3D node and rotate it a small amount around X (the red ring on the gizmo), then a small amount around Z (the blue ring). Now reverse the X rotation and click the “Preview” button. Observe how the camera is now tilted.\nThe solution to this problem is to place the camera on a gimbal - a device designed to keep an object level during movement. We can create a gimbal using two Node3D nodes, which will control the camera’s left/right and up/down rotation respectively.\nThe node setup should look like this:\nNode3D: CameraGimbal Node3D: InnerGimbal Camera3D Set the Transform/Position of the Camera3D to (0, 0, 4).\nHere’s how the gimbal works: the outer node can only be rotated in Y, while the inner one rotates only in X. You can test this out by rotating them manually, but make sure you change to “Local Space Mode” first (that’s the cube icon next to the lock in the menu bar - the keyboard shortcut to toggle is “T”). Remember to only move the green ring of the outer node and only the red ring of the inner one. Don’t touch the camera node at all.\nReset all the rotations to 0 once you’ve finished experimenting.\nKeyboard control We’ll start with the keyboard controls, then add an option to use the mouse as well. Here are the required actions and their assigned inputs:\nAction Name Input \"cam_up\" W \"cam_down\" S \"cam_right\" D \"cam_left\" A \"cam_zoom_in\" Mouse Wheel Up \"cam_zoom_out\" Mouse Wheel Down Here’s the initial script. Note that we’re making sure to rotate each Node3D in its local space around the specific axis, as described above.\nextends Node3D var rotation_speed = PI/2 func get_input_keyboard(delta): # Rotate outer gimbal around y axis var y_rotation = Input.get_axis(\"cam_left\", \"cam_right\") rotate_object_local(Vector3.UP, y_rotation * rotation_speed * delta) # Rotate inner gimbal around local x axis var x_rotation = Input.get_axis(\"cam_up\", \"cam_down\") x_rotation = -x_rotation if invert_y else x_rotation inner.rotate_object_local(Vector3.RIGHT, x_rotation * rotation_speed * delta) func _process(delta): get_input_keyboard(delta) Make a test scene with a MeshInstance3D and instance the CameraGimbal in it to test out the movement.\nYou’ll notice that holding the up/down control will cause the camera to rotate all the way around, eventually becoming upside-down. To prevent this, we can clamp the rotation.\nfunc _process(delta): get_input_keyboard(delta) $InnerGimbal.rotation.x = clamp($InnerGimbal.rotation.x, -1.4, -0.01) The -1.4 value lets it go almost to 90 degrees up, while setting a very small value for the minimum keeps the camera from clipping into the ground. Feel free to experiment with other values.\nMouse control We’ll add a flag called mouse_control to enable easy toggling of mouse/keyboard controls.\n# mouse properties var invert_y = false var invert_x = false var mouse_control = false var mouse_sensitivity = 0.005 func _unhandled_input(event): if mouse_control and event is InputEventMouseMotion: if event.relative.x != 0: var dir = 1 if invert_x else -1 rotate_object_local(Vector3.UP, dir * event.relative.x * mouse_sensitivity) if event.relative.y != 0: var dir = 1 if invert_y else -1 $InnerGimbal.rotate_object_local(Vector3.RIGHT, dir * event.relative.y * mouse_sensitivity) func _process(delta): if !mouse_control: get_input_keyboard(delta) This code works by converting horizontal mouse motion to Y rotation of the outer gimbal and vertical to X rotation for the inner gimbal. We’ve also added invert_x and invert_y flags so that you can flip the motion in either axis - many players prefer one over the other, so it’s best to allow for both options.\nAlso, in _process() we disable keyboard input when using mouse control.\nYou may notice a problem with the up/down movement if you move the mouse too quickly. A large value for event.relative.y results in “skipping” to the opposite side of the clamped value. We can solve this by clamping the vertical mouse movement to a reasonable value. Change the above code for y to this:\nif event.relative.y != 0: var dir = 1 if invert_y else -1 var y_rotation = clamp(event.relative.y, -30, 30) $InnerGimbal.rotate_object_local(Vector3.RIGHT, dir * y_rotation * mouse_sensitivity) Note In your project, you’ll probably also want to capture the mouse during gameplay. See the linked recipe at the end of this document for details.\nCamera zoom Camera zoom works by varying the scale of the gimbal system.\n# zoom settings var max_zoom = 3.0 var min_zoom = 0.5 var zoom_speed = 0.09 var zoom = 1.5 func _unhandled_input(event): if event.is_action_pressed(\"cam_zoom_in\"): zoom -= zoom_speed if event.is_action_pressed(\"cam_zoom_out\"): zoom += zoom_speed zoom = clamp(zoom, min_zoom, max_zoom) func _process(delta): scale = lerp(scale, Vector3.ONE * zoom, zoom_speed) Using lerp() to change the zoom level results in smoother zooming.\nFollowing a target Once you have the camera gimbal set up, it can follow a target by adding the following:\n@export var target : Node3D func _process(delta): if target: global_position = target.global_position Instance the camera in your scene and use the Inspector to choose the node you want to follow.\nFinal script For completeness, here’s the full script, including @export variables for all the camera settings, so that you can configure it in your project.\nextends Node3D @export var target : Node3D @export_range(0.0, 2.0) var rotation_speed = PI/2 # mouse properties @export var mouse_control = false @export_range(0.001, 0.1) var mouse_sensitivity = 0.005 @export var invert_y = false @export var invert_x = false # zoom settings @export var max_zoom = 3.0 @export var min_zoom = 0.4 @export_range(0.05, 1.0) var zoom_speed = 0.09 var zoom = 1.5 @onready var inner = $InnerGimbal func _unhandled_input(event): if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED: return if event.is_action_pressed(\"cam_zoom_in\"): zoom -= zoom_speed if event.is_action_pressed(\"cam_zoom_out\"): zoom += zoom_speed zoom = clamp(zoom, min_zoom, max_zoom) if mouse_control and event is InputEventMouseMotion: if event.relative.x != 0: var dir = 1 if invert_x else -1 rotate_object_local(Vector3.UP, dir * event.relative.x * mouse_sensitivity) if event.relative.y != 0: var dir = 1 if invert_y else -1 var y_rotation = clamp(event.relative.y, -30, 30) inner.rotate_object_local(Vector3.RIGHT, dir * y_rotation * mouse_sensitivity) func get_input_keyboard(delta): # Rotate outer gimbal around y axis var y_rotation = Input.get_axis(\"cam_left\", \"cam_right\") rotate_object_local(Vector3.UP, y_rotation * rotation_speed * delta) # Rotate inner gimbal around local x axis var x_rotation = Input.get_axis(\"cam_up\", \"cam_down\") x_rotation = -x_rotation if invert_y else x_rotation inner.rotate_object_local(Vector3.RIGHT, x_rotation * rotation_speed * delta) func _process(delta): if !mouse_control: get_input_keyboard(delta) inner.rotation.x = clamp(inner.rotation.x, -1.4, -0.01) scale = lerp(scale, Vector3.ONE * zoom, zoom_speed) if target: global_position = target.global_position ","description":"","tags":null,"title":"Camera Gimbal","uri":"/godot_recipes/4.x/3d/camera_gimbal/index.html"},{"content":"In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.\nSetting up the Ship Scene A common part of the Godot workflow is creating scenes. As discussed earlier, a scene in Godot is nothing more than a collection of nodes. In most Godot projects, each game object is configured as a scene, with nodes that provide it with the desired functionality, and optionally some code to customize its behavior.\nChoosing nodes The first step is to decide what kind of node to start with. The first node you add to the scene is called the root node. A scene’s root node should generally be the one that primarily defines the game object’s behavior. Then you attach child nodes to add additional functionality.\nSo what should our game’s ship be? Let’s break down the requirements, and look at what nodes might be useful to meet them.\nThe ship needs to:\nMove in 2D space. For this, a basic Node2D would suffice, as that’s the node that has position, rotation, and other 2D-related properties. However, it has no appearance.\nDisplay an image. Sprite2D is the node for this. Since it’s also a Node2D, we’d still be able to move it around.\nDetect getting hit. The enemies will be shooting and flying around on the screen, so we’ll need to know when the ship is hit. We don’t have a need for solid objects - they’re not going to bounce off each other or transfer momentum - we just need to know when they touch. For this, an Area2D would be perfect. It can detect touching other objects, has positional properties, but it has no appearance of its own.\nLooking at this list, the Area2D provides the main functionality. We can attach a Sprite2D to display the ship image, and then we’ll have everything we need.\nBuilding the scene In the Scene tab, click the + button or the + Other Node button to add the first node. Start typing Area2D and choose it from the list. Once it’s in the Scene tab, click the node’s name to rename it to Player, and press \u003cCtrl+S\u003e to save the scene.\nDisplaying the ship With the Player node selected, add another node: a Sprite2D. To keep things organized, let’s rename this node to Ship.\nFrom the FileSystem tab, drag the Player_ship (16x16).png file from the art pack and drop it in the Texture property of the Inspector.\nThe first thing you’ll notice is that there seem to be three ships! The image from the art pack also includes versions of the ship going to the left/right. We can use this - in the Animation section of the Inspector, set Hframes to 3. Now, changing the Frame property will move between the three different versions. Leave it at 1 for now.\nAdding a collision shape You may also have noticed the yellow warning triangle on the Area2D node. If you click it, you’ll see the warning is telling us that the area doesn’t have a shape. We need to define its shape, and we can do that by adding a CollisionShape2D node as a child of the Player.\nIn the Inspector for this node, you’ll see a Shape property that currently shows \u003cempty\u003e. If you click in this box, you’ll see a dropdown that allows you to select from a variety of shapes. Choose New RectangleShape2D and you’ll see a light blue square appear over the ship. You can adjust the size of the shape by dragging the orange circles, or you can click on the shape in the Shape property to expand it and fill in the Size manually.\nExhaust The ship will look much more dynamic with a little animation. Included in the art pack are some animations of exhaust flames named “Boosters”. There are three: one for each version of the ship (left, forward, and right).\nTo display these, select the Ship node and add a child AnimatedSprite2D node and name it “Boosters”.\nIn the Inspector, under the Animation section, you’ll find a property called Sprite Frames, which is currently \u003cempty\u003e. Click it to create a New SpriteFrames, then click the SpriteFrames item to open the animation panel at the bottom of the editor window.\nDouble-click the “default” animation to rename it to “forward”. Then, to add the animation images, click the Add frames from sprite sheet button:\nChoose the Boosters (16 x 16).png image and you’ll see the Select Frames window, allowing you to choose the frames you want.\nThere are only two frames in this animation, but the grid isn’t correct. Change the Size values to match the image sizes: 16 x 16. Then, click both frames to select them and click the Add 2 Frame(s) button.\nNow that you’ve added the two frames, press the Play button to run the animation. You can also toggle the Autoplay on Load button so that the animation will start automatically.\nIt’s a little slow, so change the speed to 10 FPS.\nAdd two more animations by clicking the Add Animation button, naming them left and right.\nRepeat the process, adding the left and right “Booster” sprite sheets.\nGun cooldown The last node we’ll need to complete the player setup is a Timer to control how fast the player can shoot. Add the Timer as a child of Player and name it GunCooldown. Set its One Shot property to “On”. This means that when the timer ends, it won’t automatically restart. In the player’s code, we’ll start the timer when the player shoots, and they won’t be able to shoot again until the timer runs out.\nNext steps That completes the player scene setup. We’ve added the nodes to give the player ship the functionality it will need in the game. In the next section, we’ll add some code to enable the player to control the ship, make it shoot, and detect when it collides with things.\nPrev Next ","description":"","tags":null,"title":"Designing the Player Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_02/index.html"},{"content":"Problem You need a 2D character that moves in a grid pattern.\nSolution Grid- or tile-based movement means the character’s position is restricted. They can only stand on a particular tile - never between two tiles.\nCharacter setup Here are the nodes we’ll use for the player:\nArea2D (“Player”): Using an Area2D means we can detect overlap (for picking up objects or colliding with enemies). Sprite2D: You can use a sprite sheet here (we’ll set up the animation below). CollisionShape2D: Don’t make the hitbox too big. Since the player will be standing on the center of a tile, overlaps will be from the center. RayCast2D: For checking if movement is possible in the given direction. AnimationPlayer: For playing the character’s walk animation(s). Add some input actions to the Input Map. We’ll use “up”, “down”, “left”, and “right” for this example.\nBasic movement We’ll start by setting up the tile-by-tile movement, without any animations or interpolation.\nextends Area2D var tile_size = 64 var inputs = {\"right\": Vector2.RIGHT, \"left\": Vector2.LEFT, \"up\": Vector2.UP, \"down\": Vector2.DOWN} tile_size should be set to match the size of your tiles. In a larger project, this can be set by your main scene when instancing the player. We’re using 64x64 tiles in the example below.\nThe inputs dictionary maps the input action names to direction vectors. Make sure you have the names spelled the same here and in the Input Map (capitalization counts!).\nfunc _ready(): position = position.snapped(Vector2.ONE * tile_size) position += Vector2.ONE * tile_size/2 snapped() allows us to “round” the position to the nearest tile increment, and adding a half-tile amount makes sure the player is centered on the tile.\nfunc _unhandled_input(event): for dir in inputs.keys(): if event.is_action_pressed(dir): move(dir) func move(dir): position += inputs[dir] * tile_size Here’s the actual movement code. When an input event occurs, we check the four directions to see which one matched, then pass it to move() to change the position.\nCollision Now we can add some obstacles. You can add StaticBody2Ds to manually add some obstacles (enable snapping to make sure they’re aligned with the grid) or use a TileMap (with collisions defined), as in the example below.\nWe’ll use the RayCast2D to determine whether a move to the next tile is allowed.\nonready var ray = $RayCast2D func move(dir): ray.target_position = inputs[dir] * tile_size ray.force_raycast_update() if !ray.is_colliding(): position += inputs[dir] * tile_size When changing a raycast’s target_position property, the physics engine won’t recalculate its collisions until the next physics frame. force_raycast_update() lets you update the ray’s state immediately. If it’s not colliding, then we allow the move.\nNote Another common method is to use 4 separate raycasts, one for each direction.\nAnimating movement Lastly we can interpolate the position between tiles, giving a smooth feel to the movement. We’ll use the Tween node to animate the position property.\nvar animation_speed = 3 var moving = false Add a reference to the Tween node and a variable to set our movement speed.\nfunc _unhandled_input(event): if moving: return for dir in inputs.keys(): if event.is_action_pressed(dir): move(dir) We’ll ignore any input while the tween is running and remove the direct position change so that the tween can handle it.\nfunc move(dir): ray.target_position = inputs[dir] * tile_size ray.force_raycast_update() if !ray.is_colliding(): #position += inputs[dir] * tile_size var tween = create_tween() tween.tween_property(self, \"position\", position + inputs[dir] * tile_size, 1.0/animation_speed).set_trans(Tween.TRANS_SINE) moving = true await tween.finished moving = false Experiment with different tween transitions for different movement effects.\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_grid_movement/\n","description":"","tags":null,"title":"Grid-based movement","uri":"/godot_recipes/4.x/2d/grid_movement/index.html"},{"content":"In the last part, we started a 3D project and looked at how to navigate and create 3D objects. In this part, you’ll learn how to import existing 3D objects that you’ve made or downloaded and how to use more of Godot’s 3D nodes.\nImporting 3D Objects If you’re familiar with 3D modeling software such as Blender, you can make your own models to use in your game. If not, there are many sources where you can download objects or even collections of objects for particular game types. One of our favorite makers of free game art is Kenney.nl.\nFor our tutorials, we’re going to use Kenney’s Platformer Kit, which you can download here: https://kenney.nl/assets/platformer-kit\nThis kit has a wide selection of objects that we can use to practice our Godot 3D skills. Here’s a sample showing what the kit looks like:\nOnce you’ve downloaded the kit, you’ll find that the objects inside are provided in a variety of different formats. Godot is able to use several of these, but since GLTF is available in this pack, it’s preferred over the others. Drop the GLTF format folder into your Godot project’s folder and rename it to “platformer_kit”.\n3D file formats Whether you create your own models or download the, you’ll need them to be saved in a format that Godot can use. Godot supports the following 3D file formats:\nglTF - supported in both text (.gltf) and binary (.glb) versions DAE (Collada) - an older format that is still supported OBJ (Wavefront) - an older format that is supported, but the format is limited compared to modern options FBX - a commercial format that has limited support glTF is the recommended format - it has the most features and is very well supported in Godot.\nWhen you switch back to your Godot window, you’ll see progress bar while Godot scans the folder and imports all of the objects. Let’s click on one of them to see what’s going on. In the FileSystem tab, double-click on crate.glb:\nHere you can see the object will be imported as a scene, with its root type set to Node3D and named “Scene Root”. Let’s change these: set the root type to RigidBody3D and the root name to “Crate”, then click the “Reimport” button.\nNow right-click on “crate.glb” and choose New Inherited Scene. Here we have a classic game object: the crate. The root node of the scene is a RigidBody3D named “Crate” just as we wanted.\nFinally, we need to add a collision shape to the body. While we could do this by adding a CollionShape3D, as you would typically do in 2D, but there’s a quicker way.\nSelect the crate2 mesh and you’ll see a Mesh menu appear at the top of the viewport. Click it and select Create Single Convex Collision Sibling. Godot will automatically add a CollionShape3D with a collision shape that matches the mesh.\nNow we’re finished setting up the object. Save your Crate scene and let’s see how we can use it.\nBuilding a 3D Scene Create a new scene with a Node3D root. The first child we’ll add is one to give us a “ground” to stack some crates on. Add a StaticBody3D called “Ground”, and to that add a MeshInstance3D. In the Mesh property, select “New BoxMesh” and then click it to open its properties. Set Size to (10, 0.1, 10) so that we have a nice large surface. However, it would look better if it weren’t plain white.\nAlso in the mesh properties is a Material property. Materials are how you define the appearance of an object. Select “New StandardMaterial3D” and then click it to open a large list of properties. To set the color of the mesh, we need the Albedo/Color property. Choose a color, such as brown or dark green.\nIf we add a crate, it will fall right through the mesh, so we also need to give it a collision shape. Add a CollisionShape3D to the Ground and choose “New BoxShape3D”. Set the collision box to the same size as the mesh.\nNow instance a few crates in the scene and arrange them in a rough stack. Add a Camera and place it where it has a good view of the crates. Run the scene and watch your crates go tumbling!\nWhy is the scene so dark? Because there’s no light! By default, Godot doesn’t add any lighting or environment to your scenes, like it does in the editor viewport. This is great when you want to set up your own specific lighting, but for a quick example scene like this, there’s a shortcut.\nLighting There are multiple light nodes available in 3D, which you can use to create a variety of lighting effects. But we’re going to start with DirectionalLight3D. However, instead of adding one manually, we’re going to have Godot use the same one it’s using in the editor window. At the top ove the viewport, there are two icons that control the preview lighting and preview environment. If you click the three dots next to them, you can see their settings.\nClick the Add Sun to Scene button, and Godot will add a DirectionalLight3D to your scene. Click Add Environment to Scene and it will do the same with the preview sky by adding a WorldEnvironment node.\nRun the scene again, and you’ll be able to see your crates falling.\nRotating Camera Let’s make the camera a little more dynamic by having it slowly orbit around the scene. Select the root node and add a Node3D, which will be located at (0, 0, 0) and name it “CameraHub”. In the scene tree, drag the camera to make it a child of this new node. Now, if the CameraHub rotates around the y axis, it will drag the camera along with it.\nAdd a script to the root node and add the following:\nextends Node3D func _process(delta): $CameraHub.rotate_y(0.6 * delta) Run the scene to see what happens.\nWrapping Up In this tutorial you learned how to import 3D objects from outside sources, and how to combine them into a simple scene. We also investigated lights and moving cameras.\nIn the next part, we’ll look at how to build a more complex scene and include a player-controlled character.\n","description":"","tags":null,"title":"Importing 3D Objects","uri":"/godot_recipes/4.x/g101/3d/101_3d_02/index.html"},{"content":"Problem You want to understand Godot’s “input action” system.\nSolution Let’s say you’re making a top-down character and you write code using InputActionKey that uses the arrow keys for movement. You’ll quickly find that many players prefer to use “WASD” style controls. You can go back into your code and add the additional key checks, but this would result in duplicated/redundant code.\nInput actions can help to make your code more configurable. Rather than hard-coding specific keys, you’ll be able to modify and customize them without changing the code.\nCreating inputs You define input actions in the “Project Settings” under the “Input Map” tab. Here, you can create new actions and/or assign inputs to them.\nYou’ll see when you click on the tab there are already some default actions configured. They are all named “ui_*” to indicate that they are the default interface actions. “Tab” for next UI element, for example.\nGenerally speaking, you should create your own actions for your game, rather than use the existing ones.\nFor this example, let’s say you want to allow the player to control the game with the keyboard or the mouse. They need to be able to shoot by pressing either the left mouse button or the spacebar.\nCreate the new action “shoot” by typing the name in the “Action” field at the top and clicking “Add” (or pressing enter). Scroll to the bottom and you’ll see the new action has been added to the list.\nNow you can assign inputs to this action by clicking the “+” sign to the right. Inputs can be keys, mouse buttons, or joy/gamepad inputs. Choose “Key” and you can press the key on the keyboard you want to assign - let’s press the spacebar - and click “OK”.\nClick “+” to add another input, and this time choose “Mouse Button”. The default of “Device 0” and “Left Button” is fine, but you can select others if you like.\nUsing input actions You can check for the action either by polling the Input singleton every frame:\nfunc _process(delta): if Input.is_action_pressed(\"shoot\"): # This will execute every frame as long as the input is held. This is best for continuous actions - i.e. those you want to check constantly, such as movement.\nIf instead you want to detect the action at the moment it occurs, you can use the _input() or _unhandled_input() callbacks:\nfunc _unhandled_input(event): if event.is_action_pressed(\"shoot\"): # This will run once on the frame when the action is first pressed There are several functions you can use for checking input state:\nis_action_pressed(): This function returns true if the action is currently in the pressed state.\nis_action_released(): This function returns true if the action is not In the pressed state.\nis_action_just_pressed() / is_action_just_released(): These methods work like the above, but only return true on the single frame after the event occurs. This is useful for non-recurring actions like shooting or jumping where the user needs to let go and then press the key again to repeat the action.\nRelated Recipes Inputs: Introduction ","description":"","tags":null,"title":"Input Actions","uri":"/godot_recipes/4.x/input/input_actions/index.html"},{"content":"Problem You need a 3D camera that smoothly follows a target (interpolates).\nSolution Info Godot’s built-in InterpolatedCamera node is deprecated and will be removed in the release of Godot 4.0.\nAttach the script below to a Camera3D node in your scene. The three export properties let you choose:\nlerp_speed - the camera’s movement speed. Lower values result in a “lazier” camera. target - choose the camera’s target node. offset - position of the camera relative to the target. See below for some examples of the camera in action.\nextends Camera3D @export var lerp_speed = 3.0 @export var target: Node3D @export var offset = Vector3.ZERO func _physics_process(delta): if !target: return var target_xform = target.global_transform.translated_local(offset) global_transform = global_transform.interpolate_with(target_xform, lerp_speed * delta) look_at(target.global_transform.origin, target.transform.basis.y) In the _physics_process() function we interpolate the camera’s position with the target’s (plus offset).\nExamples lerp_speed: 3.0 offset: (0, 7, 5) ","description":"","tags":null,"title":"Interpolated Camera","uri":"/godot_recipes/4.x/3d/interpolated_camera/index.html"},{"content":" GDScript GDScript is Godot’s built-in scripting language. Its syntax is based on Python, so if you’re familiar with that language, you’ll feel right at home. In this chapter, we’ll introduce the language and get you up to speed with how it works.\nUpdating to Godot 4.0 We’re working on a new version of Godot 101 for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: Getting started ","description":"","tags":null,"title":"Introduction to GDScript","uri":"/godot_recipes/4.x/g101/gdscript/index.html"},{"content":" Know Your Nodes In the “Know Your Nodes” series, we go in-depth with a single one of Godot’s nodes. Learn what makes it tick and see some examples of how it’s used.\nIn this section: RayCast2D ","description":"","tags":null,"title":"Know Your Nodes","uri":"/godot_recipes/4.x/kyn/index.html"},{"content":"Problem You want to detect mouse input.\nSolution InputEventMouse is the base class for mouse events. It contains position and global_position properties. Inheriting from it are two classes: InputEventMouseButton and InputEventMouseMotion.\nNote You can assign mouse button events in the InputMap, so you can use them with is_action_pressed().\nInputEventMouseButton @GlobalScope.ButtonList contains a list of BUTTON_* constants for each possible button, which will be reported in the event’s button_index property. Note that the scrollwheel also counts as a button - two buttons, to be precise, with both BUTTON_WHEEL_UP and BUTTON_WHEEL_DOWN being separate events.\nTip Unlike regular buttons, mouse wheel clicks only produce pressed events. There is no concept of a mouse wheel click being “released”.\nfunc _unhandled_input(event): if event is InputEventMouseButton: if event.button_index == BUTTON_LEFT: if event.pressed: print(\"Left button was clicked at \", event.position) else: print(\"Left button was released\") if event.button_index == BUTTON_WHEEL_DOWN: print(\"Wheel down\") InputEventMouseMotion These events occur whenever the mouse moves. You can find the distance moved (in screen coordinates) with the relative property.\nHere’s an example using mouse movement to rotate a 3D character:\n# Converts mouse movement (pixels) to rotation (radians). var mouse_sensitivity = 0.002 func _unhandled_input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) ","description":"","tags":null,"title":"Mouse Input","uri":"/godot_recipes/4.x/input/mouse_input/index.html"},{"content":" Info Many thanks to @TheDuriel on the Godot Discord for the original diagram that inspired this article. Save this and keep it handy.\nProblem Your project has started getting complex. You have multiple scenes, instances, and a lot of nodes. You’ve probably found yourself writing code like the following:\nget_node(\"../../SomeNode/SomeOtherNode\") get_parent().get_parent().get_node(\"SomeNode\") get_tree().get_root().get_node(\"SomeNode/SomeOtherNode\") If you do this, you’ll soon find that node references like this break easily. As soon as you change one thing about your scene tree, none of those references may be valid anymore.\nCommunication between nodes and scenes doesn’t have to be complicated. There is a better way.\nSolution As a general rule, nodes should manage their children, not the other way around. If you’re using get_parent() or get_node(\"..\"), then you’re probably headed for trouble. Node paths like this are brittle, meaning they can break easily. The three main problems with this arrangement:\nYou can’t test a scene independently. If you run the scene by itself or in a test scene that doesn’t have the exact same node setup, get_node() will cause a crash.\nYou can’t change things easily. If you decide to rearrange or redesign your tree, paths will no longer be valid.\nReady order is children-first, parent-last. This means that trying to access a parent’s property in a node’s _ready() can fail because the parent isn’t ready yet.\nTip See Understanding tree order for an explanation of how nodes enter the tree and become ready.\nGenerally speaking, a node or scene should be able to be instanced anywhere in your game, and it should make no assumptions about what its parent is going to be.\nWe’ll go into detailed examples later in this tutorial, but for now, here’s the “golden rule” of node communication:\nCall down, signal up.\nIf a node is calling a child (i.e. going “down” the tree), then get_node() is appropriate.\nIf a node needs to communicate “up” the tree, it should probably use a signal.\nIf you keep this rule in mind when designing your scene setup, you’ll be well on your way to a maintainable, well-organized project. And you’ll avoid using the cumbersome node paths that lead to problems.\nNow, let’s look at each of these strategies along with some examples.\n1. Using get_node() get_node() traverses the scene tree using a given path to find the named node.\nTip See Understanding node paths for a more detailed explanation of node paths.\nget_node() example Let’s consider the following common configuration:\nThe script in the Player node needs to notify the AnimatedSprite2D which animation to play, based on the player’s movement. In this situation, get_node() works well:\nextends CharacterBody2D func _process(delta): if speed \u003e 0: get_node(\"AnimatedSprite2D\").play(\"run\") else: get_node(\"AnimatedSprite2D\").play(\"idle\") Tip In GDScript you can use $ as a shorthand for get_node(), writing $AnimatedSprite2D instead.\n2. Using signals Signals should be used to call functions on nodes that are higher in the tree or at the same level (i.e. “siblings”).\nYou can connect a signal in the editor (most often for nodes that exist before the game starts) or in code (for nodes that you’re instancing at runtime). The syntax for connecting a signal is:\nsignal_name.connect(target_node.target_function)\nLooking at this, you may be thinking “Wait, if I’m connecting to a sibling, won’t I need a node paths like ../Sibling?”. While you could do this, it breaks our rule above. The answer to this puzzle is to make sure that connections are made by the common parent.\nFollowing the rule of calling down the tree, a node that’s a common parent to the signaling and receiving nodes will by definition know where they are and be ready after both of them.\nSignal example A very common use case for signals is updating your UI. Whenever the player’s health variable changes, you want to update a Label or ProgressBar display. However, your UI nodes are completely separated from your player (as they should be). The player knows nothing about where those nodes are and how to find them.\nHere’s our example setup:\nNote that the UI is an instanced scene, we’re just showing the contained nodes. This is where you often see things like get_node(\"../UI/VBoxContainer/HBoxContainer/Label).text = str(health), which is what we want to avoid.\nInstead the player emits a health_changed signal whenever it adds/loses health. We need to send that signal to the UI’s update_health() function, which handles setting the Label value. In the Player script we use this code whenever the player’s health is changed:\nhealth_changed.emit(health) In the UI script we have:\nonready var label = $VBoxContainer/HBoxContainer/Label func update_health(value): label.text = str(value) Now we just need to connect the signal to the function. The perfect place to do that is in World, which is the common parent, and knows where both nodes are:\nfunc _ready(): $Player.health_changed.connect($UI.update_health) 3. Using groups Groups are another way to decouple, especially when you have a lot of similar objects that need to do the same thing. A node can be added to any number of groups and membership can be changed dynamically at any time with add_to_group() and remove_from_group().\nA common misconception about groups is that they are some kind of object or array that “contains” node references. Groups are a tagging system. A node is “in” a group if it has that tag assigned from it. The SceneTree keeps track of the tags and has functions like get_nodes_in_group() to help you find all nodes with a particular tag.\nGroup example Let’s consider a Galaga-style space shooter where you have a lots of enemies flying around. These enemies may have different types and behaviors. You’d like to add a “smart bomb” upgrade that, when activated, destroys all enemies on the screen. Using groups, you can implement this with a minimal amount of code.\nFirst, add all enemies to an “enemies” group. You can do this in the editor using the “Node” tab:\nYou can also add nodes to the group in your script:\nfunc _ready(): add_to_group(\"enemies\") Let’s assume every enemy has an explode() function that handles what happens when it dies (playing an animation, spawning dropped items, etc). Now that every enemy is in the group, we can implement our smart bomb function like this:\nfunc activate_smart_bomb(): get_tree().call_group(\"enemies\", \"explode\") 4. Using owner owner is a Node property that’s set automatically when you save a scene. Every node in that scene will have its owner set to the scene’s root node. This makes for a convenient way to connect child signals up to the main node.\nowner example In a complex UI, you often find yourself with a very deep, nested hierarchy of containers and controls. Nodes that the user interacts with, such as Button, emit signals, and you may want to connect those signals to the script on the UI’s root node.\nHere’s an example setup:\nThe script on the root CenterContainer has the following function, which we want to call whenever any button is pressed:\nextends CenterContainer func _on_button_pressed(button_name): print(button_name, \" was pressed\") The buttons here are instances of a Button scene, representing an object which may contain dynamic code that sets the button’s text or other properties. Or perhaps you have buttons that are dynamically added/removed from the container depending on the game state. Regardless, all we need to connect the button’s signal is the following:\nextends Button func _ready(): pressed.connect(owner._on_button_pressed.bind(name)) No matter where you place the buttons in the tree - if you add more containers, for example - the CenterContainer remains the owner.\nRelated recipes Understanding tree order Understanding node paths ","description":"","tags":null,"title":"Node communication (the right way)","uri":"/godot_recipes/4.x/basics/node_communication/index.html"},{"content":"Problem You want a rigid body to rotate smoothly to look at a target.\nSolution Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc.\nTo rotate a body, we need to apply a rotational force - a torque. Once the body is rotating, we want the torque to get smaller as we get closer to the final rotation.\nThis is the perfect situation to use the dot product. Its sign will tell us whether the target is to the left/right, and its magnitude will tell us how far away from the target direction we’re pointing.\nTip See Vectors: Using Dot and Cross Product for a brief review of the dot product.\nextends RigidBody2D var angular_force = 50000 var target = position + Vector2.RIGHT func _physics_process(delta): var dir = transform.y.dot(position.direction_to(target)) constant_torque = dir * angular_force You may be wondering why we’re using the transform.y here, when transform.x is the body’s forward vector. Using transform.x, the dot product would be at its maximum when the body is directly pointing at the target, but we want the torque to be zero at that point. Using transform.y means that our torque will be higher when we’re not aligned with the target.\nSkip the Rigid Body Entirely You can avoid all of this entirely by not rotating your rigid body at all! Instead, change the child sprite’s rotation to point at the target. You can use lerp() or a Tween to make the rotation as smooth as you wish.\nIn many cases, this will be a great solution. Remember, the underlying body’s orientation doesn’t have to match the attached sprite!\nRelated recipes Vectors: Using Dot and Cross Product ","description":"","tags":null,"title":"RigidBody2D: Look at Target","uri":"/godot_recipes/4.x/physics/smooth_rigid_rotate/index.html"},{"content":"Problem You want to shoot projectiles from your player/mob/etc..\nSolution Setting up the bullet First, we’ll set up a “bullet” object that we can instance. Here are the nodes we’ll use:\nArea2D: Bullet Sprite2D CollisionShape2D For the Sprite2D’s texture, you can use any image you like. Here’s an example one:\nSet up the nodes and configure the sprite and collision shape. If your texture is oriented pointing up, like the one above, make sure to rotate the Sprite node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.\nAdd a script and connect the Area2D’s body_entered signal.\nextends Area2D var speed = 750 func _physics_process(delta): position += transform.x * speed * delta func _on_Bullet_body_entered(body): if body.is_in_group(\"mobs\"): body.queue_free() queue_free() For this example, we’ll remove the bullet if it hits anything at all. We’ll also delete anything tagged in the “mobs” group that it hits.\nShooting We need to set up a spawn location for the bullets. Add a Marker2D and place it where you want the bullets to spawn. Here’s an example, placed at the barrel of the gun. I’ve named it “Muzzle”.\nNotice that as the player rotates, the Muzzle’s transform remains oriented the same way relative to the gun. This will be very convenient when spawning the bullets, as they can use the transform to get the proper position and direction. We just set the new bullet’s transform equal to the muzzle’s.\nTip This will work for any character type, not just the “rotate-and-move” style shown here. Just attach the Marker2D where you want the bullets to spawn.\nIn the character’s script we add a variable to hold the bullet scene for instancing:\n@export var Bullet : PackedScene And check for our defined input action:\nif Input.is_action_just_pressed(\"shoot\"): shoot() Now in our shoot() function we can instance a bullet and add it to the tree. A common mistake is to add the bullet as a child of the player:\nfunc shoot(): var b = Bullet.instantiate() add_child(b) b.transform = $Muzzle.transform The problem here is that since the bullets are children of the player, they are affected when the player moves or rotates.\nTo fix this, we should make sure the bullets are added to the world instead. In this case, we’ll use owner, which refers to the root node of the scene the player is in. Note that we also need to use the muzzle’s global transform, or else the bullet would not be where we expected.\nfunc shoot(): var b = Bullet.instantiate() owner.add_child(b) b.transform = $Muzzle.global_transform Related recipes Gamedev Math: transforms Download This Project Download the project code here: https://github.com/godotrecipes/2d_shooting\n","description":"","tags":null,"title":"Shooting projectiles","uri":"/godot_recipes/4.x/2d/2d_shooting/index.html"},{"content":"Project Manager The Project Manager is the first thing you’ll see when opening Godot.\nIn this window you can see a list of your Godot projects. You can choose an existing project and click “Run” to play the game or click “Edit” to work on it in the Godot editor. Since you probably don’t have any projects yet, let’s start by clicking the “New Project” button.\nHere you can give the project a name and create a folder to store it in.\nNote Every Godot project is contained in its own folder. This has many benefits, including making it easy to move, share, and backup projects. It also means that all the project’s files (images, sounds, etc.) must be in the project folder.\nWhen you’re naming your project, try to choose a name that describes the project. “New Game Project #23” is not going to help you remember what that project was. You should also think about compatibility: some operating systems are case-sensitive, and some are not. This can lead to problems if you move or share your project from one computer to another. For this reason, many programmers develop a standardized naming scheme. For example: “No spaces, use ‘_’ between words.”\nLet’s name this new project “getting_started”. Type this name, click Create Folder, and then click Create \u0026 Edit.\nYou’re now looking at the Godot editor window. This is where you’ll spend most of your time when working in Godot. The editor is divided into sections.\nViewport: This is where you’ll see the parts of your game as you’re working on them. Workspaces: At the center-top, you can switch between working in the 2D, 3D, or Script workspaces. You start in 3D. Playtest Buttons: These buttons let you launch and control your game when testing. Docks/Tabs: On both sides are a number of docks where you can view game items and set their properties. Bottom Panel: Here, you’ll see context-specific information for various tools. The most important one to note first is the Output panel, where you’ll see any error or informational messages when your game is running. Project Settings Now we’ve talked about the main parts of the Godot window and how they work, let’s spend a little time talking about our Project settings. Usually one of the first tasks when starting a new project is make sure it’s all set up correctly.\nSo let’s click on Project in the menu and select Project Settings.\nThis is the Project settings window. On the left is a list of categories. For most projects, the default settings will be fine, and you shouldn’t worry about changing them unless you have a very specific need. For now, we’re just going to look at two of the sections. First, Application/Config.\nIn here, you can set your game’s title, choose which scene is the “main scene” (more about that in a bit), and change the icon.\nSecond, let’s look at the Display section. This is where you set up your game’s display. width \u0026 height let you set the size of the game window. If, for example, you were making a mobile game, you’d want to set this to the resolution and proportions of your target device. There are also settings for scaling, stretching, fullscreen mode, and more. For now, we’ll leave the default size - later on we’ll talk about how to adjust these to get our game running on different devices.\nThere are also some tabs across the top. We’ve been looking at the General tab. I’ll also point out briefly, the Input Map. This is where you can define different input actions for keyboard control, gamepad, mouse, and so on. In your game, you’ll just worry about the action, not what individual key or button was pressed. This is a very powerful and flexible way of handling player input.\nWe also have localization options, if you plan to support multiple languages. Autoloading, which we’ll get to later, and plugins. The Godot community has created a variety of useful plugins that you can download and add to supply more features, different tools, and so on.\nWe’ll come back to the project settings window later. Let’s close it for now and we’re ready to move on to the next step: working with nodes.\n","description":"","tags":null,"title":"The Godot Editor: Finding your way around","uri":"/godot_recipes/4.x/g101/start/101_02/index.html"},{"content":"Problem It’s probably the most common problem seen in the Godot help channels: an invalid node reference. Most often, it appears as the following error message:\nInvalid get index ‘position’ (on base: ’null instance’).\nSolution It’s that last part, the “null instance”, that’s the source of this problem, and the main source of confusion for Godot beginners.\nThe way to avoid this problem is to understand the concept of node paths.\nUnderstanding node paths The scene tree is made of nodes, which are connected together in parent-child relationships. A node path is the path it takes to get from one node to another by moving through this tree.\nAs an example, let’s take a simple “Player” scene:\nThe script for this scene is on the Player node. If the script needs to call play() on the AnimatedSprite node, it needs a reference to that node:\nget_node(\"AnimatedSprite\").play() The argument of the get_node() function is a string representing the path to the desired node. In this case, it’s a child of the node the script is on. If the path you give it is invalid, you’ll get the dreaded null instance error (as well as “Node not found”).\nGetting a node reference with get_node() is such a common situation that GDScript has a shortcut for it:\n$AnimatedSprite.play() Info get_node() returns a reference to the desired node.\nLet’s look at a more complex scene tree:\nIf the script on Main needs to access ScoreLabel it can do so with this path:\nget_node(\"HUD/ScoreLabel\").text = \"0\" # or using the shortcut: $HUD/ScoreLabel.text = \"0\" Tip When using $ notation, the Godot editor will autocomplete paths for you. You can also right-click on a node in the Scene tab and choose “Copy Node Path”.\nWhat if the node you want to access is higher in the tree? You can use get_parent() or \"..\" to reference the parent node. In the above example tree, to get the Player node from the ScoreLabel:\nget_node(\"../../Player\") Let’s break that down. The path \"../../Player\" means “get the node that’s up one level (HUD), then one more level (Main), then its child Player”.\nTip Does this seem familiar? Node paths work exactly like directory paths in your operating system. The / character indicates the parent-child relationship, and .. means “up one level”.\nRelative vs absolute paths The above examples all use relative paths - meaning they start at the current node and follow the path to the destination. Node paths can also be absolute, starting from the root node of the scene.\nFor example, the absolute path to the player node is:\nget_node(\"/root/Main/Player\") /root, which can also be accessed with get_tree().root is not the root node of your scene. It’s the Viewport node that is always present by default in the SceneTree.\nA warning While the above examples work just fine, there are some things you should be aware of that may cause problems later. Imagine the following situation: the Player node has a health property, which you want to display in a HealthBar node somewhere in your UI. You might write something like this in the player’s script:\nfunc take_damage(amount): health -= amount get_node(\"../Main/UI/HealthBar\").text = str(health) While this may work fine at first, it is brittle, meaning it can break easily. There are two main problems with this kind of arrangement:\nYou can’t test the player scene independently. If you run the player scene by itself or in a test scene that doesn’t have a UI, the get_node() line will cause a crash. You can’t change your UI. If you decide to rearrange or redesign your UI, the path will no longer be valid and you have to change it. For this reason, you should try to avoid using node paths that go up the scene tree. In the above situation, if the player instead emitted a signal when the health changed, the UI could listen for that signal to update itself. You could then rearrange and separate nodes without fear of breaking your game.\nWrapping up Once you understand how to use node paths, you’ll see how easy it is to reference any node you need. And put a stop to seeing those null instance error messages.\n","description":"","tags":null,"title":"Understanding node paths","uri":"/godot_recipes/4.x/basics/getting_nodes/index.html"},{"content":"Before reading this, make sure you have an understanding of vectors and how they’re used in game development. If you don’t, I recommend you read this introduction I wrote for the Godot documentation: Vector Math.\n2D Transforms In 2D space, we use the familiar X-Y coordinate plane. Remember that in Godot, as in most computer graphics applications, the Y axis points downward:\nTo begin, let’s consider this spaceship floating in space:\nThe ship is pointing in the same direction as the X axis. If we wanted it to move forward, we could add to its X coordinate and it would move to the right:\nposition += Vector2(10, 0) But what happens when the ship rotates?\nHow do we move the ship forward now? If you remember Trigonometry from school, you might be starting to think about angles, sine and cosine and doing something like position += Vector2(10 * cos(angle), 10 * sin(angle)). While this would work, there’s a much more convenient way: the Transform.\nLet’s look at the rotated ship again, but this time, let’s also imagine that the ship has its own X and Y axes that it carries with it, independent of the global axes:\nThese “local” axes are contained in the object’s transform.\nKnowing this, we can move the ship forward by moving it along its own X axis and we won’t have to worry about angles and trig functions. To do this in Godot, we can use the transform property, which is available to all Node2D derived nodes.\nposition += transform.x * 10 This code says “Add the transform’s x vector multiplied by 10.” Let’s break down what that means. The transform contains x and y properties that represent those local axes. They are unit vectors, which means their length is 1. Another term for unit vector is direction vector. They tell us the direction the ship’s x axis is pointing. We then multiply by 10 to scale it to a longer distance.\nTip The transform property of a node is relative to its parent node. If you need to get the global value, it’s available in global_transform.\nIn addition to the local axes, the transform also contains a component called the origin. The origin represents the translation, or change in position.\nIn this picture, the blue vector is the transform.origin. It is equal to the object’s position vector.\nConverting Between Local and Global Space You can convert coordinates from local to global by applying the transform. For convenience, Node2D and Spatial include helper functions for this: to_local() and to_global():\nvar global_position = to_global(local_position) Let’s use the example of an object in the 2D plane and convert mouse clicks (global space) into coordinates relative to the object:\nextends Sprite func _unhandled_input(event): if event is InputEventMouseButton and event.pressed: if event.button_index == BUTTON_LEFT: printt(event.position, to_local(event.position)) See the Transform2D docs for a list of the available properties and methods.\n3D Transforms In 3D space, the concept of transforms applies in the same way as in 2D. In fact, it becomes even more necessary, as using angles in 3D can lead to a variety of problems, as we’ll see in a bit.\n3D nodes inherit from the base node Node3D, which contains the transform information. The 3D transform requires more information than the 2D version. Position is still held in the origin property, but rotation is in a property called basis, which contains three unit vectors representing the body’s local X, Y, and Z axes.\nWhen you select a 3D node in the editor, the gizmo that appears allows you to manipulate the transform.\nLocal Space Mode In the editor, you can see and manipulate the body’s local orientation by clicking the “Local Space Mode” button. When in this mode, the 3 colored axis lines represent the body’s local basis axes.\nAs in 2D, we can use the local axes to move an object forward. In Godot’s 3D orientation (Y-up), this means that by default the body’s -Z axis is the forward direction. To move forward:\nposition += -transform.basis.z * speed * delta Tip Godot has default vector values defined, for example: Vector3.FORWARD == Vector3(0, 0, -1). See Vector2 and Vector3 for details.\n","description":"","tags":null,"title":"Transforms","uri":"/godot_recipes/4.x/math/transforms/index.html"},{"content":" 2D Tips, tricks, and tutorials on the 2D side of game development.\nIn this section: Entering/Exiting the screen Platform character Screen wrap Top-down movement Grid-based movement Shooting projectiles Car steering 8-Directional Movement/Animation Using Y-Sort Coyote Time Moving Platforms Pathfinding on a 2D Grid Multitarget Camera ","description":"","tags":null,"title":"2D","uri":"/godot_recipes/4.x/2d/index.html"},{"content":"Problem You need to add actions to the InputMap at runtime.\nSolution Typically, you’ll add actions to the InputMap via Project Settings, as shown in Recipe: Input Actions. However, you may find yourself needing to add one or more actions directly in a script. The InputMap singleton has methods to help you do this.\nHere’s an example that would add a new action called “attack” using the space key:\nfunc _ready(): InputMap.add_action(\"attack\") var ev = InputEventKey.new() ev.keycode = KEY_SPACE InputMap.action_add_event(\"attack\", ev) If you also wanted to add the left mouse button to the same action:\nev = InputEventMouseButton.new() ev.button_index = MOUSE_BUTTON_LEFT InputMap.action_add_event(\"attack\", ev) Note InputMap.add_action() will produce an error if the action already exists. You should check first with InputMap.has_action() before attempting to add a new action.\nPractical Example Let’s say you’ve made the platform character from Recipe: Platform character and you want to re-use it in another project. If you saved the scene, script, and assets in a single folder, you need only copy that folder to your new project. But you’d still need to edit the Input Map in order for the inputs to work.\nInstead, you could add the following code to the player script and be sure that the necessary input actions will be added automatically:\nvar controls = {\"walk_right\": [KEY_RIGHT, KEY_D], \"walk_left\": [KEY_LEFT, KEY_A], \"jump\": [KEY_UP, KEY_W, KEY_SPACE]} func _ready(): add_inputs() func add_inputs(): var ev for action in controls: if not InputMap.has_action(action): InputMap.add_action(action) for key in controls[action]: ev = InputEventKey.new() ev.keycode = key InputMap.action_add_event(action, ev) Related recipes Input Actions Platform Character ","description":"","tags":null,"title":"Adding Input Actions in code","uri":"/godot_recipes/4.x/input/custom_actions/index.html"},{"content":"Problem You want to hide the mouse cursor and keep the mouse from leaving the game window. This is common in many 3D games (and some 2D ones).\nSolution You can set the mouse state using Input.mouse_mode. There are four possible mouse modes:\nMOUSE_MODE_VISIBLE: The mouse is visible and can move freely into and out of the window. This is the default state.\nMOUSE_MODE_HIDDEN: The mouse cursor is invisible, but the mouse can still move outside the window.\nMOUSE_MODE_CAPTURED: The mouse cursor is hidden and the mouse is unable to leave the game window.\nMOUSE_MODE_CONFINED: The mouse is visible, but cannot leave the game window.\n“Captured” is the most commonly used option. You can set the mouse mode at runtime using:\nfunc _ready(): Input.mouse_mode = Input.MOUSE_MODE_CAPTURED When the mouse is captured, mouse input events will still be passed as normal. However, you will find there is a problem. If you want to close the game or switch to another window, you can’t. For this reason, you will want to also include a way to “release” the mouse. For example, to release when the player pressed the Escape key:\nfunc _input(event): if event.is_action_pressed(\"ui_cancel\"): Input.mouse_mode = Input.MOUSE_MODE_VISIBLE So that the game doesn’t respond to mouse movement when you’re in another window, you can test for the capture state in your character controller using:\nif Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: Once the mouse is released, that leaves the need to re-capture it to continue playing. Assuming you have an event in the Input Map for a mouse click, you can do the following:\nif event.is_action_pressed(\"click\"): if Input.mouse_mode == Input.MOUSE_MODE_VISIBLE: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED Since you may also be using a mouse click to shoot or perform some other action, it’s probably a good idea to stop the event from propagating. Add this after setting the mouse mode:\nget_tree().set_input_as_handled() ","description":"","tags":null,"title":"Capturing the Mouse","uri":"/godot_recipes/4.x/input/mouse_capture/index.html"},{"content":"Problem You need to create a 2D top-down car controller.\nSolution When approaching this problem, beginners often wind up creating something that handles nothing like a real car. Some common mistakes you’ll find in amateur car games:\nA car doesn’t rotate around its center. Put another way, a car’s rear wheels don’t slide side-to-side. (Unless it’s drifting, but we’ll talk about that later.) A car can only turn when it’s moving - it can’t spin in place. A car isn’t a train; it’s not on rails. Turning at high speeds should involve some sliding (drifting). There are many approaches to 2D car physics, mainly depending on how “realistic” you want to be. For this solution, we’re going for an “arcade” level of realism, meaning we’ll prioritize action over realism.\nNote The method below is based on the algorithm found here: http://engineeringdotnet.blogspot.com/2010/04/simple-2d-car-physics-in-games.html\nThe recipe below is broken into 5 parts, each adding a different feature to the car’s movement. Feel free to mix-and-match for your needs.\nScene setup Here’s the car scene setup:\nCharacterBody2D Sprite2D CollisionShape2D Camera2D Add whatever sprite texture you like. For this demo, we’ll use art from Kenney’s Racing Pack. CapsuleShape2D is a good choice for the collision, so that the car won’t have sharp corners to get caught on obstacles.\nWe’ll also use four input actions: “steer_right”, “steer_left”, “accelerate”, and “brake” - set them to whatever key inputs you prefer.\nPart 1: Movement The first step is to code the movement based on the algorithm described above.\nStart with a few variables:\nextends CharacterBody2D var wheel_base = 70 # Distance from front to rear wheel var steering_angle = 15 # Amount that front wheel turns, in degrees var steer_direction Set wheelbase to a value that works with your sprite.\nsteer_direction will be the amount that the wheels are turned.\nNote Since we’re using keyboard controls, turning is all-or-nothing. If you’re using an analog joystick, you can instead vary this value based on the distance the stick moves.\nfunc _physics_process(delta): get_input() calculate_steering(delta) move_and_slide() Each frame, we need to check for input and calculate steering. Then we pass the resulting velocity to move_and_slide(). We’ll define those two function next:\nfunc get_input(): var turn = Input.get_axis(\"steer_left\", \"steer_right\") steer_direction = turn * deg_to_rad(steering_angle) velocity = Vector2.ZERO if Input.is_action_pressed(\"accelerate\"): velocity = transform.x * 500 Here we check for user input and set the velocity. Note: the speed of 500 is temporary so that we can test movement. We’ll address it in the next part.\nHere is where we implement the algorithm from the link:\nfunc calculate_steering(delta): # 1. Find the wheel positions var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 # 2. Move the wheels forward rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_direction) * delta # 3. Find the new direction vector var new_heading = rear_wheel.direction_to(front_wheel) # 4. Set the velocity and rotation to the new direction velocity = new_heading * velocity.length() rotation = new_heading.angle() Run the project and the car should move and turn. It’s still very unnatural though - the car starts and stops instantly. To fix that, we’ll add acceleration into the calculation.\nPart 2: Acceleration We’ll need another setting variable and one to track the car’s overall acceleration:\nvar engine_power = 900 # Forward acceleration force. var acceleration = Vector2.ZERO Change the input code to apply acceleration instead of directly changing the car’s velocity.\nfunc get_input(): var turn = Input.get_axis(\"steer_left\", \"steer_right\") steer_direction = turn * deg_to_rad(steering_angle) if Input.is_action_pressed(\"accelerate\"): acceleration = transform.x * engine_power Once we’ve got our acceleration, we can apply it to the velocity like so:\nfunc _physics_process(delta): acceleration = Vector2.ZERO get_input() calculate_steering(delta) velocity += acceleration * delta move_and_slide() Now when you run, the car should gradually increase its speed. Careful: we don’t have any way to slow down yet!\nPart 3: Friction/drag A car experiences two different deceleration forces: friction and drag.\nFriction is the force applied by the ground. It’s very high if driving on sand, but very low if driving on ice. Friction is proportional to velocity - the faster you’re going the stronger the force.\nDrag is the force resulting from wind resistance. It’s based on the car’s cross-section - a large truck or van experiences more drag than a sleek race car. Drag is proportional to the velocity squared.\nThis means that friction is more significant when moving slowly, but drag becomes dominant at high speeds. We’ll add both of these forces to our calculation. As a bonus, the values of these quantities will also give our car a maximum speed - the point where the force from the engine can’t overcome the drag force any longer.\nHere are our starting values for these quantities:\nvar friction = -55 var drag = -0.06 As you can see in this graph, these values mean that at a speed of 600 the drag force overcomes the friction force.\nYou can play with the values here to see how they change: https://www.desmos.com/calculator/e4ayu3xkip\nIn _physics_process() we’ll call a function to calculate the current friction and apply it to the acceleration force.\nfunc _physics_process(delta): acceleration = Vector2.ZERO get_input() apply_friction(delta) calculate_steering(delta) velocity += acceleration * delta velocity = move_and_slide(velocity) func apply_friction(delta): if acceleration == Vector2.ZERO and velocity.length() \u003c 50: velocity = Vector2.ZERO var friction_force = velocity * friction * delta var drag_force = velocity * velocity.length() * drag * delta acceleration += drag_force + friction_force First, we’ll set a minimum speed. This will ensure that the car doesn’t keep creeping forward at very low speeds as friction never quite brings the velocity to zero.\nThen we calculate the two forces and add them to the total acceleration. Since they’re both negative, they’ll affect the car in the opposite direction.\nPart 4: Reverse/Brake We’ll need two more settings variables:\nvar braking = -450 var max_speed_reverse = 250 Add the input to get_input():\nif Input.is_action_pressed(\"brake\"): acceleration = transform.x * braking This is fine for coming to a stop, but we also want to be able to put the car in reverse. Currently, that won’t work, because the acceleration is always being applied in the “heading” direction, which is forward. When we’re reversing, we need to accelerate backward.\nfunc calculate_steering(delta): var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_angle) * delta var new_heading = (front_wheel - rear_wheel).normalized() var d = new_heading.dot(velocity.normalized()) if d \u003e 0: velocity = new_heading * velocity.length() if d \u003c 0: velocity = -new_heading * min(velocity.length(), max_speed_reverse) rotation = new_heading.angle() We can find whether we’re accelerating forward or backward using the dot product. If the two vectors are aligned, the result will be greater than 0. If the movement is in the opposite direction the car’s facing, then the dot product will be less than 0 and we must be moving backward.\nPart 5: Drift/slide We could stop here and you’d have a satisfactory driving experience. However, the car still feels like it’s “on rails”. Even at top speed, the turns are perfect, as if the tires have perfect “grip”.\nAt high speeds (or even low ones, if desired), the turning force should cause the tires to slip and result in a fishtailing/sliding motion.\nvar slip_speed = 400 # Speed where traction is reduced var traction_fast = 2.5 # High-speed traction var traction_slow = 10 # Low-speed traction We’ll apply these values when calculating the steering. Currently, the velocity is instantly set to the new heading. Instead, we’ll use interpolation - lerp() - to cause it to only “turn” partway towards the new direction. The “traction” values will determine how “sticky” the tires are.\nfunc calculate_steering(delta): var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_angle) * delta var new_heading = (front_wheel - rear_wheel).normalized() # choose which traction value to use - at lower speeds, slip should be low var traction = traction_slow if velocity.length() \u003e slip_speed: traction = traction_fast var d = new_heading.dot(velocity.normalized()) if d \u003e 0: velocity = lerp(velocity, new_heading * velocity.length(), traction * delta) if d \u003c 0: velocity = -new_heading * min(velocity.length(), max_speed_reverse) rotation = new_heading.angle() Here, we select which traction value to use and apply lerp() to the velocity.\nAdjustments At this point, we have a large number of settings that control the car’s behavior. Adjusting them can drastically change how the car drives. To make experimenting with different values easier, download the project for this recipe below. When you run the game, you’ll see a set of sliders you can use to change the car’s behavior as you drive (press \u003cTab\u003e to show/hide the slider panel).\nRelated recipes Gamedev Math: Interpolation Download This Project Download the project code here: https://github.com/godotrecipes/2d_car_steering\n","description":"","tags":null,"title":"Car steering","uri":"/godot_recipes/4.x/2d/car_steering/index.html"},{"content":"In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.\nAdding a script Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. Our Player scene displays the ship, defines its collision hitbox, etc., but it can’t move, and nothing would happen if it collided. We’ll write code to add this functionality to the ship.\nSelect the Player node and click the Attach script button:\nYou don’t need to change any of the options on the Attach Node Script window, so just click Create and you’ll be taken to the script editor.\nLet’s look at the first line of the script, which has automatically been added.\nextends Area2D This line defines what type of object this script should be attached to. It means that the script will have access to all the functionality that an Area2D provides.\nYour extends line should always match the type of node the script is attached to.\nAccessing scripts A script on its own doesn’t do much of anything. Scripts define additional functionality for whatever object they’re attached to. You will never be accessing a variable in some script, you’ll be accessing a property of an object, which is defined by that script. This is a very important distinction.\nMovement We’ll start by making the ship move around the screen. Let’s start with some code that does the following:\nDetect what input(s) the player is pressing Move the ship in the direction of the input @export var speed = 150 func _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") position += input * speed * delta Let’s break this down line-by-line:\nAdding @export in front of a variable allows you to adjust its value in the Inspector. The _process() function is called once every frame by the engine. Any code we place in this function will be executed every frame. Input.get_vector() checks the pressed state of the four given inputs and produces a vector pointing in that direction. Finally, we move the ship’s position by adding that input vector, scaling it to the desired speed, and multipling by delta. Links to more information Understanding vectors: Vector Math What is delta? Understanding delta Run the scene by clicking the Run Current Scene button, and try moving around.\nStaying on screen One problem we have is that if you keep moving, you’ll go off the screen. We need to lock the player’s position property inside the bounds of the screen rectangle. Add this line at the top of the script:\n@onready var screensize = get_viewport_rect().size The @onready here tells Godot not to set the value of the screensize variable until the Player node has entered the scene tree. Effectively, it means “wait until the game starts”, because there’s no window to get the size of until the game is running.\nThe next step is to clamp the position within the bounds of that screensize rectangle. Vector2, which is what position is, has a clamp() method we can use. Put this line right after setting the position:\nfunc _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") position += input * speed * delta position = position.clamp(Vector2.ZERO, screensize) Run the scene again and try moving off the edges. You’ll notice that half of the ship still goes off screen. This is because the ship’s position is the center of the Sprite2D. Since we know our ship is 16x16, we can change the clamp() to include 8 extra pixels:\nposition = position.clamp(Vector2(8, 8), screensize - Vector2(8, 8)) Matching animation to direction Now that the ship is moving, we can choose the “tilted” ship images when moving left or right, as well as the matching “Booster” animation.\nTo tell which direction we’re moving, we can check the x value of the input vector. Depending on whether it’s positive (right), negative (left), or zero (not moving), we can choose the frame value of the Sprite2D and the animation of the AnimatedSprite2D.\nfunc _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") if input.x \u003e 0: $Ship.frame = 2 $Ship/Boosters.animation = \"right\" elif input.x \u003c 0: $Ship.frame = 0 $Ship/Boosters.animation = \"left\" else: $Ship.frame = 1 $Ship/Boosters.animation = \"forward\" position += input * speed * delta position = position.clamp(Vector2(8, 8), screensize-Vector2(8, 8)) Once again, play the scene and verify that the images change when moving left/right. Verify that everything works as intended before moving to the next step.\nThe next step will be to create the Bullet scene and let the player shoot.\nPrev Next ","description":"","tags":null,"title":"Coding the Player","uri":"/godot_recipes/4.x/games/first_2d/first_2d_03/index.html"},{"content":"In the last part, we covered how to import 3D objects and how to arrange them in a scene. In this installment, we’ll add more objects to the scene, including a user-controlled character.\nBuilding the Scene We’re going to continue using the Kenney Platformer Kit we downloaded in Part 2. Select all the block*.glb files and in the Import tab set their Root Type to StaticBody3D. Uncheck the Root Name property and click Reimport. Select blockLarge.glb and make a new inherited scene. Use the Create Single Convex Collision Sibling option on the mesh using the menu as you did in the last tutorial. Now you can save the scene - I recommend making a separate folder for this, as soon you’re going to have a bunch of scenes representing the differently shaped platform parts.\nOpen the scene from the previous step with the “Ground” plane and the crates. Delete the crates and add an instance of the large block. We want to be able to place these blocks so that they line up. To do this, select “Configure Snap” from the “Transform” menu at the top of the Viewport and set Translate Snap to 0.5. Then click on the “Snap Mode” button (or press the Y key). Now duplicate the block a few times and drag them to arrange.\nIf you like, go ahead and add scenes for some of the other platform blocks and arrange them into a pleasing level. Be creative!\nAdding a Character Now we’re going to make a character so we can walk around on the platforms. Open a new scene and start with a CharacterBody3D named “Character”. This PhysicsBody node behaves very much like its 2D equivalent (you’ve already done the 2D tutorials, right?). It has a move_and_slide() method that we’ll use to perform the movement and collision detection.\nAdd a capsule-shaped MeshInstance3D and a matching CollionShape3D. Remember, you can add a StandardMaterial3D to the mesh and set its Albedo/Color property to change the color.\nThe capsule is nice, but it’s going to be hard to tell what direction it’s facing. Let’s add another mesh, this time with a CylinderMesh3D shape. Set its Top Radius to 0.2, its Bottom Radius to 0.001 and its Height to 0.5, then its x rotation to -90 degrees. Now you have a nice cone shape. Arrange it so it’s pointing out from the body along the negative z axis. (You can tell which way is negative because the gizmo arrows point in the positive direction).\nIn this picture, we’ve also added two sphere meshes for eyes to give a little more character. Feel free to add whatever details you like.\nLet’s also add a Camera3D to the scene, so it will follow the player around. Position the camera behind and above the character, angling it down a bit. Click the “Preview” button to check the camera’s view.\nBefore we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:\nInput Action Key move_forward W move_back S strafe_right D strafe_left A jump Space Now let’s add a script to the body.\nextends CharacterBody3D var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var speed = 4.0 # movement speed var jump_speed = 6.0 # determines jump height var mouse_sensitivity = 0.002 # turning speed func get_input(): var input = Input.get_vector(\"strafe_left\", \"strafe_right\", \"move_forward\", \"move_back\") velocity.x = input.x * speed velocity.z = input.y * speed func _physics_process(delta): velocity.y += -gravity * delta get_input() move_and_slide() The code in _physics_process() is pretty straightforward: add gravity to accelerate in the positive Y direction (downward), call get_input() to check for input, and then use move_and_slide() to move in the direction of the velocity vector.\nIn get_input() we check to see which key is pressed and then move in that direction. Run the program and test:\nThis is all good, but we need to be able to rotate using the mouse. Add the following code to the character’s script:\nfunc _unhandled_input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) This will convert any mouse motion in the x direction into a rotation around the y axis.\nRun the scene and confirm that moving the mouse rotates the character:\nHowever, there’s a problem. No matter which way we’re facing, pressing W moves us along the Z axis of the world. Our movement is using global coordinates, but we need to move in the object’s forward direction.\nThe Power of Transforms This is where transforms come in. A transform is a mathematical matrix that contains the object’s translation, rotation, and scale information all in one. In Godot it’s stored in the Transform data type. The position information is called the transform.origin and the orientation information is in the transform.basis.\nRemember how the 3D gizmo can be set to “Local Space Mode”? When in this mode, the gizmo’s X/Y/Z axes point along the object’s axes. This is the same as the basis of the transform. The basis contains three Vector3 objects called x, y, and z that represent these directions. We can use this to ensure that pressing the W key will always move us in the object’s forward direction.\nChange the get_input() function like so:\nfunc get_input(): var input = Input.get_vector(\"strafe_left\", \"strafe_right\", \"move_forward\", \"move_back\") var movement_dir = transform.basis * Vector3(input.x, 0, input.y) velocity.x = movement_dir.x * speed velocity.z = movement_dir.z * speed By multiplying the input vector by the transform.basis, we apply that transformation to the vector. Since the basis represents the object’s rotation, we’ve now converted forward and back to point along the object’s Z axis, and the strafe keys along its X.\nJumping Let’s add one more movement to the player: jumping.\nAdd these lines to the end of _unhandled_input():\nif event.is_action_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed Improving the camera You may have noticed that the if the character stands near an obstacle, the camera can “clip” inside the object, which doesn’t look nice. While coding a good 3D camera can be a complex topic on its own, we can use a built-in Godot node to get a pretty good solution.\nDelete the Camera3D from the character scene and add a SpringArm3D. This node can act as a moving arm that holds the camera while detecting collisions. It will move the camera closer if there’s an obstacle.\nIn its properties, set Spring Length to 5, and set its Position to (0, 1, 0), which is at the character’s head. Note the yellow line indicating the Spring Length. The camera will move along this line - at its end whenever possible, but moving closer if an obstacle is there.\nAdd back a Camera3D as a child of the SpringArm3D, and try running the game again. You can experiment with rotating the spring arm (around its x axis to point down slightly, for example) until you find something you like.\nWhat about first person? If you’re curious how you would do this in first person, see the Basic FPS Character recipe. You’ll notice several similarities with the 3rd person script we wrote above.\nWrapping Up In this tutorial you learned how to build a more complex scene, and how to write movement code for a user-controlled character. You also learned about transforms, which are a very important concept in 3D - you’re going to be using a lot in the future.\n","description":"","tags":null,"title":"Creating a 3D Character","uri":"/godot_recipes/4.x/g101/3d/101_3d_03/index.html"},{"content":"Nodes are the basic building blocks for creating games in Godot. A node is an object that can represent some kind of specialized game function. A given type of node might display graphics, play an animation, or represent a 3D model of an object. The node also contains a collection of properties, allowing you to customize its behavior. Which nodes you add to your project will depend on what functionality you need. It’s a modular system designed to give you flexibility in building your game objects.\nWorking with Nodes Nodes are objects, in the programming sense. They encapsulate data and behavior, and they can inherit properties from other nodes. Rather than use one of the default suggestions, let’s click the “Add/Create a New Node” button in the scene dock.\nHere you’ll see the whole hierarchy of node types available in the engine. For example, the nodes with the bluish icons all fall under the “Node2D” category, meaning they will all have the properties of a Node2D. More about that in a moment.\nThe list is long, and it would be frustrating to have to drill down every time to find the node you need. Instead, you can use the search function to find it using a small number of characters. We’re looking for the Sprite2D node, so I’ll just type “sp” and we’ll jump right to it. Click “Create” to add the node.\nNow we have this Sprite2D node in our Scene dock. Make sure it’s selected, and then look at the Inspector dock on the right side. Over here, you’ll see all the properties of whatever node you have selected. Notice that the properties are organized by where they come from. The Sprite2D node inherits from Node2D, which inherits from CanvasItem, which inherits from the plain old Node.\nOver in the viewport, the sprite doesn’t look like much. A sprite’s purpose is to display an image, or texture. As you can see in the Inspector, the Texture property is currently empty. Fortunately, every new Godot project comes with an image we can use: the Godot icon. Drag the icon from the Filesystem dock and drop it in the texture property.\nIn the Inspector, click to expand the “Transform” section, and type (50, 50) in the Position property.\nYou can also click and drag the sprite around in the viewport, and you’ll see the Position values changing as you move.\nOne important property of nodes is that they can be arranged in a parent-child hierarchy. Make sure you have the Sprite2D selected and press the add button again. Add another Sprite2D and also drag the icon into its texture.\nThis new sprite is a child of the first. This means that it’s “attached” to its parent. If the parent sprite moves, so will the child. Click on the child sprite and set its Position to (50, 50). Now click and drag the parent sprite to move it around the screen.\nNotice that the Position of the parent is changing as you move it around. Now check the child: it’s still (50, 50). That’s because its “Transform” properties are relative to its parent.\nScenes Grouping nodes together like this is a powerful tool, enabling you to construct complex objects out of node “building blocks”. For example, a “Player” node in your game might have many child nodes attached to it: a Sprite2D for display, an AnimationPlayer to animate it, a Camera2D to follow it around, and so on.\nA group of nodes arranged in a “tree” structure like this is called a Scene. In the next part, we’ll look at how you can use scenes to organize your game’s objects into independent parts that all work together. You’ll see this in practice was you work through the examples in later lessons.\n","description":"","tags":null,"title":"Nodes: Godot's building blocks","uri":"/godot_recipes/4.x/g101/start/101_03/index.html"},{"content":"Problem You need to implement shooting in an FPS, but moving individual projectiles is impractical.\nSolution Game physics engines often break down when trying to handle very fast-moving objects. The solution is to cast a ray from the shooter’s location and detect the first thing that would be hit.\nThere are two ways to approach raycasting in Godot: the RayCast3D node, or directly casting a ray in space using the physics engine. While they can both accomplish the same thing, each has its uses. The node method tends to be best for situations where you continuously want to check for collisions - a downward-facing ray to check if you’re on the floor, for example.\nWe’ll use the second method, querying the physics state, because we want to know, at the moment we press the “shoot” key, whether we’ve hit anything.\nNote This recipe assumes you already have a working FPS character controller and a world to move around in. If you don’t, see the Basic FPS Character recipe first.\nTo display what we’ve hit, add a CanvasLayer with a Label node to the FPSPlayer scene.\nWe’ll add an input check in the _input() function, which we’re already using to handle mouse input.\nif event.is_action_pressed(\"shoot\"): shoot() Then we’ll define the shoot() method. Whenever it’s called, we want to build a PhysicsRayQueryParameters3D object, which defines the start (position of the camera) and end (position of the camera projected forward by 100 meters) points of the ray. We’ll pass this to the physics engine using the direct_space_state of the world. If we get a returned value (a dictionary containing data about the collision), we’ll update the label so we can see what kind of object we hit.\nfunc shoot(): var space = get_world_3d().direct_space_state var query = PhysicsRayQueryParameters3D.create($Camera3D.global_position, $Camera3D.global_position - $Camera3D.global_transform.basis.z * 100) var collision = space.intersect_ray(query) if collision: $CanvasLayer/Label.text = collision.collider.name else: $CanvasLayer/Label.text = \"\" Related recipes Basic FPS Character Download This Project Download the project code here: https://github.com/godotrecipes/3d_shoot_raycasts\n","description":"","tags":[],"title":"Shooting with Raycasts","uri":"/godot_recipes/4.x/3d/shooting_raycasts/index.html"},{"content":"Problem The delta or “delta time” parameter is a frequently-misunderstood concept in game development. In this tutorial, we’ll explain how it’s used, the importance of frame-rate independent movement, and practical examples of its use in Godot.\nSolution To illustrate the problem, let’s consider a Sprite node moving across the screen. If our screen is 600 pixels wide and we want the sprite to take 5 seconds to cross the screen, we can use the following calculation to find the necessary speed:\n600 pixels / 5 seconds = 120 pixels/second We’ll move the sprite every frame using the _process() function. If the game is running at 60 frames per second, we can find the per-frame movement like so:\n120 pixels/second * 1/60 second/frame = 2 pixels/frame Tip Notice the units are consistent in all the calculations above. Always pay attention to the units in your calculations - it’ll save you from making mistakes.\nHere’s the necessary code:\nextends Node2D # Desired movement in pixels/frame var movement = Vector2(2, 0) func _process(delta): $Sprite.position += movement Run this code and you’ll see the sprite takes 5 seconds to cross the screen.\nMaybe. The trouble begins if there is something else occupying the computer’s time. This is called lag and can come from a variety of sources - the cause could be your code or even other applications running on your computer. If this happens, then the length of a frame might increase. As an extreme example, imagine that the frame rate is halved - each frame took 1/30 instead of 1/60 of a second. Moving at 2 px/frame, it’s now going to take twice as long for the sprite to reach the edge.\nEven small frame rate fluctuations will result in inconsistent movement speed. If this were a bullet or other fast-moving object, we wouldn’t want it slowing down like this. We need the movement to be frame rate independent.\nFixing the frame rate problem When using the _process() function, it automatically includes a parameter called delta that’s passed in from the engine (so does _physics_process(), which is used for physics-related code). This is a floating point value representing the length of time since the previous frame. Typically, this will be approximately 1/60 or 0.0167 seconds.\nWith this information, we can stop thinking about how much to move each frame, and only consider our desired speed in pixels/second (120 from the above calculation).\nMultiplying the engine’s delta value by this number will give us how many pixels to move each frame. The number will automatically adjust if the frame time fluctuates.\n# 60 frames/second 120 pixels/second * 1/60 second/frame = 2 pixels/frame # 30 frames/second 120 pixels/second * 1/30 second/frame = 4 pixels/frame Note that if the frame rate decreases by half (meaning the frame time doubles), then our per-frame movement must also double to keep the desired speed.\nLet’s change the code to use this calculation:\nextends Node2D # Desired movement in pixels/second. var movement = Vector2(120, 0) func _process(delta): $Sprite.position += movement * delta Now when running at 30 frames per second, the travel time is consistent:\nIf the frame rate gets very low, the movement is no longer smooth, but the time remains the same.\nUsing delta with motion equations What if your movement is more complex? The concept remains the same. Keep your units in seconds, not frames, and multiply by delta each frame.\nTip Working in pixels and seconds is much easier to conceptualize too, since it relates to how we measure these quantities in the real world. “Gravity is 100 pixels/second/second, so after the ball falls for 2 seconds, it’s traveling at 200 pixels/second.” If you’re working with frames, then you have to think about acceleration in units of pixels/frame/frame. Go ahead and try - it’s not very natural.\nFor example, if you are applying a gravity, that’s an acceleration - each frame it will increase the velocity by some amount. As in the above example, the velocity then changes the node’s position.\nTry adjusting delta and target_fps in the following code to see the effect:\nextends Node2D # Acceleration in pixels/sec/sec. var gravity = Vector2(0, 120) # Acceleration in pixels/frame/frame. var gravity_frame = Vector2(0, .033) # Velocity in pixels/sec or pixels/frame. var velocity = Vector2.ZERO var use_delta = false var target_fps = 60 func _ready(): Engine.target_fps = target_fps func _process(delta): if use_delta: velocity += gravity * delta $Sprite.position += velocity * delta else: velocity += gravity_frame $Sprite.position += velocity Note that we’re multiplying by our timestep each frame to update both velocity and position. Any quantity that is updated every frame should be multiplied by delta to ensure it changes independent or frame rate.\nUsing kinematic functions In the above examples, we’ve used a Sprite to keep things simple, updating the position every frame. If you’re using a kinematic body (in 2D or 3D), you’ll instead be using one of its movement methods. Specifically in the case of move_and_slide(), there tends to be some confusion, because it uses the velocity vector, not the position. This means you won’t multiply your velocity by delta to find distance - the function does that for you. But you will still need to apply it on any other calculations, such as the acceleration. For example:\n# Sprite movement code: velocity += gravity * delta position += velocity * delta # Kinematic body movement code: velocity += gravity * delta move_and_slide() If you don’t use delta when applying acceleration to your velocity, then your acceleration will be subject to fluctuations in frame rate. This can have a_much more subtle effect on movement - it will be inconsistent, but much more difficult to diagnose.\nTip When using move_and_slide() you still need to apply delta to any other quantities such as gravity, friction, etc.\nRelated Recipes ","description":"","tags":null,"title":"Understanding 'delta'","uri":"/godot_recipes/4.x/basics/understanding_delta/index.html"},{"content":" 3D Tips, tricks, and tutorials on the 3D side of game development.\nIn this section: Working with 3D Assets Basic FPS Character Camera Gimbal Interpolated Camera Shooting with Raycasts CharacterBody3D: Movement 3D Unit Healthbars Rolling Cube Arcade-style Spaceship Arcade-style Car Click to move Smooth rotation CharacterBody3D: Align with Surface ","description":"","tags":null,"title":"3D","uri":"/godot_recipes/4.x/3d/index.html"},{"content":"Problem You need a 2D character that has 8-directional movement, including animation.\nSolution For our example, we’ll use the Isometric Mini-Crusader, which contains 8-directional animations for idle, run, attack, and several other states.\nThe animations are organized in folders, with a separate image for each frame. We’ll use an AnimatedSprite2D and we’ll name each animation based on its direction. For example, idle0 pointing to the right and going clockwise to idle7.\nWhen our character moves, it will pick an animation based on the direction of movement:\nWe’ll use the mouse to move - the character will always face the mouse and run in that direction when we click the mouse button.\nTo choose which animation to play, we need to get the mouse direction and map it to this same range of 0-7. get_local_mouse_position() gives us the position of the mouse relative to the character. We can then use snappedf() to snap the angle of the mouse vector to the closest multiple of 45° (PI/4 radians) giving the following result:\nDivide each value by 45° (PI/4 radians), and we have:\nFinally, we need to map the resulting range to 0-7 using the wrapi() function, and we’ll have our correct values. Adding that value to the end of the animation name (“idle”, “run”, etc) gives us the correct animation:\nfunc _physics_process(delta): current_animation = \"idle\" var mouse = get_local_mouse_position() angle = snappedf(mouse.angle(), PI/4) / (PI/4) angle = wrapi(int(angle), 0, 8) if Input.is_action_pressed(\"left_mouse\") and mouse.length() \u003e 10: current_animation = \"run\" velocity = mouse.normalized() * speed move_and_slide() $AnimatedSprite2D.animation = current_animation + str(a) Testing the movement, we see this:\nKeyboard input If you’re using keyboard controls instead of mouse, you can get the angle of movement based on which keys are being held. The rest of the process works in the same way.\nfunc _process(delta): current_animation = \"idle\" var input_dir = Input.get_vector(\"left\", \"right\", \"up\", \"down\") if input_dir.length() != 0: angle = input_dir.angle() / (PI/4) angle = wrapi(int(a), 0, 8) current_animation = \"run\" velocity = input_dir * speed move_and_slide() $AnimatedSprite2D.play(current_animation + str(angle)) Download This Project Download the project code here: https://github.com/godotrecipes/8_direction_animation\n","description":"","tags":null,"title":"8-Directional Movement/Animation","uri":"/godot_recipes/4.x/2d/8_direction/index.html"},{"content":"Now that the player can move around the screen, our next step will be to implement shooting\nReusable objects The player will fire many “bullets” during the game, but all of them will be identical. A bullet needs to do the following:\nAppear just ahead of the player Travel forward until going off the screen Detect collisions with enemies Since all bullets will do these same things, we can save ourselves a great deal of work by designing one “prototype” bullet, and using that as the blueprint for creating as many duplicates as we need. Godot’s scene system is ideal for this.\nBullet scene Create a new scene by selecting Scene -\u003e New Scene in the menu, or by clicking the + in the tabs on the top of the viewport.\nJust like we did with the Player scene, we need to consider what nodes we’ll need to make the bullet work. We can again use an Area2D, since that will allow us to detect the bullet hitting things. This means we’ll need a collision shape, and a sprite to display the bullet image. Finally, we need a way to detect when the bullet goes offscreen so we can automatically remove it.\nHere’s the node setup:\nArea2D - name this Bullet Sprite2D CollisionShape2D VisibleOnScreenNotifier2D From the asset pack folder, drop the Player_charged_beam (16 x 16).png image on the Texture of the Sprite2D.\nAs with the ship image, there are multiple versions here, so set the *Hframes to 2 so we’ll only see one at a time.\nSet the shape of the CollisionShape2D just like you did earlier in the Player scene.\nBullet script Attach a script to the Bullet node and let’s start with the movement:\nextends Area2D @export var speed = -250 func start(pos): position = pos func _process(delta): position.y += speed * delta This should look fairly familiar, as it’s similar to the player script. We’re only changing the position.y since the bullet should travel straight up.\nNote the start() function we defined. That will let us set the bullet’s starting position, since the player will move around and spawn the bullets at different locations.\nConnecting signals Now select the Bullet node and then click the Node tab next to the Inspector.\nThis is a list of all the signals this node can emit. Signals are how Godot lets you know that something has happened. In this case, we can use the area_entered signal to tell us whenever this bullet touches another Area2D node.\nSelect the area_entered signal and click the Connect… button (you can also double-click the signal name). In the dialog that opens up, just click Connect - we don’t need to change anything there.\nYou’ll notice that you’re back in the script editor, looking at bullet.gd, and a new function as been added. It has a green “connected” icon next to its name to show that a signal is connected to it. This function will be called whenever the area touches something, so let’s add some code here:\nfunc _on_area_entered(area): if area.is_in_group(\"enemies\"): area.explode() queue_free() Here we’ll check if the bullet hit an enemy (more about that later), and if it did, we tell the enemy to explode and then delete the bullet.\nDo the same thing to connect the screen_exited signal of the VisibleOnScreenNotifier2D.\nfunc _on_visible_on_screen_notifier_2d_screen_exited(): queue_free() Next steps This completes the bullet scene, so now we can go back and add shooting to the player.\nPrev Next ","description":"","tags":null,"title":"Bullet Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_04/index.html"},{"content":"Problem You need a player-controlled 3D character body.\nSolution For this recipe, we’ll be using this adorable tank model:\nYou can grab this model on Itch.io: https://gtibo.itch.io/mini-tank or use any other model you’d like. We won’t be doing anything that’s tank-specific here.\nIn the case of this asset, the download includes an OBJ file, and we’ll find it more convenient if we import it as a scene:\nWe can add the model to the scene, but we’ll need a couple of additional nodes:\nFor the collision shape, we’re just going to use a BoxShape aligned and sized with the tank’s treads. CamPos is a Position3D we’ll use to place our following camera. It’s placed behind and above the tank, angled down.\nWe’ve also rotated the individual MeshInstance nodes 180 degrees around the Y axis. This is because they were modeled facing towards +Z, but -Z is the forward direction in Godot, and we don’t want our tank to look like it’s backwards.\nBefore we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:\nInput Action Key forward W back S right D left A Now let’s add a script, starting with the required variables:\nextends CharacterBody3D @export var speed = 4.0 @export var turn_speed = 0.8 speed is the tank’s movement speed (forward and back), while rot_speed defines how fast it can turn.\nTip Declaring properties with @export makes it easy to adjust them in the Inspector.\nUsing the move_and_slide() method makes our movement code quite simple:\nfunc _physics_process(delta): velocity.y -= gravity * delta get_input(delta) move_and_slide() With this code, we add the downward acceleration of gravity to the current velocity, get the user’s input (more about that below), and call move_and_slide().\nNext we need to define get_input(), where we’ll process and apply the input actions:\nfunc get_input(delta): var vy = velocity.y velocity = Vector3.ZERO var move = Input.get_axis(\"back\", \"forward\") var turn = Input.get_axis(\"right\", \"left\") velocity += -transform.basis.z * move * speed rotate_y(turn_speed * turn * delta) velocity.y = vy Let’s examine this more closely. Player input should affect horizontal movement: forward/back along the ground, and rotation around the tank’s center. Movement in the Y direction should only be affected by gravity, which means we don’t want to set it to 0 every frame. This is why we’re using the vy variable to temporarily hold that value while we assign a new velocity vector for the horizontal movement, then add it back in at the end.\nFor the forward and back movement, we’re using transform.basis.z so that we’ll move in our body’s local forward direction.\nHere’s the tank in action. We’ve made a test scene with a StaticBody3D plane for the ground and an Camera3D using the Interpolated Camera recipe.\nWrapping up This is the basis of movement for any kind of kinematic character. From here you can add jumping, shooting, AI behavior, etc. See the related recipes for examples that build on this recipe.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples\nRelated recipes Intro to 3D Input Actions ","description":"","tags":null,"title":"CharacterBody3D: Movement","uri":"/godot_recipes/4.x/3d/characterbody3d_examples/index.html"},{"content":"Problem You need a “homing missile” - a projectile that will seek a moving target.\nSolution For this example, we’ll use an Area2D node for the projectile. Areas are typically good choices for bullets because we need to detect when they contact something. If you also need a bullet that bounces/ricochets, one of the PhysicsBody type node might be a better choice.\nThe node setup and behavior of the missile is the same you would use for a “dumb” bullet. If you’re creating many bullet types, you can use inheritance to base all your projectiles on the same core setup.\nThe nodes we’ll use:\nArea2D: Missile Sprite2D CollisionShape2D Timer: Lifetime For the texture, you can use any image you like. Here’s an example one:\nSet up the nodes and configure the sprite’s texture and the collision shape. Make sure to rotate the Sprite2D node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.\nAdd a script and connect the Area2D’s body_entered signal and the Timer’s timeout signal.\nHere’s the starting script:\nextends Area2D export var speed = 350 var velocity = Vector2.ZERO var acceleration = Vector2.ZERO func start(_transform): global_transform = _transform velocity = transform.x * speed func _physics_process(delta): velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta func _on_Missile_body_entered(body): queue_free() func _on_Lifetime_timeout(): queue_free() This creates a “dumb” rocket that travels in a straight line when fired. To use this projectile, instance it and call its start() method with the desired Transform2D to set its position and direction.\nSee the related recipes section below for more information.\nTo change the behavior to seek a target, we’ll use the acceleration. However, we don’t want the missile to “turn on a dime”, so we’ll add a variable to control its “steering” force. This will give the missile a turning radius that can be adjusted for different behavior. We also need a target variable so that the missile knows what to chase. We’ll set that in start() as well:\nexport var steer_force = 50.0 var target = null func start(_transform, _target): target = _target ... To change the missile’s direction to move toward the target, it needs to accelerate in that direction (acceleration is change in velocity). The missile “wants” to move straight towards the target, but its current velocity is pointing in a different direction. Using a little vector math, we can find that difference:\nThe green arrow represents the needed change in velocity (i.e. acceleration). However, if we turn instantly, that will look unnatural, so the “steering” vector’s length needs to be limited. This is the purpose of the steer_force variable.\nThis is the function to calculate that acceleration. Note that if there’s no target, there will be no steering, so the missile remains traveling in a straight line.\nfunc seek(): var steer = Vector2.ZERO if target: var desired = (target.position - position).normalized() * speed steer = (desired - velocity).normalized() * steer_force return steer Finally, the resulting steer force must be applied in _physics_process():\nfunc _physics_process(delta): acceleration += seek() velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta Here’s an example of the results, with a little extra visual flair such as particle smoke and explosions:\nHere’s the full script, including the above effects. See related recipes for details.\nextends Area2D export var speed = 350 export var steer_force = 50.0 var velocity = Vector2.ZERO var acceleration = Vector2.ZERO var target = null func start(_transform, _target): global_transform = _transform rotation += rand_range(-0.09, 0.09) velocity = transform.x * speed target = _target func seek(): var steer = Vector2.ZERO if target: var desired = (target.position - position).normalized() * speed steer = (desired - velocity).normalized() * steer_force return steer func _physics_process(delta): acceleration += seek() velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta func _on_Missile_body_entered(body): explode() func _on_Lifetime_timeout(): explode() func explode(): $Particles2D.emitting = false set_physics_process(false) $AnimationPlayer.play(\"explode\") await $AnimationPlayer.animation_finished queue_free() Related recipes Spritesheet animation Top-down character Transforms ","description":"","tags":null,"title":"Homing missile","uri":"/godot_recipes/4.x/ai/homing_missile/index.html"},{"content":"Problem You want to pick up and move rigid bodies with the mouse.\nSolution Working with rigid bodies can be tricky. Godot’s physics engine controls their movements, and interfering with that can often lead to unexpected results. The key is to make use of the body’s mode property. This applies equally well in 2D or 3D.\nBody setup We’ll start with our rigid body object, adding a Sprite2D and CollisionShape2D. You can also add a PhysicsMaterial if you want to set Bounce and Friction properties.\nWe’re going to use the rigid body’s freeze property to remove it from the control of the physics engine while we’re dragging it. Since we still want it to be movable, we need to set the Freeze Mode to “Kinematic”, rather than the default value of “Static”.\nPlace the body in a group called “pickable”. We’ll use this to allow for multiple instances of the pickable object in the main scene. Attach a script to the body and connect the its _input_event signal.\nextends RigidBody2D signal clicked var held = false func _on_input_event(viewport, event, shape_idx): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: print(\"clicked\") clicked.emit(self) We’ll emit a signal when a mouse click is detected, including a reference to the body. Since there can be many bodies, we’ll let the main scene manage whether a body can be dragged or if there’s already one in the held state.\nIf the body is being dragged, we update its position to follow the mouse.\nfunc _physics_process(delta): if held: global_transform.origin = get_global_mouse_position() Finally, these are the two functions to call when the body is picked up and dropped. Changing the freeze to true removes the body from physics engine processing. Note that other objects can still collide with it. If you don’t want that, you can disable the collision_layer and/or collision_mask here as well. Just remember to re-enable them when dropping.\nfunc pickup(): if held: return freeze = true held = true func drop(impulse=Vector2.ZERO): if held: freeze = false apply_central_impulse(impulse) held = false In the drop function, after we change freeze back to `false, the body will return to the physics engine’s control. By passing in an optional impulse value, we can add the ability to “throw” the object on release.\nMain scene Create a main scene with some static body obstacles or a TileMap and instance a few copies of the pickable body.\nHere’s the script for the main scene. We start by connecting the clicked signal on any pickable bodies that are in the scene.\nextends Node2D var held_object = null func _ready(): for node in get_tree().get_nodes_in_group(\"pickable\"): node.clicked.connect(_on_pickable_clicked) Next, we have the function we connect the signal to. The connected function sets held_object so that we know something is currently being dragged, and calls the body’s pickup() method.\nfunc _on_pickable_clicked(object): if !held_object: object.pickup() held_object = object Lastly, when the mouse is released during dragging, we can perform the reverse actions.\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if held_object and !event.pressed: held_object.drop(Input.get_last_mouse_velocity()) held_object = null Note the use of get_last_mouse_velocity() to pass the impulse to the object - be careful with this! You may find yourself launching the rigid bodies at high speeds, especially if the bodies have low mass values. It’s probably a good idea to scale this to a reasonable value and clamp() it to some maximum. Experiment to find out what works for you.\nDownload This Project Download the project code here: https://github.com/godotrecipes/rigidbody_drag_drop\nRelated recipes ","description":"","tags":null,"title":"RigidBody2D: Drag and Drop","uri":"/godot_recipes/4.x/physics/rigidbody_drag_drop/index.html"},{"content":"Problem You need to save and load local data between game sessions.\nSolution Godot’s file I/O (input/output) system is based around the FileAccess object. You open a file by calling open().\nvar file = FileAccess.open(\"user://myfile.name\", File.READ) Warning User data should only be stored in the user:// path. While res:// can be used when running from the editor, when your project is exported, the res:// path becomes read-only.\nThe second argument after the file path is the “Mode Flag”, which can be one of the following:\nFileAccess.READ - Open for reading. FileAccess.WRITE - Open for writing. Creates the file if it doesn’t exist and truncates if it does. FileAccess.READ_WRITE - Open for reading and writing. Doesn’t truncate the file. FileAccess.WRITE_READ - Open for reading/writing. Creates the file if it doesn’t exist and truncates if it does. Storing data You can save data using its specific data type (store_float(), store_string(), etc.), or using the generic store_var(), which will use Godot’s built-in serialization to encode your data, including complex data like objects (more on this later).\nLet’s start with a small example: saving the player’s high score. We can write a function that we can call whenever the score needs to be saved:\nvar save_path = \"user://score.save\" func save_score(): var file = FileAccess.open(save_path, FileAccess.WRITE) file.store_var(highscore) We’re saving our score, but we need to be able to load it when the game starts:\nfunc load_score(): if FileAccess.file_exists(save_path): print(\"file found\") var file = FileAccess.open(save_path, FileAccess.READ) highscore = file.get_var() else: print(\"file not found\") highscore = 0 Don’t forget to check for the file’s existence before attempting to read from it - it may not be there! If that’s the case, you can use a default value.\nYou can store_var() and get_var() as many times as you need for any number of values.\nSaving Resources The above technique works great when all you need to save are a few values. For more complex situations, you can save your data in a Resource, just like Godot does. Godot saves all its data Resources as .tres files (Animations, TileSets, Shaders, etc.) and you can too!\nTo save and load Resources, use the ResourceSaver and ResourceLoader Godot classes.\nFor this example, let’s say you have all the data about your character’s stats stored in a Resource like this:\nextends Resource class_name PlayerData var level = 1 var experience = 100 var strength = 5 var intelligence = 3 var charisma = 2 You can then save and load like so:\nfunc load_character_data(): if ResourceLoader.exists(save_path): return load(save_path) return null func save_character_data(data): ResourceSaver.save(data, save_path) Resources can contain subresources, so you could have your player’s inventory Resource included as well, and so on.\nWhat about JSON? I see it very often (and some readers may be asking it already): “What if I want to use JSON to save my data?” This is my response:\nDon’t use JSON for your save files!\nWhile Godot has JSON support, saving game data is not what JSON is for. JSON is a data interchange format - its purpose is to allow systems using different data formats and/or languages to exchange data between each other.\nThis means JSON has limitations that are negatives for you when it comes to saving your game data. JSON doesn’t support many data types (no int vs. float, for example) so you have to do a lot of converting and validating to try and save/load your data. It’s cumbersome and time consuming.\nDon’t waste your time. Using Godot’s built-in serialization, you can store native Godot objects - Nodes, Resources, even Scenes - without any effort, which means less code and fewer errors.\nThere’s a reason that Godot itself doesn’t use JSON for saving scenes and resources.\nWrapping up This article just scratches the surface of what you can do with FileAccess. For the full list of available FileAccess methods, see the FileAccess documentation.\n","description":"","tags":null,"title":"Saving/loading data","uri":"/godot_recipes/4.x/basics/file_io/index.html"},{"content":"Problem Many 2D games use a “3/4 view” perspective, giving the impression that the camera is looking at the world at an angle. To make this work, objects that are “farther” away need to be rendered behind “nearer” objects. In practice, that means we want to “y-sort” - making the drawing order tied to the object’s y coordinate. The higher on the screen, the farther away and therefore lower the render order.\nHere’s an example of the problem:\nThese objects are being drawn in the default render order: tree order. They are arranged like this in the scene tree:\nSolution Godot has a built-in option to change the render order: on any CanvasItem node (Node2D or Control), we can enable the Y Sort Enabled property. When this is enabled, all child nodes are then y-sorted.\nIn the above example, we can enable the property on the TileMap node. However, there’s still a problem:\nThe draw order is based on each object’s y coordinate. By default, that is the object’s center:\nSince we want to give the impression that the objects are on the “ground”, we can solve this by offsetting each object’s sprite so that the object’s position is aligned with the bottom of the sprite:\nNow things look a lot better:\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/using_ysort\n","description":"","tags":null,"title":"Using Y-Sort","uri":"/godot_recipes/4.x/2d/using_ysort/index.html"},{"content":"Problem You want a floating “healthbar” for your 3D game objects (mobs, characters, etc.).\nSolution For this solution, we’re going to re-use a 2D healthbar based on a TextureProgressBar node. It’s already set up with textures and code for updating the value and color. If you already have something similar, feel free to use it here. In the example, we’ll name this scene “Healthbar2D”.\nIf you need some assets, here are the three images used in the bar:\nNote Re-using existing objects can save you a lot of time. Don’t re-invent the wheel everytime you need a healthbar, camera, or other common object.\nProject setup For our example “mob”, we’ll start with a CharacterBody3D node. It’s programmed to spawn and travel in a straight line. It also has the following code to handle damage:\nfunc _on_input_event(_camera, event, _position, _normal, _shape_idx): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: health -= 1 if health \u003c= 0: queue_free() Clicking on a unit deals one damage. Do ten damage, and the unit is destroyed. Now we need a visual representation of that using our 2D bar.\n2D in 3D We can display a 2D image in 3D using a Sprite3D. Add one to a new scene and name it “Healthbar3D”. First, we’ll get it configured and sized, so set the Texture property to the green bar image.\nThe Sprite3D acts like any other 3D object - as we pan the camera around, our perspective on it changes. However, we want the healthbar to always “face” toward the camera so that we can see it.\nIn the Inspector, under Flags, set Billboard to “Enabled”.\nNow try moving the camera to confirm that the texture is always facing you.\nAdd an instance of this scene to the Mob scene and position the bar above the mob’s body.\nViewport texture We don’t want the Sprite3D to show a static texture - we want it to display the 2D TextureProgressBar. We can do that using a SubViewport node, which can export a texture.\nAdd a SubViewport as a child of the Sprite3D. In the Inspector set Transparent BG to On.\nWe also need to set the size of the viewport to match the size of the healthbar texture, which is (200, 26).\nInstance the HealthBar2D as a child of the Viewport. Your scene should look like this:\nIf the SubViewport were not a child of the Sprite3D, we could set it as the sprite’s texture directly in the Inspector. Since it’s a child, it won’t be ready at the right time, so we’ll need to set it in a script attached to the Sprite3D:\nextends Sprite3D func _ready(): texture = $SubViewport.get_texture() Connecting it all together In the mob’s _on_input_event() method, add the following after reducing the health:\n$HealthBar3D.update(health, max_health) Add the following to HealthBar3D.gd:\nfunc update_health(_value, _max_value): $SubViewport/HealthBar2D.update_health(_value, _max_value) This calls the update method that already exists on the 2D bar, setting the progress bar’s value and selecting the bar color:\nfunc update_health(_value, _max_value): value = _value if value \u003c _max_value: show() texture_progress = bar_green if value \u003c 0.75 * _max_value: texture_progress = bar_yellow if value \u003c 0.45 * _max_value: texture_progress = bar_red Click on the mobs to see the health bars change.\nWrapping up You can use this technique to display any other Node2D or Control nodes, such as Label, VideoStreamPlayer, etc. You can even use the SubViewport to “project” an entire 2D game in 3D space.\nDownload This Project Download the project code here: https://github.com/godotrecipes/3d_object_healthbars\n","description":"","tags":null,"title":"3D Unit Healthbars","uri":"/godot_recipes/4.x/3d/healthbars/index.html"},{"content":" Animation Using Godot’s animation system.\nIn this section: Spritesheet animation Using the AnimationTree StateMachine ","description":"","tags":null,"title":"Animation","uri":"/godot_recipes/4.x/animation/index.html"},{"content":"Problem You’ve got a rigged, animated 3D character (either made by you or downloaded from a third party) and you want to set up its animations in Godot.\nSolution In this recipe, we’ll assume you’ve already imported your character model and animations. If you haven’t yet, see Importing Assets for details. As a reminder, we’re using the art packs linked in the section description.\nPrepping the character We’ve chosen CharacterBody3D for our character, so your scene should look like this (I’ve collapsed the Rig node since the mesh list is so long):\nThe first thing you probably noticed is that the character’s hands are full! The artist has helpfully provided all the weapons \u0026 shields attached and oriented at the correct points. You can go down the list and hide the ones you don’t want to see.\nAbout the AnimationTree With all of the animations we have available, it’s going to quickly get very complicated to handle all of them in code. Think about how many if statement’s we’d need to decide which animation to play at which time, depending on what the player is doing. While this is not bad if you only have a few animations, it quickly gets out of hand and becomes impractical.\nAlso, consider when the character is standing still: it should be playing the “Idle” animation. When the player presses “forward”, the character should move and switch to playing the “Walking” animation. This sudden transition is going to look jarring, so we’d prefer if the two animations can be “blended” into a smoother transition.\nThe solution to these complex animation issues is to use the AnimationTree node. This node is designed to control an AnimationPlayer and has functionality to control how animations transition and blend together.\nAdd an AnimationTree to the scene. In the Inspector, set Tree Root to a new AnimationNodeStateMachine, in Anim Player select the character’s AnimationPlayer node, and check the box next to Active.\nNote You may notice that when the AnimationTree is active, you can’t choose animations in the AnimationPlayer. If you need to make any changes or test the animations, uncheck the tree’s Active property while doing so.\nThe Idle/Walk/Run Cycle There are a lot of animations provided with these models. For this example, we’re going to focus on the idle-walk-run cycle, jumping, and attacking. If you want to include other animations, they’ll be handled in a similar way.\nIn the AnimationPlayer, find the “Idle”, “Running_A”, “Walking_Backwards”, and “Running_Strafe_Left”/“Running_Strafe_Right” animations. Make sure they’re all set to loop - you can test them by pressing the “Play” button: (▶). If any of them are not, reimport the character after setting them (see Importing Assets).\nSelect the AnimationTree node and you’ll see the panel open at the bottom of the window:\nAs an example, right-click in the empty space and choose Add Animation → Idle, then add the “1H_Melee_Attack_Chop” animation as well.\nSelect the Connect Nodes button and draw a connection from Start to Idle. You should immediately see the “Idle” animation playing.\nNow, we want to be able to transition from idle to attack and then back to idle when the attack animation finishes. Draw two more connection arrows to and from the attack. It won’t quite work, however, you’ll just be rapidly flickering between the two animations, because both are set to immediately transition.\nTo change the transition conditions, change to Select mode using the icon and then click on one of the connections. In the Inspector, you’ll see the connection properties. For the connection from idle to attack, we want Advance/Mode to be “Enabled” (not “Auto”). This means it happens only when told to. Notice that the icon on the connection line changes color.\nFor the connection from attack to idle, set Switch Mode to “At End” and Advance Mode to “Auto”.\nNow, when you press the ▶ button on the attack node, it will play and then transition back to idle as soon as it completes.\nThis gives you an idea how to set up different animations and transition between them. However, we want to do a little more here, so delete the two animations using the trash can icon, and let’s set up a blendspace.\nBlendspaces Right-click in the empty space to create a new BlendSpace2D. Click on its name to rename it to IWR (for idle-walk-run). Add a transition from Start so that the blendspace will start playing automatically.\nClick the pencil icon to edit the blend space.\nThis 2D space represents the character’s horizontal movement vector. When standing still that’s (0, 0), so click the Create Points button and click in the center of the grid to Add Animation → Idle.\nAt the center-top, add the “Running_A” animation, and center-bottom, “Walking_Backwards”. At the two horizontal ends, add the strafe animations.\nNow click the crosshair button to set the blend position and click to drag it around the grid. You should see the animations transition smoothly between the extremes.\nWhen you’re done experimenting with the blendspace, click “Root” in the Path at the top of the panel to return to the root of the tree.\nSetting up the state machine The IWR looping animations can be thought of as the “heart” of the animation tree. The character will spend most of its time playing these animations. Any other animations will branch off from it (like we did earlier with the attack).\nIn the image below, I’ve done that with several other animations. Note the transition properties are set as we did in the example above.\nYou can also click to change the names the animations, as some of them are quite long.\nThe one animation that’s different is jumping. The jump animation is split into three parts: “start\"and “land”, which are played when the character starts jumping, and when the jump ends. The “idle” portion of the jump is a looping animation that plays as long as the character is in the air - if they fall a long way, for example.\nAdd the three jumping animations and link them like this:\nWe need to be able to go straight from IWR to Jump_Idle in the event of falling off a ledge, but if pressing “jump”, we’ll go through Jump_Start first.\nIn addition, we’ve left the transition from IWR to Jump_Start as “Auto”. Instead of changing it to “Enabled”, we’ve added a Condition of jumping to the transition:\nSimilarly, the transition between Jump_Idle and Jump_Land has a condition of grounded.\nWe’ll be able to set these conditions in code to trigger the transition.\nFinally, if you’re looking closely, you may notice that the transition from Jump_Land to IWR does not look smooth, because the last frame and first frame of the two animations don’t quite match up. We can solve this by selecting the transition between them and setting a small Xfade Time of 0.1, which will smooth it out nicely.\nWrapping up We’ve now set up our 3D character’s animations and they’re ready to use. By setting up the AnimationTree, it will now be much easier to select and transition between animations in the character’s movement code.\nSee the section description for more examples of working in 3D and for example Godot projects you can download.\nCompanion Video https://youtu.be/YrNQCB34PAc\n","description":"","tags":null,"title":"Character Animation","uri":"/godot_recipes/4.x/3d/assets/character_animation/index.html"},{"content":"Problem You want your character body to interact with rigid bodies.\nSolution Note This recipe applies equally well in both 2D and 3D nodes.\nBy default, a CharacterBody2D moved with move_and_slide() or move_and_collide() will not push any RigidBody2D it collides with. The rigid body doesn’t react at all, and behaves just like a StaticBody2D.\nIn some cases, this might be all you need. However, if you want to be able to push the bodies, you’ll need to make some changes.\nFor this example, we’ll use the 2D character described in the Platform character recipe. This example uses the most common movement method for character bodies: move_and_slide(). If you’re using move_and_collide(), you’ll need to adjust the examples below accordingly.\nYou have two options when deciding how to interact with rigid bodies:\nYou can just push them, ignoring physics. If you’re familiar with Godot 3.x, this is equivalent to the “infinite inertia” option. You can give them a push based on the character’s imagined “mass” and velocity. This will give you a “realistic” result - pushing heavy bodies a little, and lighter bodies a lot. We’ll try out both options below.\nInfinite Inertia This option has its pros and cons. The biggest pro is, you don’t need any extra code. You just need to correctly set the collision layers/masks of the objects. For this example, we’ve defined three physics layers:\nFor the rigid body, we’ve placed it on the “items” layer (layer 3), and left the mask at the default (masking all layers):\nThen, we’ve placed the player on the “player” layer (layer 2), and configured the mask to ignore the “items”:\nRunning the game, we now see we can push the boxes around. Note that the mass of the box doesn’t matter - they’ll all be pushed the same.\nHere, you can also see the downside of this option. Because the physics of the boxes is being ignored, they can clip through walls and you can’t jump on top of them.\nFor some games, this will be fine. If you want to prevent the clipping, you’ll need to go with option 2.\nApplying impulses To give the colliding body a “push” we’ll need to apply an impulse. An impulse is an instantaneous “kick” - think of a bat hitting a ball. This is as opposed to a force, which is a continuous “push” on an object.\n# This represents the player's inertia. var push_force = 80.0 func _physics_process(delta): # after calling move_and_slide() for i in get_slide_collision_count(): var c = get_slide_collision(i) if c.get_collider() is RigidBody2D: c.get_collider().apply_central_impulse(-c.get_normal() * push_force) The collision normal points out of the rigid body, so we reverse it to point away from the character and apply the push_force factor. Now pushing works again, but it won’t force the rigid bodies through walls:\nYou’ll need to adjust the push_force in relation to the mass of your rigid bodies. Too high a force will still cause clipping, while too low will prevent pushing at all.\nExperiment to find the settings that work for your particular game.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/character_vs_rigid\nRelated recipes Platform character Watch Video ","description":"","tags":null,"title":"Character to Rigid Body Interaction","uri":"/godot_recipes/4.x/physics/character_vs_rigid/index.html"},{"content":"Problem Your platformer jumping feels “off”. Players don’t have good control and sometimes they “miss” jumping off the edge of platforms.\nSolution The answer to this problem is to use a technique called “coyote time”. This gives the player a greater feeling of control and a little “wiggle room” around the process of jumping from the edges of platforms.\n“Coyote time” works like this:\nIf the player walks off the edge of a platform, for a few frames afterward, we still allow them to jump as if they were still on the ground.\nOrigins The name “coyote time” comes from the famous cartoon coyote, who wouldn’t fall until he looked down:\nWe’re going to add this to an already existing platform character. See the Platform character recipe for how to set one up.\nTo handle the timing, we’ll add a Timer node called CoyoteTimer and set it to One Shot.\nThere are a few new variables we’ll need to keep track of coyote time:\nvar coyote_frames = 6 # How many in-air frames to allow jumping var coyote = false # Track whether we're in coyote time or not var last_floor = false # Last frame's on-floor state Since we’re using frames to set the duration, we can translate that to time when setting the Timer’s length in _ready():\n$CoyoteTimer.wait_time = coyote_frames / 60.0 Each frame we’ll store the current value of is_on_floor() to be used in the following frame, so put this in _physics_process() after the move_and_slide():\nlast_floor = is_on_floor() When we detect the jump input, we need to check if the character is on the floor or in coyote time:\nif Input.is_action_just_pressed(\"jump\") and (is_on_floor() or coyote): velocity.y = jump_speed jumping = true Coyote time begins if the player walks off the edge of a platform. That means that they are no longer on the floor, but were on the floor in the previous frame. We can check that like this, and start the timer if we did just transition from on- to off-floor:\nif !is_on_floor() and last_floor and !jumping: coyote = true $CoyoteTimer.start() The CoyoteTimer tells us when the coyote state ends:\nfunc _on_coyote_timer_timeout(): coyote = false Implementing in 3D You can apply the same process to 3d characters.\nDownload This Project The character in the Moving Platforms project has coyote time implemented.\nDownload the project code here: https://github.com/godotrecipes/2d_moving_platforms\nRelated recipes Platform character ","description":"","tags":null,"title":"Coyote Time","uri":"/godot_recipes/4.x/2d/coyote_time/index.html"},{"content":"Problem You need to display a heart container bar (or other icon-based bar).\nSolution A common way of displaying the player’s health is via a series of icons (typically hearts) that disappear as the player takes damage.\nIn this recipe, we’re going to explore three ways of displaying this information, which I’m labeling “simple”, “empty”, and “partial”:\nThis image shows what the bar displays when the player has 3 health.\nsimple: Only the hearts are displayed. empty: Empty heart containers are displayed. partial: The player can have partially filled containers. Setting up the bar The heart images I’m using are 53x45. You can get them here:\nKenney.nl: Platformer Art Deluxe\nIdeally, your heart bar will be easy to drop into your overall HUD/UI. It therefore makes sense to make it a separate scene. We’ll start with an HBoxContainer which will keep things aligned. Set the Theme Overrides/Constants/Separation to 5.\nAdd a TextureRect child. Drag your heart texture into the Texture property and set the Stretch Mode to “Keep”. Name the node “1” and then press “Ctrl-D” to duplicate the node for as many hearts as you need (5 in this example). Your node setup should look like this:\nAdding a script The script below will cover all three bar configurations for flexibility. You’ll probably only need one in your game, so you can remove the code relating to the other modes.\nTo begin, we’re going to load the textures we need and define our three bar modes:\nextends HBoxContainer enum modes {SIMPLE, EMPTY, PARTIAL} var heart_full = preload(\"res://assets/hud_heartFull.png\") var heart_empty = preload(\"res://assets/hud_heartEmpty.png\") var heart_half = preload(\"res://assets/hud_heartHalf.png\") @export var mode : modes func update_health(value): match mode: MODES.simple: update_simple(value) MODES.empty: update_empty(value) MODES.partial: update_partial(value) Calling update_health() on the bar will cause it to display the passed value, based on the selected mode.\nNote We’re not going to do any bounds checking on the value input. There are many ways you may have health implemented in your game, and so that’s left to you.\nFirst, the update_simple() method. Here, we loop through the heart containers and set the visibility of each TextureRect:\nfunc update_simple(value): for i in get_child_count(): get_child(i).visible = value \u003e i update_empty() is very similar, except instead of hiding the icon, we change its texture to the empty container:\nfunc update_empty(value): for i in get_child_count(): if value \u003e i: get_child(i).texture = heart_full else: get_child(i).texture = heart_empty Finally, for the partially filled containers, we have a third texture and twice the number of possible values:\nfunc update_partial(value): for i in get_child_count(): if value \u003e i * 2 + 1: get_child(i).texture = heart_full elif value \u003e i * 2: get_child(i).texture = heart_half else: get_child(i).texture = heart_empty Here’s an example using each of the bar modes:\nWrapping up Use this heart bar setup as a basis for your own HUD. This technique can be expanded to support a wide variety of information displays.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/heart_bars\n","description":"","tags":null,"title":"Heart Containers: 3 Ways","uri":"/godot_recipes/4.x/ui/heart_containers_3/index.html"},{"content":" Input Handling input - from keyboard and mouse to game controllers and touchscreens.\nIn this section: Input Actions Mouse Input Adding Input Actions in code Capturing the Mouse Mouse: Drag-select multiple units ","description":"","tags":null,"title":"Input","uri":"/godot_recipes/4.x/input/index.html"},{"content":" Intro to 3D A gentle introduction to the 3D side of Godot development.\nIn this section: The 3D Editor Importing 3D Objects Creating a 3D Character ","description":"","tags":null,"title":"Intro to 3D","uri":"/godot_recipes/4.x/g101/3d/index.html"},{"content":"This is an evolving list of the main changes and “gotchas” to look out for if you’re transitioning to 4.0.\nNew Names One of the biggest changes in Godot 4 is a whole bunch of renaming - of nodes, functions, and property names. Most of it is done to make things consistent or clear. Here are a few of the biggest ones to watch out for:\n2D/3D nodes - In Godot 3.x, 2D nodes had the “2D” suffix, but 3D nodes had none. This has been made consistent - they all now have “2D” or “3D” suffixes. For example: RigidBody2D vs. RigidBody3D.\nAlso in the category of 3D, the Spatial node is renamed to Node3D to match.\nOne of the most popular nodes, KinematicBody, has been renamed to CharacterBody2D/CharacterBody3D. See below for further changes with this node’s API.\nPackedScene’s instance() function has been renamed to instantiate().\nThe position and global_position properties replace translation and global_translation in 3D, making them consistent with 2D.\nSignals and Callables Working with signals is much more streamlined in 4.0. Signal is a native type now, so you’ll be using fewer strings, meaning you get autocomplete and error checking. This applies to functions as well, which can now be directly referenced rather than using strings.\nHere’s an example of defining, connecting, and emitting a signal.\nextends Node signal my_signal func _ready(): my_signal.connect(signal_handler) func _input(event): if event.is_action_pressed(\"ui_select\"): my_signal.emit() func signal_handler(): print(\"signal received\") Tweens If you started using SceneTreeTween in Godot 3.5, then you’ll be familiar with Godot 4.0’s Tween usage.\nTween is no longer a node. Instead, you create one-off tween animation objects whenever you need them. Once you get used to it, it’s a lot more powerful and easier to use than the old method.\nAnimatedSprite[2D|3D] The biggest change that catches people who are familiar with the 3.x version of this node is that the playing property is gone. It’s now much more consistent with AnimationPlayer’s usage - to automatically play an animation, you can toggle autoplay in the SpriteFrames panel. In code, use play() and stop() to control playback.\nCharacterBody[2D|3D] The biggest change in this node is in using move_and_slide(). It no longer takes any parameters - they are all now built-in properties. This includes a native velocity property, so you no longer need to declare your own.\nFor detailed examples of using these nodes, see Platform Character and/or Basic FPS Character.\nTileMap The TileMap node is completely overhauled for 4.0. Just about everything, from how you create TileSets to how you draw and interact with tiles is 100% new.\nOur “Using TileMaps” guide is coming soon.\nRNG There are a few changes to GDScript’s built-in random number generator functions:\nYou no longer need to call randomize() - this is automatic. If you do want repeatable “randomness”, use seed() to set it to a preselected value.\nrand_range() is now replaced with either randf_range() (for floats) or randi_range() (for ints).\nRaycasting When casting rays in code, there’s a new API. PhysicsDirectSpaceState[2D|3D].intersect_ray() now takes a special object as a parameter. This object specifies the ray properties. For example, to cast a ray in 3D:\nvar space = get_world_3d().direct_space_state var ray = PhysicsRayQueryParameters3D.create(position, destination) var collision = space.intersect_ray(ray) if collision: print(\"ray collided\") ","description":"","tags":null,"title":"Migrating from 3.x","uri":"/godot_recipes/4.x/basics/migrating/index.html"},{"content":"Problem You need moving platforms in your 2D platformer.\nSolution There are several ways to approach this problem. In this recipe, we’ll use AnimatableBody2Ds for our platform and move it with a Tween. This allows for a variety of movement styles while minimizing the amount of code we need to write.\nInfo You can also implement this moving platform technique using an AnimationPlayer rather than a tween. Much of the setup will be the same, but rather than tween code, you’ll animate the body’s position property.\nSetting up We’ll start with a basic platformer setup using the Platform character recipe. The basic movement from that recipe will work fine with the platforms. If you’ve modified it or used your own, everything should still work the same.\nCreating the platform The platform scene contains the following nodes:\nNode2D (“MovingPlatform”): The Node2D parent is there to act as the “anchor” or start point for the platform. We’ll animate the platform’s position relative to this parent node. AnimatableBody2D: This represents the platform itself. This is the node that will move. Sprite2D: You can use a sprite sheet here, individual images, or even a TileMap. CollisionShape2D: Don’t make the hitbox too big, or the player will appear to be “hovering” off the edge of the platform. Set up the Sprite2D’s Texture and the collision shape appropriately. In the AnimatableBody2D, set the Sync to Physics property “On”. Since we’re moving the body in code, this ensures that it’s moved during the physics step, keeping it in sync with the player and other physics bodies.\nNow add a script to the root Node2D:\nextends Node2D @export var offset = Vector2(0, -320) @export var duration = 5.0 func _ready(): start_tween() func start_tween(): var tween = get_tree().create_tween().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS) tween.set_loops().set_parallel(false) tween.tween_property($AnimatableBody2d, \"position\", offset, duration / 2) tween.tween_property($AnimatableBody2d, \"position\", Vector2.ZERO, duration / 2) We’ve used a few of Tween’s options here to make everything work smoothly:\nset_process_mode(): ensures that all movement takes place during the physics processing step. set_loops(): this makes the tween repeat. set_parallel(false): by default, all tween_property() changes would happen at that same time. This makes the two happen one after another: moving to one end of the offset, then back to the start. Using the two exported properties, you can adjust the platform’s movement. Set the offset to determine where the tween moves relative to its starting point, and the duration to determine how long it takes to complete the cycle.\nAdd some platforms in your level/world and try them out:\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_moving_platforms\nRelated recipes Platform character ","description":"","tags":null,"title":"Moving Platforms","uri":"/godot_recipes/4.x/2d/moving_platforms/index.html"},{"content":"Problem You have a grid-based environment and you’d like to set up pathfinding to allow navigation.\nSolution Godot provides a number of methods for pathfinding. For this recipe, we’ll consider the A* algorithm.\nAbout A* A* is a widely-used algorithm for finding the shortest path between two points. It can be used in any graph-based data structure, not just a grid.\nAStarGrid2D is a specialized version of Godot’s more generic AStar2D class. Because it’s specialized for using with a grid, it’s quicker and easier to set up because you don’t have to manually add all the individual grid cells and their connections.\nSetting up the Grid The most important configuration decision is the size of the cells and the size of the grid itself. We’ll use (64, 64) for this example, and we’ll use the window size to determine how many cells fit on the screen, but everything will work the same regardless of cell size.\nAdd this code to a Node2D.\nextends Node2D @export var cell_size = Vector2i(64, 64) var astar_grid = AStarGrid2D.new() var grid_size func _ready(): initialize_grid() func initialize_grid(): grid_size = Vector2i(get_viewport_rect().size) / cell_size astar_grid.size = grid_size astar_grid.cell_size = cell_size astar_grid.offset = cell_size / 2 astar_grid.update() In this code, we divide the size of the screen by the cell_size to calculate how big the whole grid will be. This lets us set the size property of the AStarGrid2D.\nThe offset property will come into play when we ask for a path between two points. Using cell_size / 2 means the path will be calculated from the center of each cell rather than the corners.\nFinally, we need to call update() after setting or changing any of the AStarGrid2D’s properties.\nDrawing the Grid For the purposes of this demo, we’ll draw the grid on the screen in code. In a game application, you’ll probably have a TileMap or some other visual representation of your world.\nHere’s some code to draw the grid:\nfunc _draw(): draw_grid() func draw_grid(): for x in grid_size.x + 1: draw_line(Vector2(x * cell_size.x, 0), Vector2(x * cell_size.x, grid_size.y * cell_size.y), Color.DARK_GRAY, 2.0) for y in grid_size.y + 1: draw_line(Vector2(0, y * cell_size.y), Vector2(grid_size.x * cell_size.x, y * cell_size.y), Color.DARK_GRAY, 2.0) This gives us a nice visual of the grid:\nDrawing the Path In order to find a path, we need a start and end point. Add these variables at the top of the script:\nvar start = Vector2i.ZERO var end = Vector2i(5, 5) And a couple of lines in _draw() to show them:\ndraw_rect(Rect2(start * cell_size, cell_size), Color.GREEN_YELLOW) draw_rect(Rect2(end * cell_size, cell_size), Color.ORANGE_RED) We can find the path between the two points using the get_point_path() method, but we also need to visualize it. We can use a Line2D, so add one to the scene.\nHere’s how we can get the path, and add the resulting points to the Line2D:\nfunc update_path(): $Line2D.points = PackedVector2Array(astar_grid.get_point_path(start, end)) Here’s the result:\nNote that we have a diagonal line between the two points. This is because, by default, the path will use diagonals. This can be modified by changing the diagonal_mode:\nDIAGONAL_MODE_ALWAYS - The default value, uses diagonals. DIAGONAL_MODE_NEVER - All movement is orthogonal. DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE - This allows diagonals, but prevents the path going “between” diagonally placed obstacles. DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES - This allows diagonals only in “open” areas, not near obstacles. Modifying this property can give you very different results, so make sure to experiment based on your setup. Let’s add this in the initialize_grid() function:\nastar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER Now we only have orthogonal moves:\nAdding Obstacles We can also add obstacles to the grid. By marking a cell as “solid”, the path will not include that cell. A cell can be toggled solid/not solid by using the set_point_solid() function.\nLet’s add some code to draw our walls (when they exist), by finding any solid cells and coloring them in:\nfunc fill_walls(): for x in grid_size.x: for y in grid_size.y: if astar_grid.is_point_solid(Vector2i(x, y)): draw_rect(Rect2(x * cell_size.x, y * cell_size.y, cell_size.x, cell_size.y), Color.DARK_GRAY) Call this function in _draw().\nThen, we can use the mouse to click on cells and toggle their state:\nfunc _input(event): if event is InputEventMouseButton: # Add/remove wall if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: var pos = Vector2i(event.position) / cell_size if astar_grid.is_in_boundsv(pos): astar_grid.set_point_solid(pos, not astar_grid.is_point_solid(pos)) update_path() queue_redraw() Note that we’re checking is_in_boundsv() first - this will prevent errors from being thrown if we click outside the grid boundaries.\nNow we can see the effect of obstacles on the path:\nChoosing a Heuristic A big factor that affects the resulting path is what heuristic you choose to use. The term “heuristic” refers to a “best guess”, and in the context of pathfinding just means: what direction should we try first when moving toward the goal?\nFor example, the Euclidean distance uses the Pythagorean theorem to estimate the path to try:\nWhile Manhattan distance only considers distance in N/S or E/W directions:\nAnd the Octile heuristic results in a path like this:\nYou can choose the heuristic using this property:\nastar_grid.default_estimate_heuristic = AStarGrid2D.HEURISTIC_OCTILE Which of these works best (results in the most pleasing paths) depends on the nature of your environment. Is it mostly wide-open spaces with few obstacles scattered around? Or is it a maze of twisty passages? Make sure to experiment with your specific project.\nDownload the example project below to experiment with this setup yourself. In addition to placing walls, you can use the right/middle mouse buttons to move the end/start locations.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/grid_pathfinding\n","description":"","tags":null,"title":"Pathfinding on a 2D Grid","uri":"/godot_recipes/4.x/2d/grid_pathfinding/index.html"},{"content":"The Bullet scene provides us with a reusable object we can instantiate whenever the player shoots.\nAdding to the player Let’s head back to the Player script and add a few new variables:\n@export var cooldown = 0.25 @export var bullet_scene : PackedScene var can_shoot = true The two @export variables let you configure them in the Inspector so that you can adjust the cooldown time. Set the bullet_scene by clicking the property and choosing the bullet.tscn file.\ncan_shoot is what programmers call a flag - a Boolean variable that controls a certain condition. In this case it determines whether the player is allowed to shoot or not. During the cooldown period, this variable will be false.\nNext, we’ll add a start() function similar to the one we made for the Bullet. This will let us set initial values for the player, as well as resetting them when the game restarts.\nfunc _ready(): start() func start(): position = Vector2(screensize.x / 2, screensize.y - 64) $GunCooldown.wait_time = cooldown This places the player at the bottom center of the screen - a good place to start. It also ensures that the cooldown timer has the correct wait time.\nThe shoot() function will be called whenever we press the “shoot” input.\nfunc shoot(): if not can_shoot: return can_shoot = false $GunCooldown.start() var b = bullet_scene.instantiate() get_tree().root.add_child(b) b.start(position + Vector2(0, -8)) The first thing this function does is check if the player is allowed to shoot. If it isn’t, return will end the function immediately.\nIf the player is allowed to shoot, then we set the flag to false, and start the cooldown timer. Then we create a new bullet and add it to the game, calling its start() function to make sure it’s placed in the correct position (just above the player’s ship).\nWe can call this function when the player is pressing the key. Add this to the end of the _process() function, after the position.clamp() line:\nif Input.is_action_pressed(\"shoot\"): shoot() We’ll also need to connect the timeout signal of GunCooldown.\nfunc _on_gun_cooldown_timeout(): can_shoot = true When the cooldown ends, we can allow shooting again.\nGo ahead and run the scene and try pressing the shoot action.\nAdding instances to the tree Notice that we’ve added the new bullets as children of the SceneTree root (get_tree().root), and not to the player ship. This is important because if we made the bullets children of the ship, then they would be “attached” to it when it moves.\nNext steps Shooting’s no fun without something to shoot at. We’ll start making the enemies soon, but first we need a scene where we can bring the player, enemies, and other game objects together.\nPrev Next ","description":"","tags":null,"title":"Shooting","uri":"/godot_recipes/4.x/games/first_2d/first_2d_05/index.html"},{"content":" UI Building user interfaces.\nIn this section: Heart Containers: 3 Ways Level Select Menu Minimap/radar ","description":"","tags":null,"title":"UI","uri":"/godot_recipes/4.x/ui/index.html"},{"content":"Problem A common situation: you have a large number of animations, and it’s becoming difficult to manage transitions between them. Your code has become full of if statements, and every time you change something, it all breaks.\nSolution Use an AnimationTree to create an animation state machine. This will allow us to organize our animations and most importantly, control the transitions between them.\nGetting started For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art at https://elthen.itch.io/.\nWe’ll also assume you’ve already set up the character’s animations using AnimationPlayer. Using the above spritesheet, we have the following animations: “idle”, “run”, “attack1”, “attack2”, “hurt”, and “die”.\nAnimationTree Add an AnimationTree node to the scene. In its Tree Root property, choose “New AnimationNodeStateMachine”.\nAn AnimationTree is a node that controls animations created in AnimationPlayer. To let it access the existing animations, click “Assign” in the Anim Player property and select your animation node.\nNow we can begin to set up our state machine in the AnimationTree panel:\nNote the warning. Set the Active property to “On” in the Inspector.\nRight-click and choose “Add Animation”. Choose “idle”, and you’ll see a small box representing that animation. Press its “Play” button and you should see the animation play. Do the same to add boxes for the other animations.\nNow we can add connections. Click the “Connect nodes” button and drag between nodes to connect them. As an example, let’s use the two attack animations:\nWhen you select an animation, the tree will follow the connected path from the current node to the destination. However, in the configuration above, if you play “attack2” you won’t see “attack1” along the way. That’s because the default “switch mode” for a connection is “Immediate”. Click the “Move/select” button and then click on the connection between “attack1” and “attack2”. In the Inspector, change Switch Mode to “At End”. Do the same with “attack2” to “idle”. The connection icon changes from to .\nNow, with “idle” playing, if you click “attack2”, you’ll see the two attacks play in sequence.\nBut now the animation stops on “attack2”. On its connection, set the Advance/Mode property to “Auto”. This will make the tree go back to “idle” after playing both animations. Note that the connection icon turns green to show this.\nNow the animations are played in sequence whenever they’re triggered.\nCalling states in code Here is the full tree for all of the animations:\nNow let’s set up the character to use these animations in a script.\nextends CharacterBody2D var state_machine var run_speed = 80.0 var attacks = [\"attack1\", \"attack2\"] @onready var state_machine = $AnimationTree[\"parameters/playback\"] state_machine holds a reference to the state machine, which is an AnimationNodeStateMachinePlayback. To call a specific animation, you use travel(), which will follow the connections to the given animation.\nfunc hurt(): state_machine.travel(\"hurt\") func die(): state_machine.travel(\"die\") set_physics_process(false) Here we have examples of functions we would call if the player is hurt or killed. For the other animations (running, attacking, etc.), we’ll need to combine them with our input and movement code. velocity determines whether we should be showing “run” or “idle”.\nfunc get_input(): var current = state_machine.get_current_node() velocity = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\") * run_speed if Input.is_action_just_pressed(\"attack\"): state_machine.travel(attacks.pick_random()) return # flip the character sprite left/right if velocity.x != 0: $Sprite2D.scale.x = sign(velocity.x) # choose animation if velocity.length() \u003e 0: state_machine.travel(\"run\") else: state_machine.travel(\"idle\") move_and_slide() Note that we’re using return after traveling to the attack animations. This is so that we won’t instead travel to the “run” or “idle” animations further down in the function.\nYou can use the AnimationTreeStateMachine to handle\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos\nRelated recipes Spritesheet animation Top-down character ","description":"","tags":null,"title":"Using the AnimationTree StateMachine","uri":"/godot_recipes/4.x/animation/using_animation_sm/index.html"},{"content":" Gamedev Math Math is a big part of game development. Some of it you may remember from school, or it may be something you’ve never encountered before. Here you’ll find guides to help you get up to speed and examples of how these concepts are applied to making games.\nIn this section: Interpolation Transforms Vectors: Using Dot and Cross Product ","description":"","tags":null,"title":"Gamedev Math","uri":"/godot_recipes/4.x/math/index.html"},{"content":" AI/Behavior Automated behavior and (sometimes) smarter entities.\nIn this section: Chasing the player Homing missile Pet Following ","description":"","tags":null,"title":"AI/Behavior","uri":"/godot_recipes/4.x/ai/index.html"},{"content":"Before we can make enemies, powerups, or any other game objects, we need a place where they can all exist together with the player. In most games, this would be called a “level” or “main” scene, and that’s what we’ll call it here.\nStart the scene with a Node2D called “Main” and save it.\nCreating the background Add a Sprite2D child. Name this sprite “Background” and add the Space_BG (2 frames) (64 x 64).png as its texture.\nThis image has two frames, each 64x64 pixels in size. We’d like the image to tile across the full size of the screen, so start with the following settings:\nUnder Offset set Centered to “off”. This makes the image’s top left corner start at the origin rather than its center.\nUnder Region, turn Enabled “on”, and then set the Rect to a width of 240 and a height of 320. This makes the image stretch to the size of the screen.\nUnder Texture change Repeat to Enabled. This causes the image to repeat over the full size of the screen.\nNow add the player to the scene by selecting the Main node and clicking the Instantiate Child Scene button.\nAnimating the background We can make the scene more dynamic by animating the background. While we could do this in code by changing the region_rect property every frame, we’ll use an AnimationPlayer node instead; add one as a child of Main.\nAt the bottom of the editor window, you’ll see the Animation panel. There’s a lot of information there, so let’s look at how it’s laid out:\nClick the Animation button and choose New Animation. You can name the new animation scroll. Set its Length to 2 and toggle the Looping and Autoplay buttons.\nAnimations work by adding tracks that represent properties that you want the AnimationPlayer to control. In the timeline of the player, you’ll add keyframes that define what value you want the property to have at that particular time.\nWe can add keyframes to the animation by clicking the key icon that now appears next to every property in the Inspector. Make sure the scrubber (the blue indicator on the timeline) is at time 0, then select the Background and click the key next to Region/Rect. You’ll be asked if you want to create a new track and then you’ll see the new track added to the animation panel, with a small dot representing the keyframe you’ve just added. Drag the scrubber to time 2 and then change the y value of the Region/Rect property to 64. Click the key to add another keyframe.\nNow when you press Play on the animation, you should see the background slowly scrolling behind the player.\nNext steps The main scene is now ready for us to add enemies. In the next step we’ll make a single enemy scene, as we did with the bullets, and then instantiate that multiple times.\nPrev Next ","description":"","tags":null,"title":"Main Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_06/index.html"},{"content":" Physics Learn how to use Godot’s physics nodes.\nIn this section: RigidBody2D: Look at Target RigidBody2D: Drag and Drop Character to Rigid Body Interaction Asteroids-style Physics (using RigidBody2D) ","description":"","tags":null,"title":"Physics","uri":"/godot_recipes/4.x/physics/index.html"},{"content":"Problem You want to make a rolling cube in 3D.\nSolution Rolling a cube is trickier than it seems. You can’t just rotate the cube around its center:\nInstead, the cube needs to be rotated around its bottom edge.\nHere’s the tricky part: which bottom edge? It depends on which direction the cube is rolling.\nIn preparing this recipe, I experimented with a few different solutions to this problem:\nPure math - calculating and applying rotation transforms AnimationPlayer - using animations to key the rotations and offsets Helper nodes - using Spatial(s) as rotation helpers They all worked fine, but I found the last option the most flexible and easiest to adapt, so that’s what we’ll do here.\nNode setup Cube: CharacterBody3D Pivot: Node3D Mesh: MeshInstance3D Collision: CollisionShape3D Tip You can do this with RigidBody3D, CharacterBody3D, or Area3D as your collision node. There will be minor differences in how you handle movement. Which node you choose should depend on what other behavior you want in your game. For this recipe, we’re only concerned with the movement.\nBy default, everything is centered at (0, 0, 0) so the first thing we’re going to do is offset everything so that the bottom center of the cube is the CharacterBody3D’s position.\nThe default size of a BoxMesh3D is (1, 1, 1), so do this, move the mesh and collision nodes both up to (0, 0.5, 0), leaving the rest where they are. Now when you select the root node, its position will be the bottom of the cube:\nNow when you want to roll the cube, you’ll need to move the Pivot 0.5 in the direction you want to move. Since the mesh is attached, you need to move it the opposite amount. For example, to roll to the right (+X), you’ll end up with this:\nNow the pivot node is at the correct edge and rotating it will also rotate the mesh.\nMovement script The movement is broken in to 3 steps:\nStep 1 Here we apply the two offsets shown above: shift the Pivot in the direction of movement, and shift the Mesh in the opposite direction.\nStep 2 In this step we animate the rotation. We find the axis of rotation using the cross product of the direction and the down vector. Then we use a Tween to animate rotating the pivot’s transform.\nStep 3 Finally, once the animation has finished, we need to reset everything so that it’s ready to happen again. In the end, we want to have the cube moved 1 unit in the chosen direction (for a cube of size 1) and have the pivot and mesh back at their original positions.\nextends CharacterBody3D @onready var pivot = $Pivot @onready var mesh = $Pivot/MeshInstance3D var cube_size = 1.0 var speed = 4.0 var rolling = false func _physics_process(delta): var forward = Vector3.FORWARD if Input.is_action_pressed(\"ui_up\"): roll(forward) if Input.is_action_pressed(\"ui_down\"): roll(-forward) if Input.is_action_pressed(\"ui_right\"): roll(forward.cross(Vector3.UP)) if Input.is_action_pressed(\"ui_left\"): roll(-forward.cross(Vector3.UP)) func roll(dir): # Do nothing if we're currently rolling. if rolling: return rolling = true # Step 1: Offset the pivot. pivot.translate(dir * cube_size / 2) mesh.global_translate(-dir * cube_size / 2) # Step 2: Animate the rotation. var axis = dir.cross(Vector3.DOWN) var tween = create_tween() tween.tween_property(pivot, \"transform\", pivot.transform.rotated_local(axis, PI/2), 1 / speed) await tween.finished # Step 3: Finalize the movement and reset the offset. transform.origin += dir * cube_size var b = mesh.global_transform.basis pivot.transform = Transform3D.IDENTITY mesh.position = Vector3(0, cube_size / 2, 0) mesh.global_transform.basis = b rolling = false If your cube’s texture isn’t symmetrical, you may notice that it’s resetting after every roll. To preserve the rotation of the mesh, add the following:\nIn Step 1:\nChange mesh.translate(-dir) to mesh.global_translate(-dir).\nIn Step 3:\nAdd two lines to keep the mesh rotation after reset:\n# Step 3: Finalize the movement and reset the offset. transform.origin += dir * cube_size var b = mesh.global_transform.basis # Save the mesh rotation. pivot.transform = Transform3D.IDENTITY mesh.position = Vector3(0, cube_size / 2, 0) mesh.global_transform.basis = b # Restore the mesh rotation. Checking for collisions If you plan to have obstacles in your game, you can check for collisions before moving (similar to any other grid-based movement scheme). Add a raycast check before Step 1 of the move:\n# Cast a ray before moving to check for obstacles var space = get_world_3d().direct_space_state var ray = PhysicsRayQueryParameters3D.create(mesh.global_position, mesh.global_position + dir * cube_size, collision_mask, [self]) var collision = space.intersect_ray(ray) if collision: return Note You could also use a RayCast3D node. Just remember to call force_raycast_update() before checking.\nPlaying with transitions You can add a lot of “personality” to the cube’s rolling behavior by changing which TransitionType you use. The default is Tween.TRANS_LINEAR, which results in a constant speed throughout the movement.\nBy setting a different transition type, you can get a very different feel. For example:\nvar tween = create_tween().set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN) Download This Project Download the project code here: https://github.com/godotrecipes/rolling_cube\nRelated recipes Transforms ","description":"","tags":null,"title":"Rolling Cube","uri":"/godot_recipes/4.x/3d/rolling_cube/index.html"},{"content":" Audio Helpful recipes for adding sound effects and music to your game.\nIn this section: Audio Manager ","description":"","tags":null,"title":"Audio","uri":"/godot_recipes/4.x/audio/index.html"},{"content":"Now that our player can shoot, let’s give them something to shoot at.\nSetting up the scene We’ll use an Area2D for the enemy, since we need it to detect overlap - either with the player’s bullets, or with the player itself.\nHere’s are the nodes we’ll need:\nEnemy: Area2D Sprite2D CollisionShape2D AnimationPlayer MoveTimer: Timer ShootTimer: Timer Select the area node and click the Node tab next to the Inspector. Under Groups, type “enemies” an click Add. Remember the code we wrote on the bullet? It looks for objects in the “enemies” group.\nIn the sprite’s Texture, add Bon_Bon (16 x 16).png and set its Animation/Hframes to 4.\nAs you’ve done before, add a rectangular collision shape and size it to fit. Enable One Shot on both timer nodes.\nIn the AnimationPlayer, add an animation called “bounce” and set it to looping and autoplay. Set the Snap at the bottom of the animation panel to 0.05.\nSelect the sprite node and press the key icons next to Texture and Hframes to create tracks for them. We’re doing this because later we’ll add an “explosion” animation that will use different values for these properties.\nNow we’ll key the individual Frames values we want. Start with keying Frames each .1 seconds to values in this order2, 1, 0, 3. Finally, key 0 again and put it immediately after. This will make a “pulsing” animation where the sprite grows and then bounces a little at the end. The animation setup should look like this:\nPress the play button to see it in action. Feel free to adjust it if you’d like.\nNow add another animation called “explode”. Set its length to 0.4 seconds.\nChange the sprite’s Texture to Explosion (16 x 16).png and keyframe that property. Since this image has a different number of frames than the enemy image, we also need to change Hframes to 6 and keyframe that.\nNow keyframe Frame to 0 at time 0 and to 5 at time 0.4. Play the animation to see it in action.\nEnemy script The enemies will spawn at the top of the screen in a grid. After a random amount of time, they’ll descend toward the player and then return to the top if they weren’t destroyed. Periodically, they’ll also shoot at the player.\nAdd a script, and start with the variables:\nextends Area2D var start_pos = Vector2.ZERO var speed = 0 @onready var screensize = get_viewport_rect().size The start_pos variable is going to keep track of the enemy’s starting position so that after it moves, it can return to its original location. We’ll set it when the enemy is spawned and we call its start() function.\nfunc start(pos): speed = 0 position = Vector2(pos.x, -pos.y) start_pos = pos await get_tree().create_timer(randf_range(0.25, 0.55)).timeout var tween = create_tween().set_trans(Tween.TRANS_BACK) tween.tween_property(self, \"position:y\", start_pos.y, 1.4) await tween.finished $MoveTimer.wait_time = randf_range(5, 20) $MoveTimer.start() $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() When we spawn our enemies we’ll call this function and pass it a position vector representing where on the screen the enemy should go. Note that we actually spawn it above the top of the screen (negative y value). This is so that we can animate it coming onto the screen using a tween. We also randomize the two timers so that all enemies won’t be moving and shooting at the same time.\nConnect both of the timers’ timeout signals.\nfunc _on_timer_timeout(): speed = randf_range(75, 100) func _on_shoot_timer_timeout(): $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() We can start moving when the timer runs out, and we’ll also shoot, but we haven’t made a bullet yet, so that part will come later. Now that we’re changing the speed, we can move using it.\nfunc _process(delta): position.y += speed * delta if position.y \u003e screensize.y + 32: start(start_pos) Now if the speed isn’t 0, we’ll see the enemy move down the screen. When it goes off the bottom, we start it all over again.\nWe’ve already written the code in the bullet scene that calls explode() on the enemies it hits, so let’s add that too.\nfunc explode(): speed = 0 $AnimationPlayer.play(\"explode\") set_deferred(\"monitoring\", false) died.emit(5) await $AnimationPlayer.animation_finished queue_free() In this function, we stop moving, play the explosion animation, and then delete the enemy when it’s finished. The set_deferred() call makes sure to turn off monitoring on the enemy. This is so that while the enemy is exploding, another bullet can’t hit it again.\nAdd the died signal at the top of the script:\nsignal died We’ll use that signal to let the main scene know that the player just earned some points.\nSpawning enemies Now let’s go to the Main scene and add these enemies to the game. Add a script to Main and start by loading the enemy scene:\nextends Node2D var enemy = preload(\"res://enemy.tscn\") var score = 0 Spawning enemies ordinarily won’t happen until we’ve pressed the “Start” button to begin the game, but since we haven’t made that yet, we’ll just spawn them immediately:\nfunc _ready(): spawn_enemies() func spawn_enemies(): for x in range(9): for y in range(3): var e = enemy.instantiate() var pos = Vector2(x * (16 + 8) + 24, 16 * 4 + y * 16) add_child(e) e.start(pos) e.died.connect(_on_enemy_died) This makes 27 enemies and positions them in a grid in the top half of the screen. We also make sure to connect the died signal of each, so we need to create that function:\nfunc _on_enemy_died(value): score += value We don’t have a way to display the score yet, but we’ll get to that soon.\nPlay the scene and you should see a bunch of enemies appear at the top and periodically fall down the screen. Next, we’ll make them shoot.\nPrev Next ","description":"","tags":null,"title":"Enemies","uri":"/godot_recipes/4.x/games/first_2d/first_2d_07/index.html"},{"content":"Problem You want to click-and-drag to select multiple units, RTS style.\nSolution Realtime strategy (RTS) games often require giving orders to many units at once. A typical style of selecting multiple units is to click-and-drag a box around them. Once the units are selected, clicking on the map commands them to move.\nHere’s an example of what we’re going for:\nUnit setup To test this out, we’ll need some basic RTS-style units. They are set up to move towards a target and to avoid running into each other. We won’t go into too much detail on them in this tutorial. The unit script is commented if you’d like to use it as a base for creating your own RTS units. See below for a link to download the project.\nWorld setup Processing the unit selection will happen in the world. We’ll start with a Node2D called “World” and add a few Unit instances in it. Attach a script to the World node and add the following variables:\nextends Node2D var dragging = false # Are we currently dragging? var selected = [] # Array of selected units. var drag_start = Vector2.ZERO # Location where drag began. var select_rect = RectangleShape2D.new() # Collision shape for drag box. Note that once we’ve drawn the box, we’ll need a way to find what units are inside it. The RectangleShape2D will allow us to query the physics engine and see what we collided with.\nDrawing the box We’ll be using the left mouse button for this. Clicking starts a drag and then letting go ends it. During dragging, we’ll draw the rectangle for visibility.\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: # If the mouse was clicked and nothing is selected, start dragging if selected.size() == 0: dragging = true drag_start = event.position # If the mouse is released and is dragging, stop dragging elif dragging: dragging = false queue_redraw() if event is InputEventMouseMotion and dragging: queue_redraw() func _draw(): if dragging: draw_rect(Rect2(drag_start, get_global_mouse_position() - drag_start), Color.YELLOW, false, 2.0) Selecting the units Now that we’ve got a selection box, we need to find the units that are inside it. When we release the button and the drag ends, we must query the physics space to find the units. Note that the units are CharacterBody2D, but Area2D or other bodies would work as well.\nWe’ll use PhysicsDirectSpaceState2D.intersect_shape() to find the units. This requires a shape (our rectangle) and a transform (our location). See Godot docs for details.\nelif dragging: dragging = false queue_redraw() var drag_end = event.position select_rect.extents = abs(drag_end - drag_start) / 2 We start by recording the location when we released the button, and use that to set the RectangleShape2D’s extents (remember: extents are measured from the rectangle’s center, so they’re half the full width/height).\nvar space = get_world_2d().direct_space_state var query = PhysicsShapeQueryParameters2D.new() q.shape = select_rect q.collision_mask = 2 # Units are on collision layer 2 q.transform = Transform2D(0, (drag_end + drag_start) / 2) selected = space.intersect_shape(query) Now we get a reference to the physics state and set up our shape query using PhysicsShapeQueryParameters2D, assigning it our shape, and using the center of the dragged area as the origin for the query’s transform. Our result after calling intersect_shape() is an array of dictionaries, which looks like this:\n[{ \"rid\": RID(4093103833089), \"collider_id\": 32145147326, \"collider\": Unit2:\u003cCharacterBody2D#32145147326\u003e, \"shape\": 0 }, { \"rid\": RID(4123168604162), \"collider_id\": 32229033411, \"collider\": Unit3:\u003cCharacterBody2D#32229033411\u003e, \"shape\": 0 }] Each of those collider items is a reference to a unit, so we can use this to notify them that they’ve been selected, activating the outline shader:\nfor item in selected: item.collider.selected = true Commanding the units Finally, we can command the selected units to move by clicking somewhere on the screen:\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: # If the mouse was clicked and nothing is selected, start dragging if selected.size() == 0: dragging = true drag_start = event.position # Otherwise a click tells the selected units to move else: for item in selected: item.collider.target = event.position item.collider.selected = false selected = [] The else clause here triggers if we click the mouse when selected is greater than 0. Each item’s target is set, and we make sure to deselect the units so we can start again.\nWrapping up This technique can be expanded to a wide range of RTS or other game styles. Download the full project below and use it as a base for your own game.\nDownload This Project Download the project code here: https://github.com/godotrecipes/multi_unit_select\nRelated recipes Mouse Input ","description":"","tags":null,"title":"Mouse: Drag-select multiple units","uri":"/godot_recipes/4.x/input/multi_unit_select/index.html"},{"content":"Now that our enemy can shoot, let’s give them something to shoot at.\nEnemy bullet scene Make a new EnemyBullet scene just like you made the player bullet earlier. We won’t go into all the steps here, but you can refer back to that part if you’re stuck. The only difference here is that you can use the Enemy_projectile (16 x 16).png image instead.\nThe script will be a little bit different:\nextends Area2D @export var speed = 150 func start(pos): position = pos func _process(delta): position.y += speed * delta Connect the screen_exited and area_entered signals of the VisibleOnScreenNotifier2D and Area2D, respectively:\nfunc _on_visible_on_screen_notifier_2d_screen_exited(): queue_free() func _on_area_entered(area): if area.name == \"Player\": queue_free() Notice that we’re detecting the hit on the player, but it’s not doing anything yet. We’ll come back to that once we add a way for the player to take damage.\nAdding shooting to the enemy At the top of the enemy’s script, load the new bullet:\nvar bullet_scene = preload(\"res://enemy_bullet.tscn\") Then update the shooting function:\nfunc _on_shoot_timer_timeout(): var b = bullet_scene.instantiate() get_tree().root.add_child(b) b.start(position) $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() Play the Main scene again and you should have some random enemy bullets appearing.\nPrev Next ","description":"","tags":null,"title":"Enemy Shooting","uri":"/godot_recipes/4.x/games/first_2d/first_2d_08/index.html"},{"content":"Problem You want to make a 3D spaceship that flies in an arcade/cinematic way. You’re not looking for realistic physics, but more of a dog-fighting, “Star Wars”-style of spaceflight.\nSolution To accomplish this, we’ll use a CharacterBody3D for the ship. The three axis inputs (pitch, roll, and yaw) will rotate the body’s basis around the corresponding axis. The direction of motion will always point forward.\nNote You can do this with RigidBody3D and get the same results. See the example project linked below, which includes a rigid body version as well.\nAssets Spaceship models are from this asset pack:\nUltimate Spaceships Pack by Quaternius\nI’ve chosen the “Executioner” ship model:\nFeel free to choose your favorite design.\nSetup Select the gltf file of the ship you want, and click the Import tab. Change the Root Type to CharacterBody3D and click “Reimport”. Then double-click the gltf and you’ll have a new inherited scene with a CharacterBody3D root and a MeshInstance child. Add a CollisionShape3D to the body.\nIn Project Settings -\u003e Input Map, set up the following inputs:\nroll_right / roll_left pitch_up / pitch_down yaw_right / yaw_left throttle_up / throttle_down You can assign keys or controller inputs. Analog stick inputs will work best.\nMovement To start the script, let’s handle the forward movement. Pressing the throttle buttons smoothly increases/decreases the speed.\nextends CharacterBody @export var max_speed = 50.0 @export var acceleration = 0.6 var forward_speed = 0 func get_input(delta): if Input.is_action_pressed(\"throttle_up\"): forward_speed = lerp(forward_speed, max_speed, acceleration * delta) if Input.is_action_pressed(\"throttle_down\"): forward_speed = lerp(forward_speed, 0, acceleration * delta) func _physics_process(delta): get_input(delta) velocity = -transform.basis.z * forward_speed move_and_collide(velocity * delta) Make a test scene with a Camera3D to try it out. You can use a stationary camera or a chase camera. Check that the ship accelerates and slows before moving on to the next step.\nRotation Now we can handle rotation in the three axes. Add the following variables at the top of the script:\n@export var pitch_speed = 1.5 @export var roll_speed = 1.9 @export var yaw_speed = 1.25 var pitch_input = 0.0 var roll_input = 0.0 var yaw_input = 0.0 The three axis speeds will affect the “handling” of the ship. Experiment to find values the work for you and your desired flight style.\nNext, add these lines to get_input() to capture the three axis inputs:\npitch_input = Input.get_axis(\"pitch_down\", \"pitch_up\") roll_input = Input.get_axis(\"roll_right\", \"roll_left\") yaw_input = Input.get_axis(\"yaw_right\", \"yaw_left\") Finally, we need to rotate the ship’s Basis according to the inputs. Note how each input affects one axis of rotation:\ntransform.basis = transform.basis.rotated(transform.basis.z, roll_input * roll_speed * delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(transform.basis.y, yaw_input * yaw_speed * delta) transform.basis = transform.basis.orthonormalized() Improvements Currently the rotations are a little to “sharp”. The ship starts and stops rotating instantly, which feels a bit too unnatural. We can solve this with lerp(), and by adding one more configuration variable to set how “floaty” we’d like the controls to be:\n@export var input_response = 8.0 Change the three axis inputs in get_input() to the following:\npitch_input = lerp(pitch_input, Input.get_axis(\"pitch_down\", \"pitch_up\"), input_response * delta) roll_input = lerp(roll_input, Input.get_axis(\"roll_right\", \"roll_left\"), input_response * delta) yaw_input = lerp(yaw_input, Input.get_axis(\"yaw_right\", \"yaw_left\"), input_response * delta) Now when stopping or changing direction, there’s a little bit of inertia.\nLinking roll/yaw One problem with this control scheme is that it’s awkward. Having to use a separate stick for the yaw input makes it difficult to control, especially when also shooting and using other controls. Many games solve this by linking the roll input to also apply a small amount of yaw. To do this, change the yaw_speed to around 1/4 to 1/2 of the roll_speed.\nIn the get_input() function, change the line getting yaw_input to the following:\nyaw_input = roll_input This is another fun place to experiment by changing the roll and yaw speeds. For example, what if yaw was primary and roll smaller? What if other axes were linked? If your game has different ships, you can give them different values for variety in flight styles/performance.\nWrapping up That’s it, now you can fly! This controller is a great start for whatever space-based game you might have in mind. Add some other ships, and a few effects, and you’re ready go:\nFull script Here’s the complete script:\nextends CharacterBody3D @export var max_speed = 50.0 @export var acceleration = 0.6 @export var pitch_speed = 1.5 @export var roll_speed = 1.9 @export var yaw_speed = 1.25 # Set lower for linked roll/yaw @export var input_response = 8.0 var forward_speed = 0.0 var pitch_input = 0.0 var roll_input = 0.0 var yaw_input = 0.0 func get_input(delta): if Input.is_action_pressed(\"throttle_up\"): forward_speed = lerp(forward_speed, max_speed, acceleration * delta) if Input.is_action_pressed(\"throttle_down\"): forward_speed = lerp(forward_speed, 0.0, acceleration * delta) pitch_input = lerp(pitch_input, Input.get_axis(\"pitch_down\", \"pitch_up\"), input_response * delta) roll_input = lerp(roll_input, Input.get_axis(\"roll_right\", \"roll_left\"), input_response * delta) # yaw_input = lerp(yaw_input, Input.get_axis(\"yaw_right\", \"yaw_left\"), input_response * delta) yaw_input = roll_input func _physics_process(delta): get_input(delta) transform.basis = transform.basis.rotated(transform.basis.z, roll_input * roll_speed * delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(transform.basis.y, yaw_input * yaw_speed * delta) transform.basis = transform.basis.orthonormalized() velocity = -transform.basis.z * forward_speed move_and_collide(velocity * delta) Related recipes Interpolated Camera Download This Project Download the project code here: https://github.com/godotrecipes/3d_spaceship\n","description":"","tags":[],"title":"Arcade-style Spaceship","uri":"/godot_recipes/4.x/3d/spaceship/index.html"},{"content":"The last main piece of our game is the user interface (UI). We need a way to show the player the score and other information. To do this, we’ll use a variety of Control nodes - the nodes Godot provides for building UIs.\nUI scene Start the scene with a MarginContainer and name it UI.\nContainers are Control nodes that are designed to control the size and position of their children. Using them makes it easier to position and move Control nodes without having to do it manually. The MarginContainer makes sure its children don’t get too close to the edge.\nIn the Inspector under Theme Overrides/Constants set all four Margin values to 10. Then, in the menu bar at the top of the viewport, set the anchors to the Top Wide preset.\nNext, we’ll add an HBoxContainer. This type of container organizes its children horizontally. Under that, add a TextureProgressBar, which will represent our ship’s shield level. Name it ShieldBar.\nUnfortunately, there’s not a good image in the art pack to use for a progress bar (there is one, but it isn’t formatted in an easy way to work with). Instead, we’ll use the two images below. One is a green bar and the other is a white outline. Save them in your project folder.\nIn the Texture section, drag the foreground image to the Progress and the background image to the Under texture. The first thing you’ll notice is that it’s very small. Let’s first under Layout set Custom Minimum Size to (80, 16). You’ll notice that the orange selection rectangle got bigger, but the image didn’t. Well, we don’t want the image to just stretch, or it would look bad. Instead we’ll check the Nine Patch Stretch box, and then set the four Stretch Margin values to 3.\nYou should now see a long, unfilled bar. To see what it looks like when filled, change the Value property in the Range section to anything between 0 and 100.\nOn the right side, we’d like to show the score. Now, we could just use a Label node and add a font, but that’s not very fun. The art pack includes a lovely pixel set of digits that we could use instead. We’ll just need to do a little coding to chop it up and show the corect digit(s).\nScore counter Start a new scene and add an HBoxContainer. Name it ScoreCounter then set it to Top Wide and set the Alignment to “End”. Also, set the Theme Overrides/Constants/Separation to 0 (you need to check the box next to the property).\nIn this container, we’ll have a string of TextureRect nodes showing each digit. We’ll start by adding one and then duplicating it.\nName the TextureRect Digit0. Under Texture, select “New AtlasTexture”, then click the box to open it. Drag Number_font (8 x 8).png into the Atlas property, then set the Region to (32, 8, 8, 8). Set Stretch Mode to “Keep Aspect Centered”.\nSelect the Digit0 node and press Ctrl-D 7 times to create duplicates of the node. The picture below shows what you should see after this step:\nWe now have an issue, though. Even though we’ve duplicated the TextureRect to create 8 unique copies, they are all using the same AtlasTexture in the Texture property. This means that when we change the Region to show a different digit, it will change on all the digits.\nThis is because Resource objects (such as Texture) are loaded into memory and then shared - there’s really only one texture. While this is very efficient, because you don’t waste memory loading the same image multiple times, it means that when we do want things to be unique, we have to specify it.\nOn each of the nodes, click the down arrow next to the AtlasTexture and select “Make Unique”.\nNow we’ll add a script to ScoreCounter that will choose the correct Region values for whichever digit it needs to display.\nextends HBoxContainer var digit_coords = { 1: Vector2(0, 0), 2: Vector2(8, 0), 3: Vector2(16, 0), 4: Vector2(24, 0), 5: Vector2(32, 0), 6: Vector2(0, 8), 7: Vector2(8, 8), 8: Vector2(16, 8), 9: Vector2(24, 8), 0: Vector2(32, 8) } func display_digits(n): var s = \"%08d\" % n for i in 8: get_child(i).texture.region = Rect2(digit_coords[int(s[i])], Vector2(8, 8)) We start by making a list of the coordinates in the image where each digit is found. Then, display_digits() will format the number to an 8 digit number (for example, 258 would become \"00000258\"). Then, for each digit, we can apply the correct coordinates from the array.\nScripting the UI Go back to the UI scene and add the ScoreCounter to the HBoxContainer, then add a script to UI.\nextends MarginContainer @onready var shield_bar = $HBoxContainer/ShieldBar @onready var score_counter = $HBoxContainer/ScoreCounter func update_score(value): score_counter.display_digits(value) func update_shield(max_value, value): shield_bar.max_value = max_value shield_bar.value = value We’ll call these functions from Main whenever we need to update the score or the shield.\nAdding the UI to main Now in the Main scene add a CanvasLayer node, and instance the UI as its child. The CanvasLayer node creates another drawing layer, so our UI will be drawn on top of the rest of the game.\nChange this function in main.gd:\nfunc _on_enemy_died(value): score += value $CanvasLayer/UI.update_score(score) Run the game and see that your score goes up when shooting enemies.\nPlayer shield We can also add the shield to the player’s script. Add these new lines at the top of player.gd:\nsignal died signal shield_changed @export var max_shield = 10 var shield = max_shield: set = set_shield This set = syntax tells Godot that we want to call the set_shield() function whenever the shield variable has its value set.\nfunc set_shield(value): shield = min(max_shield, value) shield_changed.emit(max_shield, shield) if shield \u003c= 0: hide() died.emit() We can also connect the ship’s area_entered signal so that we can detect when an enemy hits the ship:\nfunc _on_area_entered(area): if area.is_in_group(\"enemies\"): area.explode() shield -= max_shield / 2 And in the enemy bullet, add some damage to the shield when it hits:\nfunc _on_area_entered(area): if area.name == \"Player\": queue_free() area.shield -= 1 Finally, we need to connect the player’s shield_changed signal to the function in the UI that updates the shield bar. You can do this in the Inspector by selecting the Player node in the Main scene. Under the Node tab, double-click the shield_changed signal to open the “Connect a Signal” window. In this window, select the UI node and type update_shield in the Receiver Method box.\nRun the game again and check that your shield depletes when you get hit by a bullet or an enemy.\nNext steps We’re almost done with the basic functionality. We just need a way to start and end the game.\nPrev Next ","description":"","tags":null,"title":"UI and Score","uri":"/godot_recipes/4.x/games/first_2d/first_2d_09/index.html"},{"content":"Problem You’ve imported a rigged, animated 3D character in Godot and set up its animations using AnimationTree. Now you need to implement movement: you need a character controller.\nSolution In this recipe, we’ll assume you’ve already imported your character model and animations, and that you’re set up AnimationTree to handle transitioning and blending the animations. If you haven’t yet, see Importing Assets and Character Animation for details. As a reminder, we’re using the art packs linked in the section description.\nAdding collision We’ve chosen CharacterBody3D as the root node of the imported scene, and it’s complaining about a missing collision shape, so let’s fix that first. Add a CollisionShape3D child and choose CapsuleShape3D as its Shape property.\nSize and position the capsule to enclose the character’s body. For reference, here are the values I used:\nNote that the imported rig is positioned so that its feet are on the “ground”, ie at the body’s position. This will be helpful later, as the player’s position will represent its position on the ground, rather than floating in mid-air if it were at the center of its body.\nIf you’re familiar with Godot’s 3D orientation, you’ll also notice that the character is facing the +Z direction, which is backwards. Select the Skeleton3D node and set its Y Rotation to 180 to correct this.\nInput actions In the Input Map, we’re using the following inputs: forward, back, left, right, and jump. Assign them to whatever keys/buttons you prefer.\nCamera There are many ways to handle a 3D camera that follows the player. For this example, we’ll use a SpringArm3D as the camera “mount”.\nThe SpringArm3D node works by casting a ray and then moving its children to the collision point. Using this for a camera means nothing can get between the camera and the player, and we can implement zoom by varying this length.\nAdd one as a child of the root node, and then add a Camera3D as a child of that.\nIn the spring arm’s properties, set Spring Length to 5, the Margin to 0.1, and the Position to (0, 2.5, 0).\nWe don’t want the spring arm to collide with the player’s capsule shape, so in the root CharacterBody3D set the collision layer to 2. Since the spring arm is checking collision layer 1, that will prevent the camera hitting the player’s head.\nCollision Layers Eventually, we’ll want to organize our collision layers for various game objects: player, environment, enemies, etc.\nMovement Now we are ready to add a script to the player. We’ll start with the variables we’ll need:\nextends CharacterBody3D class_name Knight @export var speed = 5.0 @export var acceleration = 4.0 @export var jump_speed = 8.0 var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var jumping = false And then, some references to the nodes we’ll need to access:\n@onready var spring_arm = $SpringArm3D @onready var model = $Rig @onready var anim_tree = $AnimationTree @onready var anim_state = $AnimationTree.get(\"parameters/playback\") We’ll use the anim_tree reference to set the blend position for the Idle/Walk/Run blendspace and the trigger conditions for jumping. Select the AnimationTree and you can see these properties in the Inspector:\nanim_state is a reference to the animation state machine, which we can use to call transitions between animations. See the Character Animation recipe for how we set these up.\nMovement is a matter of getting the player’s input and calling move_and_slide():\nfunc _physics_process(delta): velocity.y += -gravity * delta get_move_input(delta) move_and_slide() The player’s input should be applied to the horizontal motion only (X and Z axes), since gravity is acting on the Y axis. For that reason, we’ll temporarily zero out the velocity.y, set the input, and then restore the value when we’re done.\nNote that we’re rotating the input vector using the camera’s rotation - our character is going to move forward in whatever direction the camera is facing.\nfunc get_move_input(delta): var vy = velocity.y velocity.y = 0 var input = Input.get_vector(\"left\", \"right\", \"forward\", \"back\") var dir = Vector3(input.x, 0, input.y).rotated(Vector3.UP, spring_arm.rotation.y) velocity = lerp(velocity, dir * speed, acceleration * delta) velocity.y = vy Before we do anything else, this is a good point to test things out. You can make a quick test scene with a big StaticBody3D for the ground, or start making a scene using the dungeon pack assets.\nYou should be able to move forward/back/left/right (without any animations yet).\nCamera Control Now let’s get the camera working. We want to control the camera with mouse movement. We’ll add a variable that lets us adjust the sensitivity.\n@export var mouse_sensitivity = 0.0015 Then, we want to detect mouse motion and rotate the spring arm accordingly. Rotating the arm around the X axis tilts it up and down (using the mouse’s y motion), and rotating it around Y changes its facing direction (using the mouse’s x motion). We also clamp the camera’s tilt so that it doesn’t go too far up/down.\nfunc _unhandled_input(event): if event is InputEventMouseMotion: spring_arm.rotation.x -= event.relative.y * mouse_sensitivity spring_arm.rotation_degrees.x = clamp(spring_arm.rotation_degrees.x, -90.0, 30.0) spring_arm.rotation.y -= event.relative.x * mouse_sensitivity Try it out and you should see when pressing “forward”, the character moves in the direction the camera faces.\nNow we need to rotate the character so they face in the direction of movement.\nWe’ll add a variable for the rotation speed, so that we don’t snap instantly to the new heading.\n@export var rotation_speed = 12.0 And then add this in _physics_process(), after move_and_slide():\nif velocity.length() \u003e 1.0: model.rotation.y = lerp_angle(model.rotation.y, spring_arm.rotation.y, rotation_speed * delta) Using lerp_angle() ensures we’ll always rotate the shortest direction to the new angle (rather than going the long way around from a 359° rotation to a 1° rotation, for example).\nIWR Animations Now that we have movement and rotation, we need to choose animations. The idea is to take the character’s horizontal velocity (the x/z movement) and use it to set the blend position in the IWR blendspace we created.\nIn get_move_input(), we’re setting the player’s velocity. Just after that, we can set the blend position:\nvelocity = lerp(velocity, dir * speed, acceleration * delta) var vl = velocity * model.transform.basis anim_tree.set(\"parameters/IWR/blend_position\", Vector2(vl.x, -vl.z) / speed) Since velocity is in global space, but the character model is rotating, we need to transform velocity into model space using the model’s basis. Once we have that, we need to map that 3D vector to the 2D vector of the blend space, dividing by speed so that we’ll get values between -1 and 1. Also, -z is forward, but +y represents the blendspace forward animation, so we negate the value to make them match.\nNote that you can get that parameter path by looking at the Inspector for the AnimationTree - you can even drag it into the script window to fill it in.\nAttacks We can handle attacks by first adding an input action called \"attack\", which I’ve assigned to the left mouse button.\nSince we have 3 separate attacks in the AnimationTree, we’ll make a list of them:\nvar attacks = [ \"1h_slice_diagonal\", \"1h_slice_horizontal\", \"1h_attack_chop\" ] Then, in _unhandled_input(), pick a random animation from the list when the action is pressed:\nif event.is_action_pressed(\"attack\"): anim_state.travel(attacks.pick_random()) Jumping Jumping is a little bit more involved, because it involves three separate animations. As a reminder, this is how we set up the state machine:\nFirst, we want to transition to the “Jump_Start” animation by setting jumping = true. This triggers the transition in the state machine.\nif is_on_floor() and Input.is_action_just_pressed(\"jump\"): velocity.y = jump_speed jumping = true anim_tree.set(\"parameters/conditions/grounded\", false) anim_tree.set(\"parameters/conditions/jumping\", jumping) Next, we need to know when we touch the ground, so we can transition out of the “Jump_Idle” animation. To do this, we need to keep track of our grounded status by comparing it with the previous frame. Add a new variable at the top:\nvar last_floor = true And then this if statement after the first one above:\n# We just hit the floor after being in the air if is_on_floor() and not last_floor: jumping = false anim_tree.set(\"parameters/conditions/grounded\", true) last_floor = is_on_floor() Finally, there’s the direct transition to “Jump_Idle” that happens if we step off a ledge:\n# We're in the air, but we didn't jump if not is_on_floor() and not jumping: anim_state.travel(\"Jump_Idle\") anim_tree.set(\"parameters/conditions/grounded\", false) Wrapping up We’ve now got a functional, controllable character with a chase camera and multiple animations. What’s next?\nSee the section description for more examples of working in 3D and for example Godot projects you can download.\nCompanion Video ","description":"","tags":null,"title":"Character Controller","uri":"/godot_recipes/4.x/3d/assets/character_controller/index.html"},{"content":"Problem You need to have a game entity such as a pet or minion, follow a character.\nSolution We start by adding a Marker2D to the character. This will represent the place where the pet wants to “hang out” near the character.\nIn this example, we’ve made it a child of the Sprite2D, because the character’s code uses $Sprite2D.scale.x = -1 to flip the horizontal direction when the character moves left. Since the marker is a child of the sprite, it will flip too.\nPet script Here’s the script for the pet.\nextends CharacterBody2D @export var parent : CharacterBody2D var speed = 25 @onready var follow_point = parent.get_node(\"Sprite2D/FollowPoint\") The parent variable holds a reference to the character the pet should follow. We then get the FollowPoint node from that so we can get its position in _physics_process():\nfunc _physics_process(delta): var target = follow_point.global_position velocity = Vector2.ZERO if position.distance_to(target) \u003e 5: velocity = position.direction_to(target) * speed if velocity.x != 0: $Sprite2D.scale.x = sign(velocity.x) if velocity.length() \u003e 0: $AnimationPlayer.play(\"run\") else: $AnimationPlayer.play(\"idle\") move_and_slide() If it’s close to the target point, we stop the pet’s movement.\nNavigating obstacles Depending on your world, you may find the pet gets stuck on obstacles. For more robust following, you can use navigation. See TileMap Navigation for an example.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos\n","description":"","tags":null,"title":"Pet Following","uri":"/godot_recipes/4.x/ai/pet_following/index.html"},{"content":"Our last step is to add a start button and a “game over” state to the game.\nStarting the game Currently when we run the game, it starts immediately. Let’s add a button to start it.\nIn Main as a child of the CanvasLayer, add a CenterContainer and set its layout to Full Rect. Then add a TextureButton child. Name this button Start and add the START (48 x 8).png image as its Normal texture.\nAdd a reference at the top of the script:\n@onready var start_button = $CanvasLayer/CenterContainer/Start Connect this button’s pressed texture to Main and add this code:\nfunc _on_start_pressed(): start_button.hide() new_game() The new_game() function handles starting the game, so change _ready() so that it no longer spawns enemies, but just ensures the button is showing:\nfunc _ready(): start_button.show() #\tspawn_enemies() Now add the new_game() function:\nfunc new_game(): score = 0 $CanvasLayer/UI.update_score(score) $Player.start() spawn_enemies() Now the button should show when you run the scene, and pressing it starts the game.\nEnding the game Add a TextureRect as a child of the CenterContainer and name the node GameOver. Use the GAME_OVER (72 x 8).png image. It will overlap with the start button, but that’s ok, we’re only ever going to show one at a time.\nAdd another reference at the top of the script:\n@onready var game_over = $CanvasLayer/CenterContainer/GameOver And add game_over.hide() to _ready().\nConnect the player’s died signal in Main.\nfunc _on_player_died(): get_tree().call_group(\"enemies\", \"queue_free\") game_over.show() await get_tree().create_timer(2).timeout game_over.hide() start_button.show() This will show the “game over” image for 2 seconds, then switch back to the start button so you can play again. Try it out and see if you can play a few games.\nPrev Next ","description":"","tags":null,"title":"Starting and Ending the Game","uri":"/godot_recipes/4.x/games/first_2d/first_2d_10/index.html"},{"content":"Problem You need a dynamic camera that moves and zooms to keep multiple objects on screen at the same time.\nAn example might be in a 2 player game, keeping both players on-screen as they move farther and closer together, like so:\nSolution In a single-player game, you’re probably used to attaching the camera to the player, so that it automatically follows them. We can’t really do this here because we have 2 (or more) players or other game objects that we want to keep on the screen at all times.\nWe need our camera to do 3 things:\nAdd/remove any number of targets. Keep the camera’s position centered at the midpoint of the targets. Adjust the camera’s zoom to keep all targets on screen. Create a new scene with a Camera2D and attach a script. We’ll add this camera to our game once we’re done.\nLet’s break down how the script works.\nNote You can see the full script at the end of the article.\nHere’s how the script starts:\nextends Camera2D @export var move_speed = 30 # camera position lerp speed @export var zoom_speed = 3.0 # camera zoom lerp speed @export var min_zoom = 5.0 # camera won't zoom closer than this @export var max_zoom = 0.5 # camera won't zoom farther than this @export var margin = Vector2(400, 200) # include some buffer area around targets var targets = [] # Array of targets to be tracked. @onready var screen_size = get_viewport_rect().size These settings will let you adjust the camera’s behavior. We’ll lerp() all camera changes, so setting the move/zoom speeds to lower values will introduce some delay in the camera “catching up” to sudden changes.\nMaximum and minimum zoom values will also depend on the size of objects in your game and how close or far you want to get. Adjust to suit.\nThe margin property is going to add some extra space around the targets so they’re not right on the edge of the viewable area.\nLastly, we have our array of targets and we get the viewport size so that we can properly calculate the scale.\nfunc add_target(t): if not t in targets: targets.append(t) func remove_target(t): if t in targets: targets.erase(t) For adding and removing targets, we have two helper functions. You can use these during gameplay to change what targets are being tracked (“Player 3 has entered the game!”). Note that we don’t want to have the same target tracked twice, so we reject it if it’s already there.\nMost of the functionality happens in _process(). First, moving the camera:\nfunc _process(delta): if !targets: return # Keep the camera centered between the targets var p = Vector2.ZERO for target in targets: p += target.position p /= targets.size() position = lerp(position, p, move_speed * delta) Here, we loop through the targets’ positions and find the common center. Using lerp() we make sure it moves there smoothly.\nNext, we’ll handle the zoom:\n# Find the zoom that will contain all targets var r = Rect2(position, Vector2.ONE) for target in targets: r = r.expand(target.position) r = r.grow_individual(margin.x, margin.y, margin.x, margin.y) var z if r.size.x \u003e r.size.y * screen_size.aspect(): z = 1 / clamp(r.size.x / screen_size.x, min_zoom, max_zoom) else: z = 1 / clamp(r.size.y / screen_size.y, min_zoom, max_zoom) zoom = lerp(zoom, Vector2.ONE * z, zoom_speed) The key functionality here comes from Rect2. We want to find a rectangle that encloses all the targets, which we can get with the expand() method. We then grow the rect by the margin.\nHere you can see the rectangle being drawn (press “Tab” in the demo project to enable this drawing):\nThen, depending whether the rectangle is wider or taller (relative to the screen’s aspect ratio), we find the scale and clamp it in the max/min range we’ve defined.\nFull script extends Camera2D @export var move_speed = 30 # camera position lerp speed @export var zoom_speed = 3.0 # camera zoom lerp speed @export var min_zoom = 5.0 # camera won't zoom closer than this @export var max_zoom = 0.5 # camera won't zoom farther than this @export var margin = Vector2(400, 200) # include some buffer area around targets var targets = [] @onready var screen_size = get_viewport_rect().size func _process(delta): if !targets: return # Keep the camera centered among all targets var p = Vector2.ZERO for target in targets: p += target.position p /= targets.size() position = lerp(position, p, move_speed * delta) # Find the zoom that will contain all targets var r = Rect2(position, Vector2.ONE) for target in targets: r = r.expand(target.position) r = r.grow_individual(margin.x, margin.y, margin.x, margin.y) var z if r.size.x \u003e r.size.y * screen_size.aspect(): z = 1 / clamp(r.size.x / screen_size.x, max_zoom, min_zoom) else: z = 1 / clamp(r.size.y / screen_size.y, max_zoom, min_zoom) zoom = lerp(zoom, Vector2.ONE * z, zoom_speed * delta) # For debug get_parent().draw_cam_rect(r) func add_target(t): if not t in targets: targets.append(t) func remove_target(t): if t in targets: targets.remove(t) Download This Project Download the project’s example code here: https://github.com/godotrecipes/multitarget_camera\n","description":"","tags":null,"title":"Multitarget Camera","uri":"/godot_recipes/4.x/2d/multi_target_camera/index.html"},{"content":"Problem You want to make an arcade-style car game, so you’re looking for simplicity over realistic physics. In this recipe, you’ll learn how to make a fun, driveable car using a rolling sphere.\nSolution There are a lot of ways to make a driving game. Different games need different levels of realism. If you’re trying to make a light, arcade-style car, you don’t need all of the features that Godot’s VehicleBody3D node provides, such as supension, independently modeled wheels, etc.\nInstead, we’re going to use a single RigidBody3D sphere to handle the driving physics. The sphere will be invisible, and the car mesh will be placed at the sphere’s location, making it look like it’s the car that’s driving.\nAs you can see in the preview clip above, the result looks remarkably good (and feels great to play!). Read on, and you’ll see that the amount of code required is also surprisingly small.\nInputs For control, we’re going to add four inputs to the Input Map:\naccelerate brake steer_left steer_right You can use keyboard input, game controller, or both. However, we recommend going with the analog stick for better steering.\nNode setup The car is made with two main nodes: a RigidBody3D sphere for the physics, and a MeshInstance3D to display the car body. Here’s the scene layout:\nRigidBody3D (Car) CollisionShape3D (Sphere) CarMesh (Imported model) Here’s how these nodes will interact: pressing “accelerate” will apply a force on the RigidBody3D in the direction the CarMesh is facing, while the turning inputs will rotate the CarMesh. As the ball rolls, it will carry the car mesh along with it (we’ll ignore the ball’s rotation).\nCarMesh Here’s the car model we’ll use:\nNote You can find this and other car models in Kenney’s “Car Kit”, available here: https://kenney.nl/assets/car-kit. Download the whole kit; you can use any of them that you choose. Note that this kit includes the models in multiple formats - you won’t need all of them for your project. GLTF is the recommended format for use with Godot.\nIf you use the GLTF models, you shouldn’t have adjust anything in the import settings.\nHere’s what the node tree looks like when importing the “suv” model:\nNote that the wheels \u0026 body are separate meshes. This will make it easy to add some visual appeal - like turning the wheels when steering.\nBall Add a sphere shape to the CollisionShape3D. We’re using a radius of 1 here, but you’ll want to experiment with the size of the ball to get different driving behaviors.\nHere’s how to adjust the settings on the body:\nAngular Damp: 10 - this property will have a huge effect on the driving feel. A higher value will bring the car to a stop much faster. Gravity Scale: 5 - Default gravity in Godot (9.8) feels a bit floaty, especially when going for an action feel. This will really matter if you plan to have jumps, hills, etc. in your world. You can set this globally in the Project Settings instead, if you prefer. Physics Material/Bounce: 0.1 - Playing around with this value can be a lot of fun. Be careful going above 0.5, though! For the demo, we’ve also added a spherical mesh to the collision shape for debugging purposes. You don’t need this, but it helps when troubleshooting to have a visual of the ball rolling.\nRayCast Finally, add a RayCast3D node as a child of the CarMesh. Set its Target Position to (0, -1, 0).\nWe’re going to use this for ground detection. When the car’s in the air, steering and acceleration won’t work. We can also use it to align the car mesh to a slope (if your game’s track isn’t flat).\nNow we’re ready to start coding.\nScript We’ll begin the script with some node references we’ll need:\nextends RigidBody3D @onready var car_mesh = $CarMesh @onready var body_mesh = $CarMesh/suv2 @onready var ground_ray = $CarMesh/RayCast3D @onready var right_wheel = $CarMesh/suv2/wheel_frontRight @onready var left_wheel = $CarMesh/suv2/wheel_frontLeft Next, some variables configuring the car’s behavior. See the comments describing each one’s purpose.\n# Where to place the car mesh relative to the sphere var sphere_offset = Vector3.DOWN # Engine power var acceleration = 35.0 # Turn amount, in degrees var steering = 18.0 # How quickly the car turns var turn_speed = 4.0 # Below this speed, the car doesn't turn var turn_stop_limit = 0.75 # Variables for input values var speed_input = 0 var turn_input = 0 You can @export these if you’d like to adjust them from the Inspector.\nIn _physics_process() we add a force to the body based on the direction the car is pointing, as well as keeping the car mesh positioned at the ball’s position:\nfunc _physics_process(delta): car_mesh.position = position + sphere_offset if ground_ray.is_colliding(): apply_central_force(-car_mesh.global_transform.basis.z * speed_input) The next step is to get the inputs, but we’ll also check if the ray is colliding with the ground first:\nfunc _process(delta): if not ground_ray.is_colliding(): return speed_input = Input.get_axis(\"brake\", \"accelerate\") * acceleration turn_input = Input.get_axis(\"steer_right\", \"steer_left\") * deg_to_rad(steering) right_wheel.rotation.y = turn_input left_wheel.rotation.y = turn_input Tip At this point, you can try it out. You should be able to accelerate forward and back (but not steer yet).\nNext, still in the _process() function, we’ll rotate the car mesh based on the rotation input. We’ll use slerp() (spherical linear interpolation) to do this smoothly:\n# rotate car mesh if linear_velocity.length() \u003e turn_stop_limit: var new_basis = car_mesh.global_transform.basis.rotated(car_mesh.global_transform.basis.y, turn_input) car_mesh.global_transform.basis = car_mesh.global_transform.basis.slerp(new_basis, turn_speed * delta) car_mesh.global_transform = car_mesh.global_transform.orthonormalized() Warning Because of floating point imprecision, repeatedly rotating a transform will eventually cause it to become distorted. The scale can drift or the axes can become no-perpendicular. In any script where you’re regularly rotating a transform, it’s a good idea to use orthonormalized() to correct any error before it accumulates.\nYou should try playing again at this point. You’ll be able to control the car and drive around, and everything works pretty much as expected. However, there are a few more things to add that will improve the “feel” of the driving.\nFinal touches 1. Align with slopes FIX THIS\nIf you’ve tried driving on a slope, you’ve seen that the car mesh doesn’t tilt at all, it always remains level. That looks unnatural, so let’s use the process described in KinematicBody: Align with Surface to fix that.\nAdd this code after rotating the mesh in _process():\nif ground_ray.is_colliding(): var n = ground_ray.get_collision_normal() var xform = align_with_y(car_mesh.global_transform, n) car_mesh.global_transform = car_mesh.global_transform.interpolate_with(xform, 10.0 * delta) And the align function (notice how we’re using orthonormalized() again?):\nfunc align_with_y(xform, new_y): xform.basis.y = new_y xform.basis.x = -xform.basis.z.cross(new_y) xform.basis = xform.basis.orthonormalized() return xform.orthonormalized() 2. Turn the wheels It looks nice if the front wheels turn when you steer. Add some references to the front wheel meshes at the top of the script:\n@onready var right_wheel = $CarMesh/suv2/wheel_frontRight @onready var left_wheel = $CarMesh/suv2/wheel_frontLeft And right after getting input, add the following:\n# rotate wheels for effect right_wheel.rotation.y = rotate_input left_wheel.rotation.y = rotate_input 3. Tilt the body This one adds lots of visual appeal. We’re going to tilt the car’s body based on the speed of the turn. Add a variable at the top of the script:\nvar body_tilt = 35 The smaller this number, the more extreme the tilt effect will be. Between 35 and 40 works well for the SUV model.\nNow add the following right after rotating the car mesh (in the if statement):\n# tilt body for effect var t = -rotate_input * ball.linear_velocity.length() / body_tilt body_mesh.rotation.z = lerp(body_mesh.rotation.z, t, 10 * delta) Observe the difference:\nCredits The demo project seen here uses the following open-source/creative commons assets:\nCars: Kenney Car Kit by Kenney Track: Modular Racekart Track by Keith at Fertile Soil Productions Download This Project Download the project code here: https://github.com/godotrecipes/3d_car_sphere\nRelated recipes Input Actions ","description":"","tags":null,"title":"Arcade-style Car","uri":"/godot_recipes/4.x/3d/3d_sphere_car/index.html"},{"content":"Problem You want to use a RigidBody2D to create a semi-realistic spaceship, a la Asteroids.\nSolution Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc, and we’ll refer to it as we work through this example.\nFor this example, we’ll use the following node setup:\nRigidBody2D (Ship) Sprite2D CollisionShape2D Sprite orientation Don’t forget to orient your sprite correctly. An object that is not rotated should be pointing along the +X axis, i.e. to the right. If your sprite’s art is drawn facing in another direction, rotate the Sprite2D (not the parent body) to align it correctly.\nWe’ll use the following inputs in the Input Map:\nInput Key thrust w or ↑ rotate_right d or → rotate_left a or ← Add a script to the body, and let’s define some variables:\nextends RigidBody2D @export var engine_power = 800 @export var spin_power = 10000 var thrust = Vector2.ZERO var rotation_dir = 0 The first two variables are how we’ll control the ship’s “handling”. engine_power is going to affect acceleration and top speed. spin_power controls how fast the ship rotates.\nthrust and rotation_dir are going to be set by pressing the inputs. Let’s do that next:\nfunc get_input(): thrust = Vector2.ZERO if Input.is_action_pressed(\"thrust\"): thrust = transform.x * engine_power rotation_dir = Input.get_axis(\"rotate_left\", \"rotate_right\") If we’re pressing the \"thrust\" input, we’ll set the thrust vector to the ship’s forward direction, while rotation_dir will be +/-1 based on the rotate inputs.\nWe can start flying by applying those values in _physics_process():\nfunc _physics_process(_delta): get_input() constant_force = thrust constant_torque = rotation_dir * spin_power It works, but you’ll notice that it’s very hard to control. The rotation is too fast, and it accelerates to a high speed before going offscreen. This is where we want to break from “real” space physics. In space, there’s no friction, but our Asteroids-style ship will be a lot easier to control if it coasted to a stop when we’re not thrusting. We can control this with damping.\nIn the RigidBody2D properties, you’ll find Linear/Damp and Angular/Damp. Set these to 1 and 2 respectively, and they’ll slow the movement/rotation as well as causing them to stop.\nFeel free to experiment with these values and how they interact with the engine_power and spin_power\nScreen wrapping Wrapping around the screen is really teleportation: when the ship goes off the right side of the screen, you teleport it to the left side. However, if you just tried to change the position, you’d find that it instantly snapped back. This is because the physics engine is trying to control the position as well.\nThe solution to this is to use the _integrate_forces() callback of the rigid body. In this function, you can safely update the physics properties of the object without conflicting with what the physics engine is doing.\nLet’s get the screensize at the top of the script:\n@onready var screensize = get_viewport_rect().size Then add the new function:\nfunc _integrate_forces(state): var xform = state.transform xform.origin.x = wrapf(xform.origin.x, 0, screensize.x) xform.origin.y = wrapf(xform.origin.y, 0, screensize.y) state.transform = xform As you can see, the _integrate_forces() function includes a parameter called state. This object is the PhysicsDirectBodyState2D of our body. It contains all of the current physics properties such as the forces, velocity, position, etc.\nFrom the state, we grab the current transform, modify it to wrap around the screen using wrapf(), and then set it back to the current state.\nHere’s how it looks:\nWarping Let’s look at one more example of using _integrate_forces() to alter the body’s state without issues. Let’s add a “warp” mechanic - when the player presses the \"warp\" input, the ship will teleport to a random spot on the screen.\nFirst, we’ll add a new variable for this:\nvar teleport_pos = null Then, in get_input(), we’ll set a random position:\nif Input.is_action_just_pressed(\"warp\"): teleport_pos = Vector2(randf_range(0, screensize.x), randf_range(0, screensize.y)) Finally, in _integrate_forces(), if there’s a teleport_position set, we’ll use it and then clear it:\nif teleport_pos: physics_state.transform.origin = teleport_pos teleport_pos = null Download This Project Download the project’s example code here: https://github.com/godotrecipes/asteroids_physics\n","description":"","tags":null,"title":"Asteroids-style Physics (using RigidBody2D)","uri":"/godot_recipes/4.x/physics/asteroids_physics/index.html"},{"content":"Problem You want to move a 3D object to a clicked position.\nSolution We’ll start with a flat plane for our world. Our actor will move on this plane.\nThe actor for this demo is a triangular prism mesh:\nHere is the code for the movement. If given a target, the object will turn and move toward it.\nextends CharacterBody3D @export var speed = 5 @export var gravity = -5 var target = Vector3.ZERO func _physics_process(delta): velocity.y += gravity * delta if target: look_at(target, Vector3.UP) rotation.x = 0 velocity = -transform.basis.z * speed if transform.origin.distance_to(target) \u003c .5: target = Vector3.ZERO velocity = Vector3.ZERO move_and_slide() We’ve also added a MeshInstance3D called “Marker” to the scene. This will be moved to indicate the clicked position.\nMouse -\u003e 3D Now we need a way to map mouse position into our 3D world. If you imagine the screen as a window into the 3D world, the mouse is trapped on the glass. To select something in 3D, we must project a ray from our eye (the camera), through the mouse’s position and into the world.\nWhile this can be done manually using the Camera3D’s project_ray methods, we can take advantage of the fact that CollisionObject3D nodes do this automatically. All we need to do is connect our StaticBody3D ground’s input_event signal:\nfunc _on_StaticBody_input_event(camera, event, click_position, click_normal, shape_idx): if event is InputEventMouseButton and event.pressed: $Marker.transform.origin = click_position $Player.target = click_position We set the position of the marker and the Player’s target to the clicked position:\nWrapping up You can use this technique to detect clicks on any objects in your 3D world.\n","description":"","tags":null,"title":"Click to move","uri":"/godot_recipes/4.x/3d/click_to_move/index.html"},{"content":"Problem Your game needs a “level select” menu, where the user can choose from a grid of options.\nSolution As shown in the example above, we’ll make a scrolling grid of level “boxes” that the player can choose from. Let’s start with the individual level boxes:\n1: Level box Here’s the node setup:\nLevelBox: PanelContainer Label MarginContainer TextureRect The TextureRect is for displaying the lock icon, and the Label for displaying the level number. When one is showing, the other is hidden.\nYou can style these as you like, here’s an example:\nMake sure to set the LevelBox’s Custom Minimum Size in the Inspector. We’re using (110, 110) in the example, but it depends on what size layout you’re going for.\nNow add a script and connect the gui_input signal.\n@tool extends PanelContainer signal level_selected @export var locked = true: set = set_locked @export var level_num = 1: set = set_level @onready var lock = $MarginContainer/Lock @onready var label = $Label func set_locked(value): locked = value if not is_inside_tree(): await ready lock.visible = value label.visible = not value func set_level(value): level_num = value if not is_inside_tree(): await ready label.text = str(level_num) func _on_gui_input(event): if locked: return if event is InputEventMouseButton and event.pressed: level_selected.emit(level_num) print(\"Clicked level \", level_num) We’re using @tool here so that we can make changes to the properties in the inspector and see them right away, without running the scene. Go ahead and try clicking the Locked property and verify that you see the lock appear/disappear.\nSince we don’t have actual levels to load in this project, the print() statement can help test that the click is being detected.\n2: Grid Once you have the box scene completed, add a new scene with a GridContainer. Add any number of LevelBox instances under it, making sure to set the Columns value. Here’s one with 6 columns:\nIn this example Theme Overrides/Constants/H Separation and V Separation are set to 10.\nSave this scene as LevelGrid. In the menu, we’ll use multiple instances to display the desired number of levels.\n3: Menu screen Now we can put together the final menu.\nHere’s the basic layout we’re going for:\nWe’ll create it with these nodes:\nLevelMenu: MarginContainer VBoxContainer Title: Label HBoxContainer BackButton: TextureButton ClipControl: Control NextButton: TextureButton Adjust the node properties:\nLevelMenu Theme Overrides/Constants/Margins: 20 VBoxContainer Theme Overrides/Constants/Separation: 50 Title Style the font however you like BackButton / NextButton Ignore Texture Size: On Stretch Mode: Keep Centered Layout/Container Sizing/Horizontal/Expand: On ClipControl Layout/Clip Contents: On Layout/Custom Minimum Size: (710, 350) (size of the LevelGrid) The ClipControl node is where the grid goes. Enabling Clip Contents means that if the contents are larger than the control, they’ll be cropped. That will allow us to make a horizontally scrolling set of grids. Add an HBoxContainer called GridBox to ClipControl, and instance 3 (or more) LevelGrids inside it.\nMake sure to set Theme Overrides/Constants/Separation to 0.\nYour layout should look something like this (we’ve disabled Clip Contents in order to show what’s happening):\nWith Clip Content, the three grids are all there, but the ClipControl only shows one at a time.\nNow, to scroll the menu, we need to shift the GridBox by 710 pixels to the left/right.\n110 (width of each LevelBox) * 6 (grid columns) + 10 (grid spacing) * 5 == 710 Info You may be wondering why we’re not using a ScrollContainer here. You certainly can, but we don’t want continuous scrolling, and we don’t want to see a scrollbar.\nAdd a script to the LevelMenu and connect the pressed signals of the two buttons.\nextends MarginContainer var num_grids = 1 var current_grid = 1 var grid_width = 710 @onready var gridbox = $VBoxContainer/HBoxContainer/ClipControl/GridBox func _ready(): # Number all the level boxes and unlock them # Replace with your game's level/unlocks/etc. # You can also connect the \"level_selected\" signals here num_grids = gridbox.get_child_count() for grid in gridbox.get_children(): for box in grid.get_children(): var num = box.get_position_in_parent() + 1 + 18 * grid.get_position_in_parent() box.level_num = num box.locked = false func _on_BackButton_pressed(): if current_grid \u003e 1: current_grid -= 1 gridbox.rect_position.x += grid_width func _on_NextButton_pressed(): if current_grid \u003c num_grids: current_grid += 1 gridbox.rect_position.x -= grid_width When you run the scene, try clicking the “Next” and “Back” buttons and verify that it’s scrolling as expected. Clicking the individual level boxes should print to the console.\nDownload the example project to see the whole thing in action, including some tweens for the scrolling action (because tweens make everything better).\nDownload This Project Download the project code here: https://github.com/godotrecipes/ui_level_select\n","description":"","tags":null,"title":"Level Select Menu","uri":"/godot_recipes/4.x/ui/level_select/index.html"},{"content":"Problem You want a minimap or radar-style UI item showing the locations of objects outside of the player’s view.\nSolution Here’s an example of what we are going for: Project setup To illustrate this feature, we’ll start with a simplified top-down game using the Autotile recipe and a player based on the Top-down character recipe. See the linked recipes for details on how these parts work.\nNote The art in this project comes from kenney.nl, which you can download here: Minimap Assets.\nOur main scene setup looks like this:\nThe CanvasLayer node is there to hold our UI, including the minimap/radar we’re making in this recipe.\nUI Layout The first step will be to create the layout for the minimap. In order to work with whatever other UI elements exist in the game, it must resize smoothly, and integrate well with a container-based layout.\nAdd a MarginContainer first. Set its Theme Overrides/Constants all to 5. This control will hold the rest of the nodes and ensure it doesn’t bleed over into any other elements. Name it “Minimap” and save the scene.\nNext, add a NinePatchRect node. This node is similar to a TextureRect but handles resizing differently by not stretching the corners/edges. Drop the panel_woodDetail_blank.png image from the asset folder into the Texture property. This is a 128x128 image and if we scale the root MarginContainer, the image becomes stretched and ugly:\nUsing the NinePatchRects’s properties, we can ensure that the frame remains the same size when stretched. You can define these properties graphically in the “TextureRegion” panel, but it’s sometimes easier to enter the values directly. Set all four properties in the Patch Margin section to 64 and change the node’s name to “Frame”.\nNow observe what happens when we change the size:\nNext, we’d like to fill in the inner part of the frame with the grid pattern pattern_blueprintPaper.png:\nHowever, we need it to tile automatically no matter what size we make the frame. Also, since this grid area is where our minimap markers will appear, we don’t want the grid extending past the edges of the frame.\nAs a child of the MiniMap (and a sibling of the Frame), add another MarginContainer. Set all four margin properties in Theme Overrides/Constants to 20. As a child of this node, add a TextureRect and assign its Texture to the above image. Set its Stretch Mode to “Tile”. Name this node “Grid”.\nTry changing the size of your root node to see the effect:\nFor now, let’s leave the minimap’s size at (200, 200) - you can check the root node’s Size property in the Layout section to confirm.\nAt this point, your scene tree should look like the following:\nMap Markers As a child of Grid, add a Sprite2D node named “PlayerMarker” and give it the minimapIcon_arrowA.png texture. Note the sprite’s Transform/Position property: (0, 0), which places it exactly in the top-left corner of the Grid:\nIf our Grid size is currently (150, 150) (you can check this in its Size property), then its center will be (75, 75). Put the PlayerMarker’s Position there:\nDon’t worry, we’ll automate this later.\nAdd two more Sprite2D nodes: “MobMarker” and “AlertMarker”, using the minimapIcon_jewelRed.png and minimapIcon_exclamationYellow.png textures.\nThese will represent two different types of objects in the game world. Click the “Toggle Visibility” button next to each so that they won’t appear by default.\nScripting the map markers At this point, we have some decisions to make. How we approach populating the minimap with the objects in the world has a lot to do with how the game is set up. Since this is a very minimal demonstration project, we’re going keep the process simple. In a larger game, you may need to use a more robust approach.\nFor this demo, we have two game objects: a Mob, which wanders around the map randomly, and a Crate, which the player can pick up. Many of these are scattered around the main scene. Each will need to be represented by one of the map markers we made.\nAdd each item that you want to appear on the minimap to a group named “minimap_objects”. In each object’s script, assign it a minimap_icon property:\n# In the mob's script: var minimap_icon = \"mob\" # In the crate's script: var minimap_icon = \"alert\" Now we can begin adding a script to the Minimap. First, a player reference that can be assigned in the Inspector when the minimap is added to the main scene and a zoom property to calibrate the scale - how far the minimap can “see”. We also have some @onready variables to make it more convenient to access the nodes we need.\nextends MarginContainer class_name Minimap @export var player: Player @export var zoom = 1.5 @onready var grid = $MarginContainer/Grid @onready var player_marker = $MarginContainer/Grid/PlayerMarker @onready var mob_marker = $MarginContainer/Grid/MobMarker @onready var alert_marker = $MarginContainer/Grid/AlertMarker Next, we’ll use a dictionary to map the minimap_icon tags we gave our units to the corresponding marker:\n@onready var icons = { \"mob\": mob_marker, \"alert\": alert_marker } Then we need a variable to hold the calculated ratio of map size to world size. We’ll use another dictionary to assign active markers to each object. The key will be the object (ie the Mob or Crate instance) and the value the assigned marker.\nvar grid_scale var markers = {} In _ready() we’ll center the player’s marker at the center of the grid. and calculate the scale factor. (Note: you’ll need to connect the resized signal and do both of these things in the callback if you have a dynamically sized UI).\nfunc _ready(): await get_tree().process_frame player_marker.position = grid.size / 2 grid_scale = grid.size / (get_viewport_rect().size * zoom) Nodes in Containers Due to the way that Container nodes handle their children, at _ready() time you won’t get the correct value for the child’s size. For this reason, we need to wait until the next frame to get the Grid’s size.\nWe’ll also create markers for every game object (using the “minimap_objects” group) by duplicating the matching marker node and tying the marker to the object via the markers dictionary:\nvar map_objects = get_tree().get_nodes_in_group(\"minimap_objects\") for item in map_objects: var new_marker = icons[item.minimap_icon].duplicate() grid.add_child(new_marker) new_marker.show() markers[item] = new_marker Now that we have created the markers and linked each one to an object, we can update their positions in _process(). If no player is assigned, we’ll do nothing:\nfunc _process(delta): if !player: return If there is a player, we’ll first rotate the player marker to match the player’s heading. Since our PlayerMarker sprite points upwards rather than along the x axis, we must add 90 degrees:\nplayer_marker.rotation = player.rotation + PI/2 Next, we’ll find each object’s position relative to the player and use that to find the marker’s position (remembering to offset by grid.size / 2 because the control’s origin is in the top left corner).\nfor item in markers: var obj_pos = (item.position - player.position) * grid_scale + grid.size / 2 markers[item].position = obj_pos The problem with this is that markers can be placed outside the grid:\nTo fix this, after calculating obj_pos, but before setting the marker’s position, clamp it to the grid’s rectangle:\nobj_pos = obj_pos.clamp(Vector2.ZERO, grid.size) We can also decide what to do about markers that are “off-screen” - when they would be outside the grid’s rectangle. Choose one of the following options (do this also before using clamp()). The first option is to hide them:\nif grid.get_rect().has_point(obj_pos + grid.position): markers[item].show() else: markers[item].hide() The second is to change their appearance, in this case we’ll make them smaller to show they’re at a farther distance:\nif grid.get_rect().has_point(obj_pos + grid.position): markers[item].scale = Vector2(1, 1) else: markers[item].scale = Vector2(0.75, 0.75) Removing objects If a mob gets killed or a crate picked up, the game will crash because the marker reference is no longer valid. We need a way to ensure markers are removed when the object is. Here’s a quick way to do this in our rudimentary demo setup:\nAdd signal removed to any object that you’ve put in the “minimap_objects” group. Emit this signal when the object is destroyed (or collected), along with a reference to itself so the map can identify it:\nremoved.emit(self) In the _ready() of the main script, connect these signals to the minimap:\nfunc _ready(): for object in get_tree().get_nodes_in_group(\"minimap_objects\"): object.removed.connect(minimap._on_object_removed) Now add the receiving function to the minimap script to free the marker and remove the reference:\nfunc _on_object_removed(object): if object in markers: markers[object].queue_free() markers.erase(object) Adjusting zoom If you’ve stuck with it this far, we have one more feature to add: adjustable zoom level. With this, scrolling the mouse wheel when hovering over the map will zoom its scale in and out.\nFirst, add a setter to the zoom property:\n@export var zoom = 1.5: set = set_zoom func set_zoom(value): zoom = clamp(value, 0.5, 5) grid_scale = grid.size / (get_viewport_rect().size * zoom) On the MiniMap node, connect the _gui_input signal in the Inspector so we can process the scroll wheel events:\nfunc _on_gui_input(event): if event is InputEventMouseButton and event.pressed: if event.button_index == MOUSE_BUTTON_WHEEL_UP: zoom += 0.1 if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: zoom -= 0.1 That’s it - observe the effect of scrolling in and out:\nWrapping up While this is a pretty big recipe, I’ve tried to make it flexible enough for you to incorporate into whatever project you’re working on.\nSome other things you might want to add:\nMore marker types for different game objects. Adding new units when they’re spawned (hint: use a signal just like we did for removing units). Clicking on a marker to get info about it. Use a picture of your map as the minimap background instead of the grid. Download This Project Download the project’s example code here: https://github.com/godotrecipes/minimap\nRelated recipes Top-down character ","description":"","tags":null,"title":"Minimap/radar","uri":"/godot_recipes/4.x/ui/minimap/index.html"},{"content":"Problem You want to smoothly rotate a 3D object to point in a new direction.\nSolution When you first encounter this problem, you may find yourself thinking in terms of Euler angles - the three values representing the angles to the x/y/z axes. While Godot will allow you to see the object’s Euler angles in the rotation property, it is not recommended to use them to work in 3D. There are a number of reasons why this the case, such as a problem called “gimbal lock”, where you lose one degree of freedom when one of your rotations reaches 90 degrees.\nInfo If you’re interested in the background behind Euler angles and the problems they introduce, like gimbal lock, here’s a video that explains it well.\nWe can avoid using 3D Euler angles in Godot by using the object’s transform property. This property represents the body’s position and orientation in space. It uses a mathematical construct called a matrix to do this, but you don’t really need to understand the underlying math in order to make use of it.\nlook_at() Let’s say you have a 3D object such as a missile or arrow and you want it to point at its target. You can do this using the Node3D method look_at():\nfunc _process(delta): var target_position = $Target.transform.origin $Arrow.look_at(target_position, Vector3.UP) This code would make our node ($Arrow) always point at the target’s position, no matter how it moves.\nNote that look_at() requires 2 parameters: the target position, and an “up vector”. Imagine an airplane pointing its nose towards a target - there are an infinite number of ways it could be oriented, because the plane could roll about its axis. This second parameter is how you define what you want the final orientation to be.\nSmooth rotation The above code works, but it snaps the rotation instantly to the target. This might be fine if you have a very slow-moving target, but looks unnatural. It would look better if we move smoothly, or “interpolated”, the rotation smoothly between the starting orientation and the ending.\nGodot has us covered here too. Rather than look_at(), we can use the Transform object’s looking_at() method, which doesn’t rotate the node, but returns the transform that would be looking at the target. Combine this with the interpolate_with() method, which returns an intermediate transform between a current one and a target one, and we can smoothly transition between the current orientation and our desired one.\nvar speed = 5 func _process(delta): var target_position = $Target.transform.origin var new_transform = $Arrow.transform.looking_at(target_position, Vector3.UP) $Arrow.transform = $Arrow.transform.interpolate_with(new_transform, speed * delta) Note that since interpolate_with() operates on the transform, it can be used to interpolate both rotation and position of an object.\nWrapping up That’s it! Use this handy method to rotate your 3D objects, and stop thinking about angles!\nRelated recipes ","description":"","tags":null,"title":"Smooth rotation","uri":"/godot_recipes/4.x/3d/rotate_interpolate/index.html"},{"content":"Problem You’d like to understand what is meant by dot product and cross product.\nSolution In this recipe we’ll introduce the concept of vector dot product and cross product and how they might be used.\nDot product Dot product is an operation on two vectors that returns a scalar. It is often visualized as the projection of vector A onto vector B:\nThis is the formula for calculating the dot product:\nWhere θ is the angle between the two vectors and ||A|| is the magnitude of A.\nThis is very useful when both vectors are normalized (i.e. their magnitudes are 1), then the formula simplifies to:\nThis shows that the dot product is directly related to the angle between the two vectors. Since cos(0) == 1 and cos(180) == -1, the result of the dot product can tell you how closely aligned two vectors are:\nSee below for how we can apply this fact in a practical example.\nCross product The cross product of two vectors is a third vector that is perpendicular to both of them. Its magnitude is related to their magnitudes and the angle between them.\nOnce again, if we’re using normalized vectors, the result is simplified: it will be directly related to the angle and its magnitude will range from -1 to 1.\nNote Since the cross product is perpendicular to both vectors, we would need to be working in 3D. In most 2D frameworks, including Godot, the 2D Vector2.cross() method returns a scalar value representing the result’s magnitude.\nPractical applications Consider this animation, showing how the results of Vector2.dot() and Vector2.cross() change in relation to the changing angle:\nThis demonstrates two common applications of these methods. If the red vector is our object’s forward direction, and the green shows the direction towards another object:\nDot product: Using the result, we can tell if the object is in front of (\u003e 0) or behind (\u003c 0) us. Cross product: Using the result, we can tell if the object is to the left (\u003e 0) or right (\u003c 0). ","description":"","tags":null,"title":"Vectors: Using Dot and Cross Product","uri":"/godot_recipes/4.x/math/dot_cross_product/index.html"},{"content":"Problem You need your character body to align with the surface or terrain.\nSolution This recipe builds on the basic CharacterBody3D controller described in the CharacterBody3D: Movement recipe, so read that one first.\nFirst, we’ve added some terrain to the scene. You can download the terrain from here: https://fertile-soil-productions.itch.io/modular-terrain-pack. This is low-poly terrain, but you can use or make any terrain you like for this technique.\nAs you can see, the movement still works with the terrain, but the tank seems to “float” above the slopes because it doesn’t change its orientation.\nInstead, we need to rotate the tank so that its treads are aligned with the ground, even as the slope changes. To do that, we need to know which way is up.\nSurface normals A surface normal is a unit vector (“normal vector” and “unit vector” mean the same thing) perpendicular to a surface. It shows which way the surface is facing. In the case of a mesh, every surface has a normal pointing outward.\nIn Godot, when a body collides, you can get the normal of the collision. This will be the colliding body’s normal at the point of contact.\nOnce we have the surface normal, we need to align the tank’s Y axis with it. Note that we can’t use Transform3D.looking_at(), because that will align the -Z (forward) axis with the normal.\nTo do this, we’ll use the following function:\nfunc align_with_y(xform, new_y): xform.basis.y = new_y xform.basis.x = -xform.basis.z.cross(new_y) xform.basis = xform.basis.orthonormalized() return xform Given a transform and a new Y direction vector, this function returns the transform rotated so that its basis.y is aligned with the given normal.\nNote If you’re unfamiliar with the cross product or other vector math, there’s a great vector math intro in the Godot Docs.\nWe can update the tank’s movement code to call this function when it collides with a surface:\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) move_and_slide() for i in get_slide_count(): var c = get_slide_collision(i) global_transform = align_with_y(global_transform, c.get_normal()) This doesn’t work quite as expected:\nThe problem is that the tank’s collision shape could be colliding with more than one of the terrain’s faces. Also, move_and_slide() can result in more than one collision in a single frame. This leads to the jittering. We need to choose one face and stick with it.\nAdd a RayCast3D child to the tank and set its Target Position to (0, -1, 0).\nSince this raycast is pointing down from the exact center of the tank, we’ll align with the individual surface that it collides with - the one directly beneath the tank.\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) move_and_slide(v) var n = $RayCast3D.get_collision_normal() global_transform = align_with_y(global_transform, n) This is much better, but because we are instantly snapping to the new alignment every time the tank crosses an edge, it still looks a little jarring:\nWe can solve this last problem by interpolating to the new transform rather than snapping immediately to it.\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) velocity = move_and_slide_with_snap(velocity, Vector3.DOWN*2, Vector3.UP, true) var n = $RayCast.get_collision_normal() var xform = align_with_y(global_transform, n) global_transform = global_transform.interpolate_with(xform, 12 * delta) The result is much smoother and more pleasing:\nYou can get even better results with two raycasts - one at the front and one at the back. Get the average normal from them:\nvar n = ($FrontRay.get_collision_normal() + $RearRay.get_collision_normal()) / 2.0 Feel free to experiment with the interpolation amount. We found 12 to work well in this situation, but you might find a higher or lower value works better for your setup.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples\nRelated recipes CharacterBody3D: Movement Math: Interpolation Math: Transforms ","description":"","tags":null,"title":"CharacterBody3D: Align with Surface","uri":"/godot_recipes/4.x/3d/3d_align_surface/index.html"},{"content":" Games Demo games and tutorials.\nUpdating to Godot 4.0 We’re working on new content for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: Your First 2D Game ","description":"","tags":null,"title":"Game Tutorials","uri":"/godot_recipes/4.x/games/index.html"},{"content":"If you’ve been following along, you’ve learned a lot of the fundamentals of building games in Godot. We’re going to end the tutorial here, since we’ve completed the basic game.\nThe secret to learning effectively Here’s my big secret for getting the most out of tutorials like this and others you may find online. At the end, once you’ve finished building the project, immediately delete it and start over. This time, try and re-create it without looking at the tutorial. If you get stuck, look at just that part, then close it again.\nIt may sound repetitive, but that is how we learn: by doing things repeatedly. If you follow this tip, you’ll be amazed at how quickly you level up your gamedev skills.\nAdding to the game If you’re feeling comfortable with the techniques used to make this game, then you’re ready to branch out. Try adding a single new feature to this game.\nIf you’re stuck coming up with an idea, here are some suggestions:\nAdditional enemy types - there is art for other enemies in the art pack. How do they move and shoot?\nWaves - make more enemies spawn every time you clear the screen\nBoss enemies - what if a big enemy appears?\nBoosts - powerups could appear for the player to collect. There’s some art for those too.\nShield recharge - collect these to power up the shield Weapon upgrades - shoot more bullets, patterns, etc. Sound and music - give everything a lot more personality with some sound effects and background music.\nLearning more Ready for more? Here are some suggestions for your next learning adventure:\nGodot 101: Getting started in 3D - if you’re interested in making things in 3D, check out this introduction to Godot’s 3D features.\nCheck out the rest of the content on this website. There are lots of examples, tutorials, and code snippets to help you learn how to make your dream game.\nDownload This Project on GitHub Download the project code here:\nhttps://github.com/godotrecipes/8_direction_animation\n","description":"","tags":null,"title":"Wrapping up","uri":"/godot_recipes/4.x/games/first_2d/first_2d_end/index.html"},{"content":" Godot Recipes Godot’s nodes are your ingredients. What can you cook up?\nOn this site you’ll find a collection of solutions and examples to help you make whatever game system you need.\nGodot 4.0 Godot 4.0 has been released!\nGodot 4.0 is the latest stable release version of the engine.\nThere is a limited amount of learning material available, so if you’re looking to make a game or learn the engine, we recommend you stick with 3.x for now. Don’t worry - what you learn will still apply when you’re ready to move to the newer version!\nThis site has lots of learning material for Godot 3 - but not all of it has been updated for version 4 yet. You can click the ribbon in the top-right to toggle the Godot Recipes version, or click the button below:\nGodot 3 Recipes Are you ready to learn game development? Whether it’s as a hobby or working towards your dream career, there’s never been a better time to get started. Modern programming languages and tools have made it easier than ever to build high-quality games and distribute them to the world. One of these tools is the Godot game engine. For beginners, it offers a friendly way to learn gamedev techniques. For experienced developers, it’s a powerful, customizable and open tool for bringing your visions to life.\nOn this site you’ll find a gentle introduction to the Godot game engine, as well as a wide variety of gamedev tips and techniques. Feel free to browse the categories in the sidebar and see what catches your interest.\nIf you’re new to Godot, start here: What is Godot?.\nHow to use this site Beginners If you’re new to game development, start with the “Godot 101: Basics” section. There you’ll find an introduction to the Godot application, and a step-by-step guide to creating your first project. There is a lot of material to absorb here. Don’t feel discouraged if you feel you don’t get it at first. Repetition is the key to learning complex topics; the more you work with Godot’s features, the more familiar and easy they will start to feel.\nInfo It’s assumed that you have at least some general programming experience. If you’re completely new to programming, click here for tips on how to get started.\nExperienced Developers If you’re an experienced developer and/or you’re familiar with other modern game engine(s), feel free to explore the menu on the left. You’ll find a number of useful guides and tutorials to show you how to do things the “Godot Way”. Code samples and example projects are available for all articles.\n","description":"","tags":null,"title":"Home","uri":"/godot_recipes/4.x/index.html"},{"content":"","description":"","tags":null,"title":"Categories","uri":"/godot_recipes/4.x/categories/index.html"},{"content":"RayCast2D Raycasting is a common technique in game development. “Casting a ray” means extending a line from a point until it collides with something or reaches its limit.\nNode properties Add a RayCast2D node and take a look at the Inspector:\nHere are the main properties you’ll need to understand:\nEnabled Turn this off to disabled the raycast work.\nExclude Parent This property causes the ray to ignore collisions with the parent object. Enabled by default.\nTarget Position This is the destination point of the ray. Note: This is in local coordinates.\nAlso, take note of the Collide With section. By default the ray will only detect bodies, so you’ll need to go here if you want to detect areas as well or instead.\nUseful functions You can see the full list of the node’s functions in the API Documentation. Here are the some of the most useful ones:\nis_colliding() Boolean function, lets you know if the ray is colliding with something.\nget_collision_point() If the ray is colliding, this will return the position of the collision (in global coordinates).\nget_collider() If the ray is colliding, this function will return a reference to the colliding object.\nget_collision_normal() Another useful piece of information, this is the normal of the collided object at the point of collision.\nExample uses There are many uses for raycasts: visibility (can A see B, or is there an obstacle between?), proximity (am I close to a wall/ground/obstacle?), etc. Here are a couple of practical examples in use:\n1. Shooting Fast-moving projectiles often have the problem of “tunneling” through obstacles - they are moving too fast for the collision to be detected in a single frame. As an alternative, you can use a Raycast2D to represent the path (or a laser, etc.).\nHere’s a player sprite with a raycast attached to the end of the gun. The target_position is set to (250, 0).\nWhen the player shoots, you check to see if the ray is colliding with something:\nfunc _input(event): if event.is_action_pressed(\"shoot\"): if $RayCast2D.is_colliding(): print($RayCast2D.get_collider().name) 2. Edge detection Consider a platformer enemy that walks on platforms, but you don’t want it to fall off the edges. Add two downward-pointing raycasts to the mob like so:\nIn the mob’s script, check for when the ray stops colliding. That means you’ve found the edge and should turn around:\nfunc _physics_process(delta): velocity.y += gravity * delta if not $RayRight.is_colliding(): dir = -1 if not $RayLeft.is_colliding(): dir = 1 velocity.x = dir * speed $AnimatedSprite.flip_h = velocity.x \u003e 0 velocity = move_and_slide(velocity, Vector2.UP) Here’s what it looks like in action:\n","description":"","tags":null,"title":"RayCast2D","uri":"/godot_recipes/4.x/kyn/raycast2d/index.html"},{"content":"","description":"","tags":null,"title":"Tags","uri":"/godot_recipes/4.x/tags/index.html"}] \ No newline at end of file +[{"content":" Godot 101 Your introduction to the Godot game engine. If you’ve never used a game engine before, or if you’re just new to Godot, this is the place to start.\nIn this section: Getting Started Introduction to GDScript Intro to 3D See also: Game Tutorials/Your First 2D Game ","description":"","tags":null,"title":"Godot 101","uri":"/godot_recipes/4.x/g101/index.html"},{"content":"Problem You’ve tried adding an AudioStreamPlayer to your mob/coin/etc. to play when the object dies or is collected. But the problem is that when you remove the object, the audio player goes with it, chopping off the sound. You need an easier way to manage playing audio.\nSolution We’ll solve this problem with a node that is available from anywhere in the SceneTree. This node manages a set of AudioStreamPlayer nodes and a queue of sound streams to play.\nCreate a new script in the script editor.\nextends Node var num_players = 8 var bus = \"master\" var available = [] # The available players. var queue = [] # The queue of sounds to play. func _ready(): # Create the pool of AudioStreamPlayer nodes. for i in num_players: var p = AudioStreamPlayer.new() add_child(p) available.append(p) p.finished.connect(_on_stream_finished.bind(p)) p.bus = bus func _on_stream_finished(stream): # When finished playing a stream, make the player available again. available.append(stream) func play(sound_path): queue.append(sound_path) func _process(delta): # Play a queued sound if any players are available. if not queue.empty() and not available.empty(): available[0].stream = load(queue.pop_front()) available[0].play() available.pop_front() Set this script as an autoload in Project Settings. Give it an easily recognizable name, such as “AudioStreamManager”.\nAnywhere in your project that you want to play a sound, use:\nAudioStreamManager.play(\"res://path/to/sound\") Note This audio manager is adapted with thanks from [SFXPlayer by TheDuriel] (https://github.com/TheDuriel/DurielsGodotUtilities).\nExample project Below you can download an example project showing the use of the audio manager node. This project reads a folder full of audio files and generates a grid of buttons. Click the button to play the sound.\nAt the top, you can see the audio manager’s live statistics.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/audio_manager\n","description":"","tags":null,"title":"Audio Manager","uri":"/godot_recipes/4.x/audio/audio_manager/index.html"},{"content":"Problem You want an enemy to chase the player.\nSolution The first step in getting an enemy to chase the player is to determine what direction the enemy needs to move. To get the vector pointing from A to B, you subtract: B - A. Normalize the result and you have a direction vector.\nThis makes the solution quite straightforward. Every frame, set the enemy’s velocity to point in the direction of the player.\nvelocity = (player.position - position).normalized() * speed Godot’s Vector2 object has a built-in helper for this:\nvelocity = position.direction_to(player.position) * speed However, this would allow the enemy to chase the player from any distance, even if it’s far away. To fix this, we can add an Area2D to the enemy, and only chase the player when it’s inside this “detect radius”.\nHere’s some example code:\nextends CharacterBody2D var run_speed = 25 var player = null func _physics_process(delta): velocity = Vector2.ZERO if player: velocity = position.direction_to(player.position) * run_speed move_and_slide() func _on_DetectRadius_body_entered(body): player = body func _on_DetectRadius_body_exited(body): player = null We’ve connected the body_entered and body_exited signals from the Area2D so that the enemy knows whether it’s in range or not.\nNote The above assumes that the player is the only body that will enter/exit, which is usually done by setting the appropriate collision layers/masks.\nThis concept can be extended to other types of games as well. The key is to find the direction vector from the enemy to the player:\nIf, for example, your game is a side-scroller or has other constraints in movement, you can use only the x component of the resulting vector to determine movement.\nLimitations Note that this method results in very simplistic straight-line movement. The enemy will not move around obstacles such as walls, nor will it stop if it gets too close to the player.\nWhat to do when the enemy gets close to the player depends on your game. You could add a second, smaller area that causes the enemy to stop and attack, or you could knockback the player on contact.\nAnother problem is more apparent with fast-moving enemies. As the player moves, the enemies using this technique will change direction instantly. For a more natural-looking movement, you might want to use a steering behavior.\nFor more advanced behaviors, see the other recipes in this chapter.\nRelated recipes Top-down movement Homing missile ","description":"","tags":null,"title":"Chasing the player","uri":"/godot_recipes/4.x/ai/chasing/index.html"},{"content":"Problem You want to detect when an object enters or exits the screen.\nSolution The engine provides a node for this: VisibleOnScreenNotifier2D. Attach this node to your object, and you’ll be able to use its screen_entered and screen_exited signals. *\nExample 1 Consider a projectile that travels in a straight line after it’s fired. If we continue firing, eventually we’ll have a large number of objects for the engine to track, event though they’re offscreen, which can cause lag.\nHere’s the movement code for the projectile:\nextends Area2D var velocity = Vector2(500, 0) func _process(delta): position += velocity * delta To have the projectile automatically deleted when it moves offscreen, add a VisibleOnScreenNotifier2D and connect its screen_exited signal.\nfunc _on_VisibleOnScreenNotifier2D_screen_exited(): queue_free() Example 2 We have an enemy that performs some actions, such as moving along a path or playing an animation. On a large map with many enemies, only a few of them will be onscreen at the same time. We can disable the enemy’s actions while it’s offscreen using VisibleOnScreenNotifier2D.\nPartial code:\nvar active = false func _process(delta): if active: play_animation() move() func _on_VisibleOnScreenNotifier2D_screen_entered(): active = true func _on_VisibleOnScreenNotifier2D_screen_exited(): active = false ","description":"","tags":null,"title":"Entering/Exiting the screen","uri":"/godot_recipes/4.x/2d/enter_exit_screen/index.html"},{"content":"Here you can find the most recently added recipes:\nMultitarget Camera Character to Rigid Body Interaction CharacterBody3D: Align with Surface CharacterBody3D: Movement Arcade-style Car Pathfinding on a 2D Grid Migrating from 3.x Shooting with Raycasts Basic FPS Character RigidBody2D: Drag and Drop 2D Car Steering 3D Healthbars Grid-based Movement Arcade-style 3D Spaceship Interpolated Camera Platform Character ","description":"","tags":null,"title":"Fresh Recipes","uri":"/godot_recipes/4.x/recent/index.html"},{"content":"Overview Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. For example, a Sprite2D node automatically displays an image, but to move it across the screen, you’ll add a script that tells it how fast, in what direction, and so on.\nYou can think of it as the coding version of using the Inspector - GDScript knows all about Godot nodes and how to access them, plus it allows you to change them dynamically.\nGDScript is Godot’s built-in language for scripting and interacting with nodes. The GDScript documentation on the Godot website is a great place to get an overview of the language, and I highly recommend taking the time to read through it.\nIs GDScript Python?\nYou’ll often read comments to the effect that “GDScript is based on Python”. That’s somewhat misleading; GDScript uses a syntax that’s modeled on Python’s, but it’s a distinct language that’s optimized for and integrated into the Godot engine. That said, if you already know some Python, you’ll find GDScript looks very familiar.\nWarning Many tutorials (and Godot in general) assume that you have at least some programming experience already. If you’ve never coded before, you’ll likely find learning Godot to be a challenge. Learning a game engine is a large task on its own; learning to code at the same time means you’re taking on a lot. If you find yourself struggling with the code in this section, you may find that working through an introductory programming lesson (Python is a good option) will help you grasp the basics.\nStructure of a script The first line of any GDScript file must be extends \u003cClass\u003e, where \u003cClass\u003e is some existing built-in or user-defined class. For example, if you’re attaching a script to a CharacterBody2D node, then your script would start with extends CharacterBody2D. This states that your script is taking all the functionality of the built-in CharacterBody2D object and extending it with additional functionality created by you.\nIn the rest of the script, you can define any number of variables (aka “class properties”) and functions (aka “class methods”).\nCreating a script Let’s make our first script. Remember, any node can have a script attached to it.\nOpen the editor and add a Sprite2D node to empty scene. Right-click on the new node, and choose “Attach Script”. You can also click the button next to the search box.\nNext you need to decide where you want the script saved and what to call it. If you’ve named the node, the script will automatically be named to match it (so unless you’ve changed anything this script will likely be called “sprite2d.gd”).\nNow the script editor window opens up, and this is your new, empty sprite script. Godot has automatically included some lines of code, as well as some comments describing what they do.\nextends Sprite2D # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(delta): pass Since the script was added to a Sprite2D, the first line is automatically set to extends Sprite2D. Because this script extends the Sprite2D class, it will be able to access and manipulate all the properties and methods that a Sprite2D node provides.\nProperties and methods Properties and methods are two terms which specifically mean variables and functions that are defined in an object. Programmers tend to use the terms interchangeably.\nAfter that is where you’re going to define all the variables you will use in the script, the “member variables”. You define variables with the ‘var’ keyword - as you can see by the comment examples.\nGo ahead and delete the comments and let’s talk about this next piece.\nNow we see a function called _ready(). In GDScript you define a function with the keyword “func”. The _ready() function is a special one that Godot looks for and runs whenever a node is added to the tree, for example when we hit “Play”.\nLet’s say that when the game starts, we want to make sure the sprite goes to a particular location. In the Inspector, we want to set the Position property. Notice that it’s in the section called “Node2D” - that means this is a property that any Node2D type node will have, not just Sprite2Ds.\nHow do we set the property in code? One way to find the name of the property is by hovering over it in the Inspector.\nGodot has a great built-in help/reference tool. Click on “Classes” at the top of the Script window and search for Node2D and you’ll see a help page showing you all the properties and methods the class has available. Looking down a bit you can see position in the “Member Variables” section - that’s the one we want. It also tells us the property is of the type “Vector2”.\nLet’s go back to the script and use that property:\nfunc _ready(): position = Vector2(100, 150) Notice how the editor is making suggestions as you type. Godot uses vectors for lots of things, and we’ll talk more about them later. For now, let’s type Vector2, and the hint tells us to put two floats for x and y.\nNow we have a script that says “When this sprite starts, set its position to (100, 150)”. We can try this out by pressing the “Play Scene” button.\nLearning tip When first learning to code, beginners often ask “How do you memorize all these commands?” Just like any other skill, it’s not a matter of memorization, it’s about practice. As you use things more, the things you do frequently will “stick” and become automatic. Until then, it’s a great idea to keep the reference docs handy. Use the search function whenever you see something you don’t recognize. If you have multiple monitors, keep a copy of the web docs open on the side for quick reference.\nWrapping up Congratulations on making your first script in GDScript! Before moving on, make sure you understand everything we did in this step. In the next part, we’ll add some more code to move the sprite around the screen.\n","description":"","tags":null,"title":"Getting started","uri":"/godot_recipes/4.x/g101/gdscript/gdscript_01/index.html"},{"content":"Getting Started Have you downloaded Godot yet? You can get it here:\nhttps://godotengine.org\nUpdating to Godot 4.0 We’re working on a new version of Godot 101 for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: What is Godot? The Godot Editor: Finding your way around Nodes: Godot's building blocks ","description":"","tags":null,"title":"Getting Started","uri":"/godot_recipes/4.x/g101/start/index.html"},{"content":"Problem You’ve downloaded (or created) a set of 3D assets, including rigged and animated characters, and you want to import it into Godot.\nSolution For this example, we’ll assume you’ve downloaded the art packs linked in the section description and unzipped them.\nBefore copying the files into your Godot project, notice that there are multiple versions of the assets in different file formats: OBJ, FBX, and GLTF. There are also some extra files such as examples and separate textures in case you want to modify them. We don’t need all of that, and GLTF is the preferred import format for Godot. So make sure you’re only dragging the gltf folder or .gltf files (or .glb, which is the binary version of the same) into your project folder.\nHere, I’ve taken the gltf folder from the “Dungeon” pack and the characters folder from the “Adventurers” pack and dragged them into my project.\nNote There are a lot of files in the Dungeon pack - Godot may take a little time to read them all!\nImporting a Character Select the knight.glb file in the FileSystem tab, then click the Import tab at the top left.\nHere you’ll find some basic import settings, but we can go into more detail. Click Advanced button and you’ll see a new window appear:\nOne the left you’ll see all the data that is contained in the GLTF scene, including textures and animations. Note all the weapon options attached to the character and the extensive list of animations.\nThere’s a preview of the character in the middle, and a set of options on the right side where you can adjust how the selected item is configured.\nSince we will code our player as a CharacterBody3D, we can go ahead and specify that node type here. Click on the Scene Root and on the right set the Root Type to CharacterBody3D.\nAnimations Scroll down to the list of animations. You’ll see that there are many, but while some we’ll only want to play once, such as attacks, others like “Idle” and “Running”, we’d like to be looping. For any animation like this, select the animation name and set the Loop Mode to “Linear”. Do this for all of the “Walking”, “Running”, and “Idle” variations. When you’re done, click the Reimport button at the bottom.\nSetting Loop Automatically If you are making your own characters, you can skip this step by ensuring that your animations’ names end with \"-loop\". For details on this and other import hints, see Import Hints in the Godot documentation.\nRight click knight.glb in the FileSystem and choose New Inherited Scene.\nIn this scene you’ll see all the models and the AnimationPlayer where you can test out the animations.\nImporting World Items Importing objects for the environment will be a similar process. As an example, let’s use one of the dungeon walls. There are a lot of files in the dungeon pack, so type “wall” in the file filter to help find it:\nWe’ll want our dungeon walls to be solid, and it would be painful to manually create a StaticBody3D and collision shape for each one. Fortunately, when importing, Godot can do this for us.\nIn the import window, select the mesh object. On the right side, check the Physics box, and set the Shape Type to “Simple Convex” (feel free to check out the other options too).\nClick Reimport. Now when using this in the game, Godot will automatically create a StaticBody3D with a collision shape to match.\nAutomating Collision Shapes As above, there is an import hint for collision shapes as well. In your Blender project, appending -col (or some other variations) will let the importer know to do this step automatically. See the import hints link for details.\nAutomating Imports While adding import hints is the preferred method when making your own assets, it’s not something you can do when downloading an asset pack like the one we’re using.\nIt is possible to write an import script that can run on every imported node of a particular type. For example, we could automate the creation of the static collision we did above.\nAs an example, the following script will loop through all the nodes of the imported object and create a static collision on each mesh it finds.\n@tool extends EditorScenePostImport func _post_import(scene): iterate(scene) return scene func iterate(node): if node != null: if node is MeshInstance3D: node.create_trimesh_collision() for child in node.get_children(): iterate(child) In the Import tab, you can set this as the Import Script, and when you click Reimport, the collisions will be created.\nWrapping up That concludes the overview of importing 3D assets into Godot.\nSee the section description for examples of working with the 3D assets you’ve imported.\nCompanion Video ","description":"","tags":null,"title":"Importing Assets","uri":"/godot_recipes/4.x/3d/assets/importing_assets/index.html"},{"content":"Linear Interpolation, or its commonly-used abbreviation lerp, is a term that comes up often in game development. If you’ve never come across it before it can seem mysterious and highly-technical, but as you’ll see in this tutorial, it’s actually a straightforward concept with a wide variety of applications in game programming.\nNumeric Interpolation The core formula for linear interpolation is this:\nfunc lerp(a, b, t): return (1 - t) * a + t * b In this formula, a and b represent the two values and t is the amount of interpolation, typically expressed as a value between 0 (which returns a), and 1 (which returns b). The function finds a value the given amount between the two. For example:\nx = lerp(0, 1, 0.75) # x is 0.75 x = lerp(0, 100, 0.5) # x is 50 x = lerp(10, 75, 0.3) # x is 29.5 x = lerp(30, 2, 0.75) # x is 9 It’s called linear interpolation because the path between the two points is a straight line.\nYou can animate a node’s properties with lerp(). For example, if you divide the elapsed time by the desired duration, you’ll get a value between zero and one you can use to alter a property smoothly over time. This script scales a sprite up to five times its starting size while fading it out (using modulate.a) over two seconds:\nextends Sprite2D var time = 0 var duration = 2 # length of the effect func _process(delta): if time \u003c duration: time += delta modulate.a = lerp(1, 0, time / duration) scale = Vector2.ONE * lerp(1, 5, time / duration) Vector interpolation You can also interpolate between vectors. Both Vector2 and Vector3 provide linear_interpolate() methods for this.\nFor example, to find a vector that’s halfway between a Spatial node’s forward and left direction vectors:\nvar forward = -transform.basis.z var left = transform.basis.x var forward_left = forward.linear_interpolate(left, 0.5) The following example moves a Sprite node towards the mouse click position. Each frame the node moves 10% of the way to the target. This results in an “approach” effect, where the object’s speed becomes slower the closer it gets to the target.\nextends Sprite2D var target func _input(event): if event is InputEventMouseButton and event.pressed: target = event.position func _process(delta): if target: position = position.linear_interpolate(target, 0.1) For more advanced applications of interpolation, see Tween.\n","description":"","tags":null,"title":"Interpolation","uri":"/godot_recipes/4.x/math/interpolation/index.html"},{"content":"Problem You need to make a 2D platform-style character.\nSolution New developers are often surprised at how complex a platform character can be to program. Godot provides some built-in tools to assist, but there are as many solutions as there are games. In this tutorial, we won’t be going in-depth with features like double-jumps, crouching, wall-jumps, or animation. Here we’ll discuss the fundamentals of platformer movement. See the rest of the recipes for other solutions.\nTip While it’s possible to use RigidBody2D to make a platform character, we’ll be focusing on CharacterBody2D. Kinematic bodies are well-suited for platformers, where you are less interested in realistic physics than in responsive, arcade feel.\nStart with a CharacterBody2D node, and add a Sprite2D and CollisionShape2D to it.\nAttach the following script to the root node of the character. Note that we’re using input actions we’ve defined in the InputMap: \"walk_right\", \"walk_left\", and \"jump\". See InputActions.\nextends CharacterBody2D @export var speed = 1200 @export var jump_speed = -1800 @export var gravity = 4000 func _physics_process(delta): # Add gravity every frame velocity.y += gravity * delta # Input affects x axis only velocity.x = Input.get_axis(\"walk_left\", \"walk_right\") * speed move_and_slide() # Only allow jumping when on the ground if Input.is_action_just_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed The values used for speed, gravity, and jump_speed depend greatly on the size of your player sprite. The player’s texture in this example is 108x208 pixels. If your sprite is smaller, you’ll want to use smaller values. We also want high values so that everything feels fast and responsive. A low gravity results in a floaty-feeling game while a high value means you’re quickly back on the ground and ready to jump again.\nNote that we’re checking is_on_floor() after using move_and_slide(). The move_and_slide() function sets the value of this method, so it’s important not to check it before, or you’ll be getting the value from the previous frame.\nFriction and acceleration The above code is a great start, and you can use it as the foundation for a wide variety of platform controllers. One problem it has, though, is the instantaneous movement. For a more natural feel, it’s better if the character has to accelerate up to its max speed and that it coasts to a stop when there is no input.\nOne way to add this behavior is to use linear interpolation (“lerp”). When moving, we will lerp between the current speed and the max speed and while stopping we’ll lerp between the current speed and 0. Adjusting the lerp amount will give us a variety of movement styles.\nTip For an overview of linear interpolation, see Gamedev Math: Interpolation.\nextends CharacterBody2D @export var speed = 1200 @export var jump_speed = -1800 @export var gravity = 4000 @export_range(0.0, 1.0) var friction = 0.1 @export_range(0.0 , 1.0) var acceleration = 0.25 func _physics_process(delta): velocity.y += gravity * delta var dir = Input.get_axis(\"walk_left\", \"walk_right\") if dir != 0: velocity.x = lerp(velocity.x, dir * speed, acceleration) else: velocity.x = lerp(velocity.x, 0.0, friction) move_and_slide() if Input.is_action_just_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed Try changing the values for friction and acceleration to see how they affect the game’s feel. An ice level, for example, could use very low values, making it harder to maneuver.\nConclusion This code gives you a starting point for building your own platformer controller. For more advanced platforming features such as wall jumps, see the other recipes in this section.\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_platform_basic\n","description":"","tags":null,"title":"Platform character","uri":"/godot_recipes/4.x/2d/platform_character/index.html"},{"content":"This first game project will guide you through making your first Godot Engine game. While you don’t need any previous experience, it’s expected that you’ve at least read through the Godot 101: Getting Started section. There, you’ll learn about the editor interface and how to get around the Godot UI.\nWhy start with 2D? In a nutshell, 3D games are much more complex than 2D ones. However, many of the underlying game engine features you’ll need to know are the same. You should stick to 2D until you have a good understanding of Godot’s workflow. At that point, the jump to 3D will feel much easier.\nOpen Godot and start a new project. You can name it anything you’d like - we’re going with “Classic Shmup”, since this is a traditional shoot-em-up style game.\nDownloading the art You can download the art we’ll be using for the game from itch.io: Mini Pixel Pack by Grafxkid\nUnzip the art pack and copy it into your project by dropping the folder in the FileSystem tab.\nProject settings Next, we need to set up some project-wide settings. Open Project Settings and check the “Advanced Settings” toggle in the upper-right.\nIn the Display/Window section:\nViewport Width \u0026 Viewport Height to 240, 320. Window Width Override \u0026 Window Height Override to 480, 640. Stretch/Mode to canvas_items. These settings will ensure the game is the right size. Because we’re using pixel art, the images themselves are very small, so an old-school resolution like 240x320 is perfect. However, on a modern monitor, that’s a fairly small window, so the other settings let us scale that up proportionally. If you have a 1080p monitor, you can make the override values 720x960 instead. You’ll also be able to resize the window when the game is running.\nIn the Rendering/Textures section under Canvas Textures, set Default Texture Filter to Nearest. This will ensure that our beautiful pixel art stays nice and crisp, looking like the image on the right, not the one on the left: Click the Input Map tab at the top of the Project Settings window. This is where we can set up the inputs we want to use in the game. In the “Add New Action” box, type the following, hitting \u003center\u003e after each to add it to the list of actions: right, left, up, down, shoot. To assign key(s) to each named input, click the + button to its right and press the key on your keyboard. When you’re done, you should have something like this: Feel free to use other keys if you’d rather use a different setup.\nNext steps That takes care of setting up - now we’re ready to get started! In the next section, we’ll create the player-controlled spaceship.\nPrev Next ","description":"","tags":null,"title":"Project Setup","uri":"/godot_recipes/4.x/games/first_2d/first_2d_01/index.html"},{"content":"Problem You want to allow the player to “wrap around” the screen, teleporting from one side of the screen to the other. This is a common feature, especially in old-school 2D games (think Pac-man).\nSolution Get your screen (viewport) size\n@onready var screen_size = get_viewport_rect().size get_viewport_rect() is available to any CanvasItem derived node.\nCompare your player’s position\nif position.x \u003e screen_size.x: position.x = 0 if position.x \u003c 0: position.x = screen_size.x if position.y \u003e screen_size.y: position.y = 0 if position.y \u003c 0: position.y = screen_size.y Note that this is using the node’s position, which is usually the center of your sprite and/or body.\nSimplifying with wrapf()\nThe above code can be simplified using GDScript’s wrapf() function, which “loops” a value between the given limits.\nposition.x = wrapf(position.x, 0, screen_size.x) position.y = wrapf(position.y, 0, screen_size.y) ","description":"","tags":null,"title":"Screen wrap","uri":"/godot_recipes/4.x/2d/screen_wrap/index.html"},{"content":"Problem You want to use a spritesheet containing 2D animations.\nSolution Spritesheets are a common way for 2D animations to be distributed. In a spritesheet, all of the animation frames are packed into a single image.\nFor this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art athttps://elthen.itch.io/.\nWarning Make sure the images in your spritesheet are laid out in a constant-sized grid. This will enable Godot to automatically slice them. If they’re packed irregularly, you will not be able to use the following technique.\nNode setup This animation technique uses a Sprite2D node to display the texture, and then we animate the changing frames with AnimationPlayer. This can work with any 2D node, but for this demo, we’ll use a CharacterBody2D.\nAdd the following nodes to your scene:\nCharacterBody2D: Player Sprite2D CollisionShape2D AnimationPlayer Drag the spritesheet texture into the Texture property of the Sprite2D. You’ll see the entire spritesheet displayed in the viewport. To slice it up into individual frames, expand the “Animation” section in the Inspector and set the Hframes to 13 and Vframes to 8. Hframes and Vframes are the number of horizontal and vertical frames in your spritesheet.\nTry changing the Frame property to see the image change. This is the property we’ll be animating.\nAdding animations Select the AnimationPlayer and click the “Animation” button followed by “New\" . Name the new animation “idle”. Set the animation length to 2 and click the “Loop” button so that our animation will repeat (see below).\nWith the scrubber at time 0, select the Sprite2D node. Set its Animation/Frame to 0, then click the key icon next to the value.\nIf you try playing the animation, you’ll see it doesn’t appear to do anything. That’s because the last frame (12) looks the same as the first (0), but we’re not seeing any of the frames in-between (1-11). To fix this, change the “Update Mode” of the track from its default value of “Discrete” to “Continuous”. You can find this button at the end of the track on the right side.\nNote that this will only work for spritesheets where the frames are already in order. If they are not, you’ll have to keyframe each Frame seperately along the timeline.\nFeel free to add the other animations yourself. For example, the “jump” animation is on frames 65 through 70.\nRelated recipes Platform character ","description":"","tags":null,"title":"Spritesheet animation","uri":"/godot_recipes/4.x/animation/spritesheet_animation/index.html"},{"content":"In this tutorial, we’ll look at how to start working in 3D in Godot. You’ll learn how to navigate in the 3D editor, how to create and manipulate 3D objects, and how to work with some of Godot’s essential 3D nodes, such as cameras and lighting.\nAre you ready? A word of warning: 3D development can be quite a bit more complex than working in 2D. While many of the same principles apply - such as working with nodes, writing scripts, and handling logic/data - 3D brings with it a number of other considerations. For this reason, it’s a good idea to stick to 2D for your first few projects, moving to 3D once you have a good understanding of the game development process. This tutorial will assume you have completed at least an introductory Godot 2D project, such as the one in the [official Godot tutorial] (https://docs.godotengine.org/en/stable/getting_started/step_by_step/your_first_game.html).\nGetting Started in 3D One of Godot’s strengths is its ability to handle both 2D and 3D games. While much of what you’ve learned working on 2D projects (nodes, scenes, signals, etc.) applies equally well in 3D, there is also a whole new layer of complexity and capabilities. First, you’ll find that there are some additional features available in the 3D editor window, so we’ll start there:\nOrienting in 3D Space When you first open a new project in Godot, you will see the 3D project view:\nThe first thing you should notice is the three colored lines in the center. These are the x (red), y (green), and z (blue) axes. The point where they meet is the origin, which has the coordinates (0, 0, 0). You’ll find that this color scheme will also apply elsewhere in the Inspector.\nNote Different 3D applications follow different conventions for orientation. Godot uses Y-Up orientation, so that when looking at the axes, if x is pointing to the left/right, then y is up/down, and z is forward/back. Some other popular 3D software uses Z-UP. It’s good to keep this in mind when moving between applications.\nNavigation in 3D is performed using the mouse and keyboard. Here are the basic controls for the view camera:\nMousewheel up/down: zoom in/out Middle button + drag: orbit camera around current target Shift + middle button + drag: pan camera Right-click + drag: rotate camera in place In addition, if you’re familiar with popular 3D games, you might prefer Freelook mode, which you can toggle on/off using Shift+F. In this mode, you can use the WASD keys to fly around the scene while aiming with the mouse.\nYou can also alter the camera’s view by clicking on the [Perspective] label in the upper-left corner. Here, you can snap the camera to a particular orientation.\nAdding 3D Objects Now let’s add our first 3D node. Just as all 2D nodes inherit from Node3D, which provides properties such as position and rotation, 3D nodes inherit from Node3D, which provides 3D versions of the same properties. Add one to your scene and you’ll see the following object appear at the origin:\nThis object is not the node. It is something called a 3D gizmo. Gizmos are tools that allow you to move and rotate objects in space. The three rings control rotation, while the three arrows move (translate) the object along the three axes. Note that the rings and arrows are color-coded to match the axis colors.\nTake a few minutes to experiment and get familiar with the gizmo. Use Undo if you find yourself getting lost.\nTip Sometimes you may feel the gizmos are getting in your way. You can click on the mode icons to restrict yourself to only one type of transformation: move, rotate, or scale: Global vs. Local Space By default, the gizmo controls operate in global space. When you rotate the object, the gizmo’s arrows still point along the axes. However, if you click the Use Local Space button, the gizmo will switch to moving the body in local space.\nNow when you rotate the object, the gizmo arrows point along the object’s axes and not the world’s. Switching back and forth between Local and World space can make it much easier to place an object exactly where you want it.\nTransforms Look at the Inspector for the Node3D node. In the Transform section, you’ll see properties for Position, Rotation, and Scale. Drag the object around with the gizmo and observe how these values change. Just like in 2D, these properties are relative to the node’s parent.\nTogether, these properties make up the node’s transform. When changing the node’s spatial properties in code, you’ll access the transform property, which is a Godot Transform3D object. It has two properties: origin and basis. The origin represents the body’s position, while the basis contains three vectors that define the body’s local coordinate axes - think of the three axis arrows in the gizmo when you’re in Local Space mode.\nYou’ll see how to use these properties later in this section.\nMeshes Just like a Node2D, a Node3D has no size or appearance of its own. In 2D, you would use a Sprite2D to add a texture to the node. In 3D, you need to add a mesh. A mesh is a mathematical description of a shape. It consists of a collection of points, called vertices. These vertices are connected by lines, called edges, and multiple edges (at least three) together make a face.\nFor example, a cube is made up of 8 vertices, 12 edges, and 6 faces.\nAdding Meshes Typically, meshes are created by using 3D modeling software, such as Blender. You can also find many collections of 3D models available for download, if you’re unable to create your own. However, often you just need a basic shape such as a cube or sphere. In this case, Godot provides a way to create simple meshes called primitives.\nAdd a MeshInstance3D node as a child of the Node3D and in the Inspector, click its Mesh property:\nHere you can see the list of available primitives. They represent a handy collection of common useful shapes. Select “New BoxMesh” and you’ll see a plain cube appear on the screen.\nCameras Try running the scene with your cube object. Did you see anything? In 3D, you won’t see anything in the game viewport without adding a Camera3D. Add one to the root node and use the camera’s gizmo to position it pointing towards the cube:\nThe pinkish-purple pyramid shape on the camera is called the fustrum and represents the camera’s view. Notice the small triangular arrow which represents the camera’s “up” orientation. As you’re moving the camera around, try pressing the Preview button in the upper-left to see what the camera sees. Play the scene to verify everything is working as expected.\nWrapping Up In this tutorial you learned how to use Godot’s 3D editor, how to add 3D nodes such as Node3D, MeshInstance3D, and Camera3D, and how to use gizmos to place your objects. You also learned a bunch of new terminology. Hopefully you’re not overwhelmed.\nIn the next part, we’ll look at how to build a 3D scene by importing 3D assets and how to use more of Godot’s 3D nodes.\n","description":"","tags":null,"title":"The 3D Editor","uri":"/godot_recipes/4.x/g101/3d/101_3d_01/index.html"},{"content":"Problem You’re making a 2D top-down game, and you want to control a character’s movement.\nSolution For this solution, we’ll assume you have the following input actions defined:\nAction Name Key(s) \"up\" W,↑ \"down\" S,↓ \"right\" D,→ \"left\" A,← \"click\" Mouse button 1 We will also assume you’re using a CharacterBody2D node.\nWe can solve this problem in many ways, depending on what type of behavior you’re looking for.\nOption 1: 8-way movement In this scenario, the player uses the four directional keys to move (including diagonals).\nextends CharacterBody2D var speed = 400 # speed in pixels/sec func _physics_process(delta): var direction = Input.get_vector(\"left\", \"right\", \"up\", \"down\") velocity = direction * speed move_and_slide() Option 2: Rotate and move In this scenario, the left/right actions rotate the character and up/down move the character forward and back in whatever direction it’s facing. This is sometimes referred to as “Asteroids-style” movement.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec var rotation_speed = 1.5 # turning speed in radians/sec func _physics_process(delta): var move_input = Input.get_axis(\"down\", \"up\") var rotation_direction = Input.get_axis(\"left\", \"right\") velocity = transform.x * move_input * speed rotation += rotation_direction * rotation_speed * delta move_and_slide() Note Godot considers an angle of 0 degrees to be pointing along the x axis. This means that a node’s forward direction (transform.x) is to the right. You should ensure that your character’s sprite is also drawn pointing to the right.\nOption 3: Aim with mouse Similar to option 2, but this time the character rotation is controlled with the mouse (ie the character always points towards the mouse). Forward/back movement is done with the keys as before.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec func _physics_process(delta): look_at(get_global_mouse_position()) var move_input = Input.get_axis(\"down\", \"up\") velocity = transform.x * move_input * speed move_and_slide() Option 4: Click and move In this option, the character moves to the clicked location.\nextends CharacterBody2D var speed = 400 # move speed in pixels/sec var target = null func _input(event): if event.is_action_pressed(\"click\"): target = get_global_mouse_position() func _physics_process(delta): if target: # look_at(target) velocity = position.direction_to(target) * speed if position.distance_to(target) \u003c 10: velocity = Vector2.ZERO move_and_slide() Note that we stop moving if we get close to the target position. If you don’t do this, the character will “jiggle” back and forth as it moves a little bit past the target, moves back, goes a little past it, and so on. Optionally, you can use look_at() to face in the direction of movement.\nDownload This Project Download the project code here: https://github.com/godotrecipes/topdown_movement\n","description":"","tags":null,"title":"Top-down movement","uri":"/godot_recipes/4.x/2d/topdown_movement/index.html"},{"content":"Problem You need to understand in what order Godot handles nodes in the scene tree.\nSolution “Tree order” is mentioned often in the Godot docs and in tutorials. However, it is not always obvious to a beginner what is meant by this. Generally speaking, the order in which nodes are handled in the tree is in top-down fashion, starting at the root and going down each branch in turn.\nScene tree order is something that can cause a great deal of confusion for Godot beginners. In this example, we’ll illustrate in what order things happen.\nHere’s our sample node setup:\nOn each node, we have the following script attached:\nextends Node func _init(): # Note: a Node doesn't have a \"name\" yet here. print(\"TestRoot init\") func _enter_tree(): print(name + \" enter tree\") func _ready(): print(name + \" ready\") # This ensures we only print *once* in process(). var test = true func _process(delta): if test: print(name + \" process\") test = false Before we talk about the results, let’s review what each of these callback functions represents:\n_init() is called when the object is first created. It now exists in the computer’s memory.\n_enter_tree() is called when the node first enters the tree. This can be when instancing or when add_child() is used, for example.\n_ready() is called when the node and its children have all been added to the tree and are ready.\n_process() is called every frame (typically 60 times per second) on every node in the tree.\nIf we ran this on a single node all by itself, the order would be as you might expect:\nTestRoot init TestRoot enter tree TestRoot ready TestRoot process Once we add children to the mix, it becomes a bit more complex, and probably needs some clarification:\nTestRoot init TestChild1 init TestChild3 init TestChild2 init TestRoot enter tree TestChild1 enter tree TestChild3 enter tree TestChild2 enter tree TestChild3 ready TestChild1 ready TestChild2 ready TestRoot ready TestRoot process TestChild1 process TestChild3 process TestChild2 process As you can see, all of these nodes printed their messages in tree order, from top to bottom, following branches first - with the exception of the _ready() code.\nHere’s a quote from the Node reference:\nCalled when the node is “ready”, i.e. when both the node and its children have entered the scene tree. If the node has children, their _ready callbacks get triggered first, and the parent node will receive the ready notification afterwards.\nThis leads to an important rule-of-thumb to remember when setting up your node structure:\nTip Parent nodes should manage their children, not vice-versa.\nThis means any code in the parent must be able to fully access any data in its children. For that reason, _ready() must be processed in reverse tree order.\nRemember this when trying to access other nodes in _ready(). If you need to go up the tree to a parent (or grandparent), you should probably run that code in the parent rather than the child.\nRelated recipes Understanding node paths ","description":"","tags":null,"title":"Understanding tree order","uri":"/godot_recipes/4.x/basics/tree_ready_order/index.html"},{"content":"Game Engines Game development is complex and involves a wide variety of knowledge and skills. In order to build a modern game, you need a lot of underlying technology before you can make the actual game itself. Imagine if you had to build your own computer and write your own operating system before you could even start programming. Game development would be a lot like that if you truly had to start from scratch and build everything you needed.\nIn addition, there are a number of common needs every game has. For example, no matter what your game is, it’s going to need to draw things on the screen. If the code to do that has already been written, it makes more sense to reuse it that to create it all over again for every game. This is where game engines come in.\nA game engine is a collection of tools and technologies designed to assist in developing games. This allows you to focus more on building your game, and less on reinventing the wheel. Here are some of the features a good game engine will provide:\nRendering (2D/3D) “Rendering” is the process of displaying your game on the player’s screen. A good rendering pipeline needs to work with modern GPU features, high resolution displays, and effects like lighting and perspective, while maintaining a high frame rate.\nPhysics Building an accurate and usable physics engine is an enormous task. Most games require some sort of collision detection and response, and many need simulated physics (ie. friction, inertia, etc.), but few developers want to take on the task of writing one.\nPlatform Support In today’s market, you want to be able to release your game on multiple platforms, such as mobile, web, PC, and/or console. A game engine lets you build your game once and export it to one or more platforms.\nDevelopment Environment All of these tools are brought together in a single application, combining everything into one environment so you don’t have to learn a new workflow for every new project.\nThere are dozens of popular game engines to choose from today, such as Unity, Unreal, and GameMaker Studio, to name a few. It is important to remember that the majority of popular engines are commercial products. They may or may not be free to download, but the will require some kind of licensing or royalty agreement if you plan to release your game (and especially if your game makes money). You need to carefully read and understand what you’re agreeing to and what you are and are not allowed to do with the engine.\nWhy use Godot? Click here to download Godot\nIn contrast to the above, Godot is completely free and open source, released under the very permissive MIT license. This means there are no fees, hidden costs, or royalties you need to pay. This is in addition to being a fully featured modern game engine.\nAs a developer, the benefits are great. Because it’s unencumbered by commercial licensing, you have complete control over exactly how and where your game is distributed. In addition, Godot’s open source nature also means there is a much greater level of transparency than you’ll find with commercial engines. For example, if you find a particular feature doesn’t quite meet your needs, you’re free to modify the engine itself - no permission required.\n","description":"","tags":null,"title":"What is Godot?","uri":"/godot_recipes/4.x/g101/start/101_01/index.html"},{"content":" Working with 3D Assets Detailed recipes for importing and working with 3D assets including models, animations, and materials.\nFor these examples, we’ll be using the following 3d assets from Kay Lousberg:\nAdventurers Character Pack Dungeon Asset Pack In this section: Importing Assets Character Animation Character Controller ","description":"","tags":null,"title":"Working with 3D Assets","uri":"/godot_recipes/4.x/3d/assets/index.html"},{"content":" Your First 2D Game Get started with Godot by building a 2D shooter. In this series, we’ll start with the basics and build a classic, old-school space shooter.\nHere’s a screenshot of the finished game:\nIn each part of the series, we’ll build a piece of the game, adding features and explaining the process along the way.\nBackground If you find that you’re struggling with the programming side of things, see these resources:\nGodot 101: Introduction to GDScript - tutorial on this website. Godot Official Documentation - official tutorial resources Download This Project on GitHub Download the project code here:\nhttps://github.com/godotrecipes/classic_shmup\n","description":"","tags":null,"title":"Your First 2D Game","uri":"/godot_recipes/4.x/games/first_2d/index.html"},{"content":"Problem You need to make a first-person shooter (FPS) character.\nSolution Start with a CharacterBody3D node, and add a CollisionShape3D to it. The CapsuleShape3D collision shape is the most common choice. Depending on your world setup, you may want to add additional shapes here, but for the purposes of this example, we’ll stick to the basics.\nWe’ll leave all the sizing at the default values, meaning the capsule will be 2 meters high. Move it up by 1.0 m to align its bottom with the ground.\nNext, add a Camera3D as a child of the body and move it up about 1.6 m.\nWhere’s the body? For this example, we’ll leave the character “bodyless” - meaning we’re not adding a mesh to display for the player’s body. Depending on your setup, you may or may not need to see the player’s body.\nAttach a script to the body and start by defining some properties:\nextends CharacterBody3D var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var speed = 5 var jump_speed = 5 var mouse_sensitivity = 0.002 The _physics_process() function is the place to handle movement. Note that Input.get_vector() returns a 2-dimensional vector based on the combination of the forward/back/left/right keys. We want to use this vector to set the x and z components of the body’s velocity (because y is handled by gravity). Multiplying this vector by the body’s basis ensures we account for rotation - forward should always be the body’s forward vector.\nfunc _physics_process(delta): velocity.y += -gravity * delta var input = Input.get_vector(\"left\", \"right\", \"forward\", \"back\") var movement_dir = transform.basis * Vector3(input.x, 0, input.y) velocity.x = movement_dir.x * speed velocity.z = movement_dir.z * speed move_and_slide() if is_on_floor() and Input.is_action_just_pressed(\"jump\"): velocity.y = jump_speed Don’t forget to add the input actions to your Input Map using the keys/inputs you prefer (W/A/S/D is typical, or you can use joystick axes if you prefer a controller).\nAdd the player to a “World” scene where you’ve created some StaticBody3D nodes for the floor and some walls.\nWhen you try to move, you’ll notice you can move forward/back and left/right, but you can’t rotate. That’s what we’ll handle next.\nMouse control in 3D First, we need the player to rotate left/right when we move the mouse the same way. Mouse input is represented in 2D, relative to the screen, so we need the x movement of the mouse to rotate the player’s body around its y (vertical) axis. The mouse_sensitivity property we defined above lets us adjust how many pixels of mouse movement translate to a degree of rotation.\nfunc _input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) Try the code again, and you’ll see that you can now rotate with the mouse. However, you may find your mouse running outside the game window. This is the perfect time to add some code to capture your mouse. See Input: Capturing the Mouse for details.\nOur updated code then becomes\nfunc _input(event): if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * mouse_sensitivity) Finally, to look up/down, we’ll use the y motion of the mouse to tilt the camera. We don’t want it to turn completely upside-down, though, so we’ll clamp() the rotation to a reasonable value of 70 degrees.\nfunc _input(event): if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * mouse_sensitivity) $Camera3D.rotate_x(-event.relative.y * mouse_sensitivity) $Camera3D.rotation.x = clampf($Camera3D.rotation.x, -deg_to_rad(70), deg_to_rad(70)) Holding a weapon An FPS character typically has a 3D mesh of a weapon positioned in front. Setting this up can be easy with a couple of Godot editor tricks.\nAdd your weapon mesh as a child of the Camera3D. Then, in the editor view menu, choose “2 Viewports” and set one of them to preview the camera. Then, you can move around the weapon and easily see how it will look from the player’s perspective.\nTo add a little personality, try using an AnimationPlayer to animate the weapon’s position from side-to-side as the player moves.\nRelated recipes Input: Capturing the Mouse Download This Project Download the project code here: https://github.com/godotrecipes/basic_fps\n","description":"","tags":[],"title":"Basic FPS Character","uri":"/godot_recipes/4.x/3d/basic_fps/index.html"},{"content":" Basics Basic Godot tips and tricks that apply to any project.\nIn this section: Understanding tree order Node communication (the right way) Understanding node paths Understanding 'delta' Saving/loading data Migrating from 3.x ","description":"","tags":null,"title":"Basics","uri":"/godot_recipes/4.x/basics/index.html"},{"content":"Problem You need a camera controller, using mouse or keyboard, that remains level while rotating and following a target.\nSolution Try this: take a Camera3D node and rotate it a small amount around X (the red ring on the gizmo), then a small amount around Z (the blue ring). Now reverse the X rotation and click the “Preview” button. Observe how the camera is now tilted.\nThe solution to this problem is to place the camera on a gimbal - a device designed to keep an object level during movement. We can create a gimbal using two Node3D nodes, which will control the camera’s left/right and up/down rotation respectively.\nThe node setup should look like this:\nNode3D: CameraGimbal Node3D: InnerGimbal Camera3D Set the Transform/Position of the Camera3D to (0, 0, 4).\nHere’s how the gimbal works: the outer node can only be rotated in Y, while the inner one rotates only in X. You can test this out by rotating them manually, but make sure you change to “Local Space Mode” first (that’s the cube icon next to the lock in the menu bar - the keyboard shortcut to toggle is “T”). Remember to only move the green ring of the outer node and only the red ring of the inner one. Don’t touch the camera node at all.\nReset all the rotations to 0 once you’ve finished experimenting.\nKeyboard control We’ll start with the keyboard controls, then add an option to use the mouse as well. Here are the required actions and their assigned inputs:\nAction Name Input \"cam_up\" W \"cam_down\" S \"cam_right\" D \"cam_left\" A \"cam_zoom_in\" Mouse Wheel Up \"cam_zoom_out\" Mouse Wheel Down Here’s the initial script. Note that we’re making sure to rotate each Node3D in its local space around the specific axis, as described above.\nextends Node3D var rotation_speed = PI/2 func get_input_keyboard(delta): # Rotate outer gimbal around y axis var y_rotation = Input.get_axis(\"cam_left\", \"cam_right\") rotate_object_local(Vector3.UP, y_rotation * rotation_speed * delta) # Rotate inner gimbal around local x axis var x_rotation = Input.get_axis(\"cam_up\", \"cam_down\") x_rotation = -x_rotation if invert_y else x_rotation inner.rotate_object_local(Vector3.RIGHT, x_rotation * rotation_speed * delta) func _process(delta): get_input_keyboard(delta) Make a test scene with a MeshInstance3D and instance the CameraGimbal in it to test out the movement.\nYou’ll notice that holding the up/down control will cause the camera to rotate all the way around, eventually becoming upside-down. To prevent this, we can clamp the rotation.\nfunc _process(delta): get_input_keyboard(delta) $InnerGimbal.rotation.x = clamp($InnerGimbal.rotation.x, -1.4, -0.01) The -1.4 value lets it go almost to 90 degrees up, while setting a very small value for the minimum keeps the camera from clipping into the ground. Feel free to experiment with other values.\nMouse control We’ll add a flag called mouse_control to enable easy toggling of mouse/keyboard controls.\n# mouse properties var invert_y = false var invert_x = false var mouse_control = false var mouse_sensitivity = 0.005 func _unhandled_input(event): if mouse_control and event is InputEventMouseMotion: if event.relative.x != 0: var dir = 1 if invert_x else -1 rotate_object_local(Vector3.UP, dir * event.relative.x * mouse_sensitivity) if event.relative.y != 0: var dir = 1 if invert_y else -1 $InnerGimbal.rotate_object_local(Vector3.RIGHT, dir * event.relative.y * mouse_sensitivity) func _process(delta): if !mouse_control: get_input_keyboard(delta) This code works by converting horizontal mouse motion to Y rotation of the outer gimbal and vertical to X rotation for the inner gimbal. We’ve also added invert_x and invert_y flags so that you can flip the motion in either axis - many players prefer one over the other, so it’s best to allow for both options.\nAlso, in _process() we disable keyboard input when using mouse control.\nYou may notice a problem with the up/down movement if you move the mouse too quickly. A large value for event.relative.y results in “skipping” to the opposite side of the clamped value. We can solve this by clamping the vertical mouse movement to a reasonable value. Change the above code for y to this:\nif event.relative.y != 0: var dir = 1 if invert_y else -1 var y_rotation = clamp(event.relative.y, -30, 30) $InnerGimbal.rotate_object_local(Vector3.RIGHT, dir * y_rotation * mouse_sensitivity) Note In your project, you’ll probably also want to capture the mouse during gameplay. See the linked recipe at the end of this document for details.\nCamera zoom Camera zoom works by varying the scale of the gimbal system.\n# zoom settings var max_zoom = 3.0 var min_zoom = 0.5 var zoom_speed = 0.09 var zoom = 1.5 func _unhandled_input(event): if event.is_action_pressed(\"cam_zoom_in\"): zoom -= zoom_speed if event.is_action_pressed(\"cam_zoom_out\"): zoom += zoom_speed zoom = clamp(zoom, min_zoom, max_zoom) func _process(delta): scale = lerp(scale, Vector3.ONE * zoom, zoom_speed) Using lerp() to change the zoom level results in smoother zooming.\nFollowing a target Once you have the camera gimbal set up, it can follow a target by adding the following:\n@export var target : Node3D func _process(delta): if target: global_position = target.global_position Instance the camera in your scene and use the Inspector to choose the node you want to follow.\nFinal script For completeness, here’s the full script, including @export variables for all the camera settings, so that you can configure it in your project.\nextends Node3D @export var target : Node3D @export_range(0.0, 2.0) var rotation_speed = PI/2 # mouse properties @export var mouse_control = false @export_range(0.001, 0.1) var mouse_sensitivity = 0.005 @export var invert_y = false @export var invert_x = false # zoom settings @export var max_zoom = 3.0 @export var min_zoom = 0.4 @export_range(0.05, 1.0) var zoom_speed = 0.09 var zoom = 1.5 @onready var inner = $InnerGimbal func _unhandled_input(event): if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED: return if event.is_action_pressed(\"cam_zoom_in\"): zoom -= zoom_speed if event.is_action_pressed(\"cam_zoom_out\"): zoom += zoom_speed zoom = clamp(zoom, min_zoom, max_zoom) if mouse_control and event is InputEventMouseMotion: if event.relative.x != 0: var dir = 1 if invert_x else -1 rotate_object_local(Vector3.UP, dir * event.relative.x * mouse_sensitivity) if event.relative.y != 0: var dir = 1 if invert_y else -1 var y_rotation = clamp(event.relative.y, -30, 30) inner.rotate_object_local(Vector3.RIGHT, dir * y_rotation * mouse_sensitivity) func get_input_keyboard(delta): # Rotate outer gimbal around y axis var y_rotation = Input.get_axis(\"cam_left\", \"cam_right\") rotate_object_local(Vector3.UP, y_rotation * rotation_speed * delta) # Rotate inner gimbal around local x axis var x_rotation = Input.get_axis(\"cam_up\", \"cam_down\") x_rotation = -x_rotation if invert_y else x_rotation inner.rotate_object_local(Vector3.RIGHT, x_rotation * rotation_speed * delta) func _process(delta): if !mouse_control: get_input_keyboard(delta) inner.rotation.x = clamp(inner.rotation.x, -1.4, -0.01) scale = lerp(scale, Vector3.ONE * zoom, zoom_speed) if target: global_position = target.global_position ","description":"","tags":null,"title":"Camera Gimbal","uri":"/godot_recipes/4.x/3d/camera_gimbal/index.html"},{"content":"In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.\nSetting up the Ship Scene A common part of the Godot workflow is creating scenes. As discussed earlier, a scene in Godot is nothing more than a collection of nodes. In most Godot projects, each game object is configured as a scene, with nodes that provide it with the desired functionality, and optionally some code to customize its behavior.\nChoosing nodes The first step is to decide what kind of node to start with. The first node you add to the scene is called the root node. A scene’s root node should generally be the one that primarily defines the game object’s behavior. Then you attach child nodes to add additional functionality.\nSo what should our game’s ship be? Let’s break down the requirements, and look at what nodes might be useful to meet them.\nThe ship needs to:\nMove in 2D space. For this, a basic Node2D would suffice, as that’s the node that has position, rotation, and other 2D-related properties. However, it has no appearance.\nDisplay an image. Sprite2D is the node for this. Since it’s also a Node2D, we’d still be able to move it around.\nDetect getting hit. The enemies will be shooting and flying around on the screen, so we’ll need to know when the ship is hit. We don’t have a need for solid objects - they’re not going to bounce off each other or transfer momentum - we just need to know when they touch. For this, an Area2D would be perfect. It can detect touching other objects, has positional properties, but it has no appearance of its own.\nLooking at this list, the Area2D provides the main functionality. We can attach a Sprite2D to display the ship image, and then we’ll have everything we need.\nBuilding the scene In the Scene tab, click the + button or the + Other Node button to add the first node. Start typing Area2D and choose it from the list. Once it’s in the Scene tab, click the node’s name to rename it to Player, and press \u003cCtrl+S\u003e to save the scene.\nDisplaying the ship With the Player node selected, add another node: a Sprite2D. To keep things organized, let’s rename this node to Ship.\nFrom the FileSystem tab, drag the Player_ship (16x16).png file from the art pack and drop it in the Texture property of the Inspector.\nThe first thing you’ll notice is that there seem to be three ships! The image from the art pack also includes versions of the ship going to the left/right. We can use this - in the Animation section of the Inspector, set Hframes to 3. Now, changing the Frame property will move between the three different versions. Leave it at 1 for now.\nAdding a collision shape You may also have noticed the yellow warning triangle on the Area2D node. If you click it, you’ll see the warning is telling us that the area doesn’t have a shape. We need to define its shape, and we can do that by adding a CollisionShape2D node as a child of the Player.\nIn the Inspector for this node, you’ll see a Shape property that currently shows \u003cempty\u003e. If you click in this box, you’ll see a dropdown that allows you to select from a variety of shapes. Choose New RectangleShape2D and you’ll see a light blue square appear over the ship. You can adjust the size of the shape by dragging the orange circles, or you can click on the shape in the Shape property to expand it and fill in the Size manually.\nExhaust The ship will look much more dynamic with a little animation. Included in the art pack are some animations of exhaust flames named “Boosters”. There are three: one for each version of the ship (left, forward, and right).\nTo display these, select the Ship node and add a child AnimatedSprite2D node and name it “Boosters”.\nIn the Inspector, under the Animation section, you’ll find a property called Sprite Frames, which is currently \u003cempty\u003e. Click it to create a New SpriteFrames, then click the SpriteFrames item to open the animation panel at the bottom of the editor window.\nDouble-click the “default” animation to rename it to “forward”. Then, to add the animation images, click the Add frames from sprite sheet button:\nChoose the Boosters (16 x 16).png image and you’ll see the Select Frames window, allowing you to choose the frames you want.\nThere are only two frames in this animation, but the grid isn’t correct. Change the Size values to match the image sizes: 16 x 16. Then, click both frames to select them and click the Add 2 Frame(s) button.\nNow that you’ve added the two frames, press the Play button to run the animation. You can also toggle the Autoplay on Load button so that the animation will start automatically.\nIt’s a little slow, so change the speed to 10 FPS.\nAdd two more animations by clicking the Add Animation button, naming them left and right.\nRepeat the process, adding the left and right “Booster” sprite sheets.\nGun cooldown The last node we’ll need to complete the player setup is a Timer to control how fast the player can shoot. Add the Timer as a child of Player and name it GunCooldown. Set its One Shot property to “On”. This means that when the timer ends, it won’t automatically restart. In the player’s code, we’ll start the timer when the player shoots, and they won’t be able to shoot again until the timer runs out.\nNext steps That completes the player scene setup. We’ve added the nodes to give the player ship the functionality it will need in the game. In the next section, we’ll add some code to enable the player to control the ship, make it shoot, and detect when it collides with things.\nPrev Next ","description":"","tags":null,"title":"Designing the Player Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_02/index.html"},{"content":"Problem You need a 2D character that moves in a grid pattern.\nSolution Grid- or tile-based movement means the character’s position is restricted. They can only stand on a particular tile - never between two tiles.\nCharacter setup Here are the nodes we’ll use for the player:\nArea2D (“Player”): Using an Area2D means we can detect overlap (for picking up objects or colliding with enemies). Sprite2D: You can use a sprite sheet here (we’ll set up the animation below). CollisionShape2D: Don’t make the hitbox too big. Since the player will be standing on the center of a tile, overlaps will be from the center. RayCast2D: For checking if movement is possible in the given direction. AnimationPlayer: For playing the character’s walk animation(s). Add some input actions to the Input Map. We’ll use “up”, “down”, “left”, and “right” for this example.\nBasic movement We’ll start by setting up the tile-by-tile movement, without any animations or interpolation.\nextends Area2D var tile_size = 64 var inputs = {\"right\": Vector2.RIGHT, \"left\": Vector2.LEFT, \"up\": Vector2.UP, \"down\": Vector2.DOWN} tile_size should be set to match the size of your tiles. In a larger project, this can be set by your main scene when instancing the player. We’re using 64x64 tiles in the example below.\nThe inputs dictionary maps the input action names to direction vectors. Make sure you have the names spelled the same here and in the Input Map (capitalization counts!).\nfunc _ready(): position = position.snapped(Vector2.ONE * tile_size) position += Vector2.ONE * tile_size/2 snapped() allows us to “round” the position to the nearest tile increment, and adding a half-tile amount makes sure the player is centered on the tile.\nfunc _unhandled_input(event): for dir in inputs.keys(): if event.is_action_pressed(dir): move(dir) func move(dir): position += inputs[dir] * tile_size Here’s the actual movement code. When an input event occurs, we check the four directions to see which one matched, then pass it to move() to change the position.\nCollision Now we can add some obstacles. You can add StaticBody2Ds to manually add some obstacles (enable snapping to make sure they’re aligned with the grid) or use a TileMap (with collisions defined), as in the example below.\nWe’ll use the RayCast2D to determine whether a move to the next tile is allowed.\nonready var ray = $RayCast2D func move(dir): ray.target_position = inputs[dir] * tile_size ray.force_raycast_update() if !ray.is_colliding(): position += inputs[dir] * tile_size When changing a raycast’s target_position property, the physics engine won’t recalculate its collisions until the next physics frame. force_raycast_update() lets you update the ray’s state immediately. If it’s not colliding, then we allow the move.\nNote Another common method is to use 4 separate raycasts, one for each direction.\nAnimating movement Lastly we can interpolate the position between tiles, giving a smooth feel to the movement. We’ll use the Tween node to animate the position property.\nvar animation_speed = 3 var moving = false Add a reference to the Tween node and a variable to set our movement speed.\nfunc _unhandled_input(event): if moving: return for dir in inputs.keys(): if event.is_action_pressed(dir): move(dir) We’ll ignore any input while the tween is running and remove the direct position change so that the tween can handle it.\nfunc move(dir): ray.target_position = inputs[dir] * tile_size ray.force_raycast_update() if !ray.is_colliding(): #position += inputs[dir] * tile_size var tween = create_tween() tween.tween_property(self, \"position\", position + inputs[dir] * tile_size, 1.0/animation_speed).set_trans(Tween.TRANS_SINE) moving = true await tween.finished moving = false Experiment with different tween transitions for different movement effects.\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_grid_movement/\n","description":"","tags":null,"title":"Grid-based movement","uri":"/godot_recipes/4.x/2d/grid_movement/index.html"},{"content":"In the last part, we started a 3D project and looked at how to navigate and create 3D objects. In this part, you’ll learn how to import existing 3D objects that you’ve made or downloaded and how to use more of Godot’s 3D nodes.\nImporting 3D Objects If you’re familiar with 3D modeling software such as Blender, you can make your own models to use in your game. If not, there are many sources where you can download objects or even collections of objects for particular game types. One of our favorite makers of free game art is Kenney.nl.\nFor our tutorials, we’re going to use Kenney’s Platformer Kit, which you can download here: https://kenney.nl/assets/platformer-kit\nThis kit has a wide selection of objects that we can use to practice our Godot 3D skills. Here’s a sample showing what the kit looks like:\nOnce you’ve downloaded the kit, you’ll find that the objects inside are provided in a variety of different formats. Godot is able to use several of these, but since GLTF is available in this pack, it’s preferred over the others. Drop the GLTF format folder into your Godot project’s folder and rename it to “platformer_kit”.\n3D file formats Whether you create your own models or download the, you’ll need them to be saved in a format that Godot can use. Godot supports the following 3D file formats:\nglTF - supported in both text (.gltf) and binary (.glb) versions DAE (Collada) - an older format that is still supported OBJ (Wavefront) - an older format that is supported, but the format is limited compared to modern options FBX - a commercial format that has limited support glTF is the recommended format - it has the most features and is very well supported in Godot.\nWhen you switch back to your Godot window, you’ll see progress bar while Godot scans the folder and imports all of the objects. Let’s click on one of them to see what’s going on. In the FileSystem tab, double-click on crate.glb:\nHere you can see the object will be imported as a scene, with its root type set to Node3D and named “Scene Root”. Let’s change these: set the root type to RigidBody3D and the root name to “Crate”, then click the “Reimport” button.\nNow right-click on “crate.glb” and choose New Inherited Scene. Here we have a classic game object: the crate. The root node of the scene is a RigidBody3D named “Crate” just as we wanted.\nFinally, we need to add a collision shape to the body. While we could do this by adding a CollionShape3D, as you would typically do in 2D, but there’s a quicker way.\nSelect the crate2 mesh and you’ll see a Mesh menu appear at the top of the viewport. Click it and select Create Single Convex Collision Sibling. Godot will automatically add a CollionShape3D with a collision shape that matches the mesh.\nNow we’re finished setting up the object. Save your Crate scene and let’s see how we can use it.\nBuilding a 3D Scene Create a new scene with a Node3D root. The first child we’ll add is one to give us a “ground” to stack some crates on. Add a StaticBody3D called “Ground”, and to that add a MeshInstance3D. In the Mesh property, select “New BoxMesh” and then click it to open its properties. Set Size to (10, 0.1, 10) so that we have a nice large surface. However, it would look better if it weren’t plain white.\nAlso in the mesh properties is a Material property. Materials are how you define the appearance of an object. Select “New StandardMaterial3D” and then click it to open a large list of properties. To set the color of the mesh, we need the Albedo/Color property. Choose a color, such as brown or dark green.\nIf we add a crate, it will fall right through the mesh, so we also need to give it a collision shape. Add a CollisionShape3D to the Ground and choose “New BoxShape3D”. Set the collision box to the same size as the mesh.\nNow instance a few crates in the scene and arrange them in a rough stack. Add a Camera and place it where it has a good view of the crates. Run the scene and watch your crates go tumbling!\nWhy is the scene so dark? Because there’s no light! By default, Godot doesn’t add any lighting or environment to your scenes, like it does in the editor viewport. This is great when you want to set up your own specific lighting, but for a quick example scene like this, there’s a shortcut.\nLighting There are multiple light nodes available in 3D, which you can use to create a variety of lighting effects. But we’re going to start with DirectionalLight3D. However, instead of adding one manually, we’re going to have Godot use the same one it’s using in the editor window. At the top ove the viewport, there are two icons that control the preview lighting and preview environment. If you click the three dots next to them, you can see their settings.\nClick the Add Sun to Scene button, and Godot will add a DirectionalLight3D to your scene. Click Add Environment to Scene and it will do the same with the preview sky by adding a WorldEnvironment node.\nRun the scene again, and you’ll be able to see your crates falling.\nRotating Camera Let’s make the camera a little more dynamic by having it slowly orbit around the scene. Select the root node and add a Node3D, which will be located at (0, 0, 0) and name it “CameraHub”. In the scene tree, drag the camera to make it a child of this new node. Now, if the CameraHub rotates around the y axis, it will drag the camera along with it.\nAdd a script to the root node and add the following:\nextends Node3D func _process(delta): $CameraHub.rotate_y(0.6 * delta) Run the scene to see what happens.\nWrapping Up In this tutorial you learned how to import 3D objects from outside sources, and how to combine them into a simple scene. We also investigated lights and moving cameras.\nIn the next part, we’ll look at how to build a more complex scene and include a player-controlled character.\n","description":"","tags":null,"title":"Importing 3D Objects","uri":"/godot_recipes/4.x/g101/3d/101_3d_02/index.html"},{"content":"Problem You want to understand Godot’s “input action” system.\nSolution Let’s say you’re making a top-down character and you write code using InputActionKey that uses the arrow keys for movement. You’ll quickly find that many players prefer to use “WASD” style controls. You can go back into your code and add the additional key checks, but this would result in duplicated/redundant code.\nInput actions can help to make your code more configurable. Rather than hard-coding specific keys, you’ll be able to modify and customize them without changing the code.\nCreating inputs You define input actions in the “Project Settings” under the “Input Map” tab. Here, you can create new actions and/or assign inputs to them.\nYou’ll see when you click on the tab there are already some default actions configured. They are all named “ui_*” to indicate that they are the default interface actions. “Tab” for next UI element, for example.\nGenerally speaking, you should create your own actions for your game, rather than use the existing ones.\nFor this example, let’s say you want to allow the player to control the game with the keyboard or the mouse. They need to be able to shoot by pressing either the left mouse button or the spacebar.\nCreate the new action “shoot” by typing the name in the “Action” field at the top and clicking “Add” (or pressing enter). Scroll to the bottom and you’ll see the new action has been added to the list.\nNow you can assign inputs to this action by clicking the “+” sign to the right. Inputs can be keys, mouse buttons, or joy/gamepad inputs. Choose “Key” and you can press the key on the keyboard you want to assign - let’s press the spacebar - and click “OK”.\nClick “+” to add another input, and this time choose “Mouse Button”. The default of “Device 0” and “Left Button” is fine, but you can select others if you like.\nUsing input actions You can check for the action either by polling the Input singleton every frame:\nfunc _process(delta): if Input.is_action_pressed(\"shoot\"): # This will execute every frame as long as the input is held. This is best for continuous actions - i.e. those you want to check constantly, such as movement.\nIf instead you want to detect the action at the moment it occurs, you can use the _input() or _unhandled_input() callbacks:\nfunc _unhandled_input(event): if event.is_action_pressed(\"shoot\"): # This will run once on the frame when the action is first pressed There are several functions you can use for checking input state:\nis_action_pressed(): This function returns true if the action is currently in the pressed state.\nis_action_released(): This function returns true if the action is not In the pressed state.\nis_action_just_pressed() / is_action_just_released(): These methods work like the above, but only return true on the single frame after the event occurs. This is useful for non-recurring actions like shooting or jumping where the user needs to let go and then press the key again to repeat the action.\nRelated Recipes Inputs: Introduction ","description":"","tags":null,"title":"Input Actions","uri":"/godot_recipes/4.x/input/input_actions/index.html"},{"content":"Problem You need a 3D camera that smoothly follows a target (interpolates).\nSolution Info Godot’s built-in InterpolatedCamera node is deprecated and will be removed in the release of Godot 4.0.\nAttach the script below to a Camera3D node in your scene. The three export properties let you choose:\nlerp_speed - the camera’s movement speed. Lower values result in a “lazier” camera. target - choose the camera’s target node. offset - position of the camera relative to the target. See below for some examples of the camera in action.\nextends Camera3D @export var lerp_speed = 3.0 @export var target: Node3D @export var offset = Vector3.ZERO func _physics_process(delta): if !target: return var target_xform = target.global_transform.translated_local(offset) global_transform = global_transform.interpolate_with(target_xform, lerp_speed * delta) look_at(target.global_transform.origin, target.transform.basis.y) In the _physics_process() function we interpolate the camera’s position with the target’s (plus offset).\nExamples lerp_speed: 3.0 offset: (0, 7, 5) ","description":"","tags":null,"title":"Interpolated Camera","uri":"/godot_recipes/4.x/3d/interpolated_camera/index.html"},{"content":" GDScript GDScript is Godot’s built-in scripting language. Its syntax is based on Python, so if you’re familiar with that language, you’ll feel right at home. In this chapter, we’ll introduce the language and get you up to speed with how it works.\nUpdating to Godot 4.0 We’re working on a new version of Godot 101 for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: Getting started ","description":"","tags":null,"title":"Introduction to GDScript","uri":"/godot_recipes/4.x/g101/gdscript/index.html"},{"content":" Know Your Nodes In the “Know Your Nodes” series, we go in-depth with a single one of Godot’s nodes. Learn what makes it tick and see some examples of how it’s used.\nIn this section: RayCast2D ","description":"","tags":null,"title":"Know Your Nodes","uri":"/godot_recipes/4.x/kyn/index.html"},{"content":"Problem You want to detect mouse input.\nSolution InputEventMouse is the base class for mouse events. It contains position and global_position properties. Inheriting from it are two classes: InputEventMouseButton and InputEventMouseMotion.\nNote You can assign mouse button events in the InputMap, so you can use them with is_action_pressed().\nInputEventMouseButton @GlobalScope.ButtonList contains a list of BUTTON_* constants for each possible button, which will be reported in the event’s button_index property. Note that the scrollwheel also counts as a button - two buttons, to be precise, with both BUTTON_WHEEL_UP and BUTTON_WHEEL_DOWN being separate events.\nTip Unlike regular buttons, mouse wheel clicks only produce pressed events. There is no concept of a mouse wheel click being “released”.\nfunc _unhandled_input(event): if event is InputEventMouseButton: if event.button_index == BUTTON_LEFT: if event.pressed: print(\"Left button was clicked at \", event.position) else: print(\"Left button was released\") if event.button_index == BUTTON_WHEEL_DOWN: print(\"Wheel down\") InputEventMouseMotion These events occur whenever the mouse moves. You can find the distance moved (in screen coordinates) with the relative property.\nHere’s an example using mouse movement to rotate a 3D character:\n# Converts mouse movement (pixels) to rotation (radians). var mouse_sensitivity = 0.002 func _unhandled_input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) ","description":"","tags":null,"title":"Mouse Input","uri":"/godot_recipes/4.x/input/mouse_input/index.html"},{"content":" Info Many thanks to @TheDuriel on the Godot Discord for the original diagram that inspired this article. Save this and keep it handy.\nProblem Your project has started getting complex. You have multiple scenes, instances, and a lot of nodes. You’ve probably found yourself writing code like the following:\nget_node(\"../../SomeNode/SomeOtherNode\") get_parent().get_parent().get_node(\"SomeNode\") get_tree().get_root().get_node(\"SomeNode/SomeOtherNode\") If you do this, you’ll soon find that node references like this break easily. As soon as you change one thing about your scene tree, none of those references may be valid anymore.\nCommunication between nodes and scenes doesn’t have to be complicated. There is a better way.\nSolution As a general rule, nodes should manage their children, not the other way around. If you’re using get_parent() or get_node(\"..\"), then you’re probably headed for trouble. Node paths like this are brittle, meaning they can break easily. The three main problems with this arrangement:\nYou can’t test a scene independently. If you run the scene by itself or in a test scene that doesn’t have the exact same node setup, get_node() will cause a crash.\nYou can’t change things easily. If you decide to rearrange or redesign your tree, paths will no longer be valid.\nReady order is children-first, parent-last. This means that trying to access a parent’s property in a node’s _ready() can fail because the parent isn’t ready yet.\nTip See Understanding tree order for an explanation of how nodes enter the tree and become ready.\nGenerally speaking, a node or scene should be able to be instanced anywhere in your game, and it should make no assumptions about what its parent is going to be.\nWe’ll go into detailed examples later in this tutorial, but for now, here’s the “golden rule” of node communication:\nCall down, signal up.\nIf a node is calling a child (i.e. going “down” the tree), then get_node() is appropriate.\nIf a node needs to communicate “up” the tree, it should probably use a signal.\nIf you keep this rule in mind when designing your scene setup, you’ll be well on your way to a maintainable, well-organized project. And you’ll avoid using the cumbersome node paths that lead to problems.\nNow, let’s look at each of these strategies along with some examples.\n1. Using get_node() get_node() traverses the scene tree using a given path to find the named node.\nTip See Understanding node paths for a more detailed explanation of node paths.\nget_node() example Let’s consider the following common configuration:\nThe script in the Player node needs to notify the AnimatedSprite2D which animation to play, based on the player’s movement. In this situation, get_node() works well:\nextends CharacterBody2D func _process(delta): if speed \u003e 0: get_node(\"AnimatedSprite2D\").play(\"run\") else: get_node(\"AnimatedSprite2D\").play(\"idle\") Tip In GDScript you can use $ as a shorthand for get_node(), writing $AnimatedSprite2D instead.\n2. Using signals Signals should be used to call functions on nodes that are higher in the tree or at the same level (i.e. “siblings”).\nYou can connect a signal in the editor (most often for nodes that exist before the game starts) or in code (for nodes that you’re instancing at runtime). The syntax for connecting a signal is:\nsignal_name.connect(target_node.target_function)\nLooking at this, you may be thinking “Wait, if I’m connecting to a sibling, won’t I need a node paths like ../Sibling?”. While you could do this, it breaks our rule above. The answer to this puzzle is to make sure that connections are made by the common parent.\nFollowing the rule of calling down the tree, a node that’s a common parent to the signaling and receiving nodes will by definition know where they are and be ready after both of them.\nSignal example A very common use case for signals is updating your UI. Whenever the player’s health variable changes, you want to update a Label or ProgressBar display. However, your UI nodes are completely separated from your player (as they should be). The player knows nothing about where those nodes are and how to find them.\nHere’s our example setup:\nNote that the UI is an instanced scene, we’re just showing the contained nodes. This is where you often see things like get_node(\"../UI/VBoxContainer/HBoxContainer/Label).text = str(health), which is what we want to avoid.\nInstead the player emits a health_changed signal whenever it adds/loses health. We need to send that signal to the UI’s update_health() function, which handles setting the Label value. In the Player script we use this code whenever the player’s health is changed:\nhealth_changed.emit(health) In the UI script we have:\nonready var label = $VBoxContainer/HBoxContainer/Label func update_health(value): label.text = str(value) Now we just need to connect the signal to the function. The perfect place to do that is in World, which is the common parent, and knows where both nodes are:\nfunc _ready(): $Player.health_changed.connect($UI.update_health) 3. Using groups Groups are another way to decouple, especially when you have a lot of similar objects that need to do the same thing. A node can be added to any number of groups and membership can be changed dynamically at any time with add_to_group() and remove_from_group().\nA common misconception about groups is that they are some kind of object or array that “contains” node references. Groups are a tagging system. A node is “in” a group if it has that tag assigned from it. The SceneTree keeps track of the tags and has functions like get_nodes_in_group() to help you find all nodes with a particular tag.\nGroup example Let’s consider a Galaga-style space shooter where you have a lots of enemies flying around. These enemies may have different types and behaviors. You’d like to add a “smart bomb” upgrade that, when activated, destroys all enemies on the screen. Using groups, you can implement this with a minimal amount of code.\nFirst, add all enemies to an “enemies” group. You can do this in the editor using the “Node” tab:\nYou can also add nodes to the group in your script:\nfunc _ready(): add_to_group(\"enemies\") Let’s assume every enemy has an explode() function that handles what happens when it dies (playing an animation, spawning dropped items, etc). Now that every enemy is in the group, we can implement our smart bomb function like this:\nfunc activate_smart_bomb(): get_tree().call_group(\"enemies\", \"explode\") 4. Using owner owner is a Node property that’s set automatically when you save a scene. Every node in that scene will have its owner set to the scene’s root node. This makes for a convenient way to connect child signals up to the main node.\nowner example In a complex UI, you often find yourself with a very deep, nested hierarchy of containers and controls. Nodes that the user interacts with, such as Button, emit signals, and you may want to connect those signals to the script on the UI’s root node.\nHere’s an example setup:\nThe script on the root CenterContainer has the following function, which we want to call whenever any button is pressed:\nextends CenterContainer func _on_button_pressed(button_name): print(button_name, \" was pressed\") The buttons here are instances of a Button scene, representing an object which may contain dynamic code that sets the button’s text or other properties. Or perhaps you have buttons that are dynamically added/removed from the container depending on the game state. Regardless, all we need to connect the button’s signal is the following:\nextends Button func _ready(): pressed.connect(owner._on_button_pressed.bind(name)) No matter where you place the buttons in the tree - if you add more containers, for example - the CenterContainer remains the owner.\nRelated recipes Understanding tree order Understanding node paths ","description":"","tags":null,"title":"Node communication (the right way)","uri":"/godot_recipes/4.x/basics/node_communication/index.html"},{"content":"Problem You want a rigid body to rotate smoothly to look at a target.\nSolution Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc.\nTo rotate a body, we need to apply a rotational force - a torque. Once the body is rotating, we want the torque to get smaller as we get closer to the final rotation.\nThis is the perfect situation to use the dot product. Its sign will tell us whether the target is to the left/right, and its magnitude will tell us how far away from the target direction we’re pointing.\nTip See Vectors: Using Dot and Cross Product for a brief review of the dot product.\nextends RigidBody2D var angular_force = 50000 var target = position + Vector2.RIGHT func _physics_process(delta): var dir = transform.y.dot(position.direction_to(target)) constant_torque = dir * angular_force You may be wondering why we’re using the transform.y here, when transform.x is the body’s forward vector. Using transform.x, the dot product would be at its maximum when the body is directly pointing at the target, but we want the torque to be zero at that point. Using transform.y means that our torque will be higher when we’re not aligned with the target.\nSkip the Rigid Body Entirely You can avoid all of this entirely by not rotating your rigid body at all! Instead, change the child sprite’s rotation to point at the target. You can use lerp() or a Tween to make the rotation as smooth as you wish.\nIn many cases, this will be a great solution. Remember, the underlying body’s orientation doesn’t have to match the attached sprite!\nRelated recipes Vectors: Using Dot and Cross Product ","description":"","tags":null,"title":"RigidBody2D: Look at Target","uri":"/godot_recipes/4.x/physics/smooth_rigid_rotate/index.html"},{"content":"Problem You want to shoot projectiles from your player/mob/etc..\nSolution Setting up the bullet First, we’ll set up a “bullet” object that we can instance. Here are the nodes we’ll use:\nArea2D: Bullet Sprite2D CollisionShape2D For the Sprite2D’s texture, you can use any image you like. Here’s an example one:\nSet up the nodes and configure the sprite and collision shape. If your texture is oriented pointing up, like the one above, make sure to rotate the Sprite node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.\nAdd a script and connect the Area2D’s body_entered signal.\nextends Area2D var speed = 750 func _physics_process(delta): position += transform.x * speed * delta func _on_Bullet_body_entered(body): if body.is_in_group(\"mobs\"): body.queue_free() queue_free() For this example, we’ll remove the bullet if it hits anything at all. We’ll also delete anything tagged in the “mobs” group that it hits.\nShooting We need to set up a spawn location for the bullets. Add a Marker2D and place it where you want the bullets to spawn. Here’s an example, placed at the barrel of the gun. I’ve named it “Muzzle”.\nNotice that as the player rotates, the Muzzle’s transform remains oriented the same way relative to the gun. This will be very convenient when spawning the bullets, as they can use the transform to get the proper position and direction. We just set the new bullet’s transform equal to the muzzle’s.\nTip This will work for any character type, not just the “rotate-and-move” style shown here. Just attach the Marker2D where you want the bullets to spawn.\nIn the character’s script we add a variable to hold the bullet scene for instancing:\n@export var Bullet : PackedScene And check for our defined input action:\nif Input.is_action_just_pressed(\"shoot\"): shoot() Now in our shoot() function we can instance a bullet and add it to the tree. A common mistake is to add the bullet as a child of the player:\nfunc shoot(): var b = Bullet.instantiate() add_child(b) b.transform = $Muzzle.transform The problem here is that since the bullets are children of the player, they are affected when the player moves or rotates.\nTo fix this, we should make sure the bullets are added to the world instead. In this case, we’ll use owner, which refers to the root node of the scene the player is in. Note that we also need to use the muzzle’s global transform, or else the bullet would not be where we expected.\nfunc shoot(): var b = Bullet.instantiate() owner.add_child(b) b.transform = $Muzzle.global_transform Related recipes Gamedev Math: transforms Download This Project Download the project code here: https://github.com/godotrecipes/2d_shooting\n","description":"","tags":null,"title":"Shooting projectiles","uri":"/godot_recipes/4.x/2d/2d_shooting/index.html"},{"content":"Project Manager The Project Manager is the first thing you’ll see when opening Godot.\nIn this window you can see a list of your Godot projects. You can choose an existing project and click “Run” to play the game or click “Edit” to work on it in the Godot editor. Since you probably don’t have any projects yet, let’s start by clicking the “New Project” button.\nHere you can give the project a name and create a folder to store it in.\nNote Every Godot project is contained in its own folder. This has many benefits, including making it easy to move, share, and backup projects. It also means that all the project’s files (images, sounds, etc.) must be in the project folder.\nWhen you’re naming your project, try to choose a name that describes the project. “New Game Project #23” is not going to help you remember what that project was. You should also think about compatibility: some operating systems are case-sensitive, and some are not. This can lead to problems if you move or share your project from one computer to another. For this reason, many programmers develop a standardized naming scheme. For example: “No spaces, use ‘_’ between words.”\nLet’s name this new project “getting_started”. Type this name, click Create Folder, and then click Create \u0026 Edit.\nYou’re now looking at the Godot editor window. This is where you’ll spend most of your time when working in Godot. The editor is divided into sections.\nViewport: This is where you’ll see the parts of your game as you’re working on them. Workspaces: At the center-top, you can switch between working in the 2D, 3D, or Script workspaces. You start in 3D. Playtest Buttons: These buttons let you launch and control your game when testing. Docks/Tabs: On both sides are a number of docks where you can view game items and set their properties. Bottom Panel: Here, you’ll see context-specific information for various tools. The most important one to note first is the Output panel, where you’ll see any error or informational messages when your game is running. Project Settings Now we’ve talked about the main parts of the Godot window and how they work, let’s spend a little time talking about our Project settings. Usually one of the first tasks when starting a new project is make sure it’s all set up correctly.\nSo let’s click on Project in the menu and select Project Settings.\nThis is the Project settings window. On the left is a list of categories. For most projects, the default settings will be fine, and you shouldn’t worry about changing them unless you have a very specific need. For now, we’re just going to look at two of the sections. First, Application/Config.\nIn here, you can set your game’s title, choose which scene is the “main scene” (more about that in a bit), and change the icon.\nSecond, let’s look at the Display section. This is where you set up your game’s display. width \u0026 height let you set the size of the game window. If, for example, you were making a mobile game, you’d want to set this to the resolution and proportions of your target device. There are also settings for scaling, stretching, fullscreen mode, and more. For now, we’ll leave the default size - later on we’ll talk about how to adjust these to get our game running on different devices.\nThere are also some tabs across the top. We’ve been looking at the General tab. I’ll also point out briefly, the Input Map. This is where you can define different input actions for keyboard control, gamepad, mouse, and so on. In your game, you’ll just worry about the action, not what individual key or button was pressed. This is a very powerful and flexible way of handling player input.\nWe also have localization options, if you plan to support multiple languages. Autoloading, which we’ll get to later, and plugins. The Godot community has created a variety of useful plugins that you can download and add to supply more features, different tools, and so on.\nWe’ll come back to the project settings window later. Let’s close it for now and we’re ready to move on to the next step: working with nodes.\n","description":"","tags":null,"title":"The Godot Editor: Finding your way around","uri":"/godot_recipes/4.x/g101/start/101_02/index.html"},{"content":"Problem It’s probably the most common problem seen in the Godot help channels: an invalid node reference. Most often, it appears as the following error message:\nInvalid get index ‘position’ (on base: ’null instance’).\nSolution It’s that last part, the “null instance”, that’s the source of this problem, and the main source of confusion for Godot beginners.\nThe way to avoid this problem is to understand the concept of node paths.\nUnderstanding node paths The scene tree is made of nodes, which are connected together in parent-child relationships. A node path is the path it takes to get from one node to another by moving through this tree.\nAs an example, let’s take a simple “Player” scene:\nThe script for this scene is on the Player node. If the script needs to call play() on the AnimatedSprite node, it needs a reference to that node:\nget_node(\"AnimatedSprite\").play() The argument of the get_node() function is a string representing the path to the desired node. In this case, it’s a child of the node the script is on. If the path you give it is invalid, you’ll get the dreaded null instance error (as well as “Node not found”).\nGetting a node reference with get_node() is such a common situation that GDScript has a shortcut for it:\n$AnimatedSprite.play() Info get_node() returns a reference to the desired node.\nLet’s look at a more complex scene tree:\nIf the script on Main needs to access ScoreLabel it can do so with this path:\nget_node(\"HUD/ScoreLabel\").text = \"0\" # or using the shortcut: $HUD/ScoreLabel.text = \"0\" Tip When using $ notation, the Godot editor will autocomplete paths for you. You can also right-click on a node in the Scene tab and choose “Copy Node Path”.\nWhat if the node you want to access is higher in the tree? You can use get_parent() or \"..\" to reference the parent node. In the above example tree, to get the Player node from the ScoreLabel:\nget_node(\"../../Player\") Let’s break that down. The path \"../../Player\" means “get the node that’s up one level (HUD), then one more level (Main), then its child Player”.\nTip Does this seem familiar? Node paths work exactly like directory paths in your operating system. The / character indicates the parent-child relationship, and .. means “up one level”.\nRelative vs absolute paths The above examples all use relative paths - meaning they start at the current node and follow the path to the destination. Node paths can also be absolute, starting from the root node of the scene.\nFor example, the absolute path to the player node is:\nget_node(\"/root/Main/Player\") /root, which can also be accessed with get_tree().root is not the root node of your scene. It’s the Viewport node that is always present by default in the SceneTree.\nA warning While the above examples work just fine, there are some things you should be aware of that may cause problems later. Imagine the following situation: the Player node has a health property, which you want to display in a HealthBar node somewhere in your UI. You might write something like this in the player’s script:\nfunc take_damage(amount): health -= amount get_node(\"../Main/UI/HealthBar\").text = str(health) While this may work fine at first, it is brittle, meaning it can break easily. There are two main problems with this kind of arrangement:\nYou can’t test the player scene independently. If you run the player scene by itself or in a test scene that doesn’t have a UI, the get_node() line will cause a crash. You can’t change your UI. If you decide to rearrange or redesign your UI, the path will no longer be valid and you have to change it. For this reason, you should try to avoid using node paths that go up the scene tree. In the above situation, if the player instead emitted a signal when the health changed, the UI could listen for that signal to update itself. You could then rearrange and separate nodes without fear of breaking your game.\nWrapping up Once you understand how to use node paths, you’ll see how easy it is to reference any node you need. And put a stop to seeing those null instance error messages.\n","description":"","tags":null,"title":"Understanding node paths","uri":"/godot_recipes/4.x/basics/getting_nodes/index.html"},{"content":"Before reading this, make sure you have an understanding of vectors and how they’re used in game development. If you don’t, I recommend you read this introduction I wrote for the Godot documentation: Vector Math.\n2D Transforms In 2D space, we use the familiar X-Y coordinate plane. Remember that in Godot, as in most computer graphics applications, the Y axis points downward:\nTo begin, let’s consider this spaceship floating in space:\nThe ship is pointing in the same direction as the X axis. If we wanted it to move forward, we could add to its X coordinate and it would move to the right:\nposition += Vector2(10, 0) But what happens when the ship rotates?\nHow do we move the ship forward now? If you remember Trigonometry from school, you might be starting to think about angles, sine and cosine and doing something like position += Vector2(10 * cos(angle), 10 * sin(angle)). While this would work, there’s a much more convenient way: the Transform.\nLet’s look at the rotated ship again, but this time, let’s also imagine that the ship has its own X and Y axes that it carries with it, independent of the global axes:\nThese “local” axes are contained in the object’s transform.\nKnowing this, we can move the ship forward by moving it along its own X axis and we won’t have to worry about angles and trig functions. To do this in Godot, we can use the transform property, which is available to all Node2D derived nodes.\nposition += transform.x * 10 This code says “Add the transform’s x vector multiplied by 10.” Let’s break down what that means. The transform contains x and y properties that represent those local axes. They are unit vectors, which means their length is 1. Another term for unit vector is direction vector. They tell us the direction the ship’s x axis is pointing. We then multiply by 10 to scale it to a longer distance.\nTip The transform property of a node is relative to its parent node. If you need to get the global value, it’s available in global_transform.\nIn addition to the local axes, the transform also contains a component called the origin. The origin represents the translation, or change in position.\nIn this picture, the blue vector is the transform.origin. It is equal to the object’s position vector.\nConverting Between Local and Global Space You can convert coordinates from local to global by applying the transform. For convenience, Node2D and Spatial include helper functions for this: to_local() and to_global():\nvar global_position = to_global(local_position) Let’s use the example of an object in the 2D plane and convert mouse clicks (global space) into coordinates relative to the object:\nextends Sprite func _unhandled_input(event): if event is InputEventMouseButton and event.pressed: if event.button_index == BUTTON_LEFT: printt(event.position, to_local(event.position)) See the Transform2D docs for a list of the available properties and methods.\n3D Transforms In 3D space, the concept of transforms applies in the same way as in 2D. In fact, it becomes even more necessary, as using angles in 3D can lead to a variety of problems, as we’ll see in a bit.\n3D nodes inherit from the base node Node3D, which contains the transform information. The 3D transform requires more information than the 2D version. Position is still held in the origin property, but rotation is in a property called basis, which contains three unit vectors representing the body’s local X, Y, and Z axes.\nWhen you select a 3D node in the editor, the gizmo that appears allows you to manipulate the transform.\nLocal Space Mode In the editor, you can see and manipulate the body’s local orientation by clicking the “Local Space Mode” button. When in this mode, the 3 colored axis lines represent the body’s local basis axes.\nAs in 2D, we can use the local axes to move an object forward. In Godot’s 3D orientation (Y-up), this means that by default the body’s -Z axis is the forward direction. To move forward:\nposition += -transform.basis.z * speed * delta Tip Godot has default vector values defined, for example: Vector3.FORWARD == Vector3(0, 0, -1). See Vector2 and Vector3 for details.\n","description":"","tags":null,"title":"Transforms","uri":"/godot_recipes/4.x/math/transforms/index.html"},{"content":" 2D Tips, tricks, and tutorials on the 2D side of game development.\nIn this section: Entering/Exiting the screen Platform character Screen wrap Top-down movement Grid-based movement Shooting projectiles Car steering 8-Directional Movement/Animation Using Y-Sort Coyote Time Moving Platforms Pathfinding on a 2D Grid Multitarget Camera ","description":"","tags":null,"title":"2D","uri":"/godot_recipes/4.x/2d/index.html"},{"content":"Problem You need to add actions to the InputMap at runtime.\nSolution Typically, you’ll add actions to the InputMap via Project Settings, as shown in Recipe: Input Actions. However, you may find yourself needing to add one or more actions directly in a script. The InputMap singleton has methods to help you do this.\nHere’s an example that would add a new action called “attack” using the space key:\nfunc _ready(): InputMap.add_action(\"attack\") var ev = InputEventKey.new() ev.keycode = KEY_SPACE InputMap.action_add_event(\"attack\", ev) If you also wanted to add the left mouse button to the same action:\nev = InputEventMouseButton.new() ev.button_index = MOUSE_BUTTON_LEFT InputMap.action_add_event(\"attack\", ev) Note InputMap.add_action() will produce an error if the action already exists. You should check first with InputMap.has_action() before attempting to add a new action.\nPractical Example Let’s say you’ve made the platform character from Recipe: Platform character and you want to re-use it in another project. If you saved the scene, script, and assets in a single folder, you need only copy that folder to your new project. But you’d still need to edit the Input Map in order for the inputs to work.\nInstead, you could add the following code to the player script and be sure that the necessary input actions will be added automatically:\nvar controls = {\"walk_right\": [KEY_RIGHT, KEY_D], \"walk_left\": [KEY_LEFT, KEY_A], \"jump\": [KEY_UP, KEY_W, KEY_SPACE]} func _ready(): add_inputs() func add_inputs(): var ev for action in controls: if not InputMap.has_action(action): InputMap.add_action(action) for key in controls[action]: ev = InputEventKey.new() ev.keycode = key InputMap.action_add_event(action, ev) Related recipes Input Actions Platform Character ","description":"","tags":null,"title":"Adding Input Actions in code","uri":"/godot_recipes/4.x/input/custom_actions/index.html"},{"content":"Problem You want to hide the mouse cursor and keep the mouse from leaving the game window. This is common in many 3D games (and some 2D ones).\nSolution You can set the mouse state using Input.mouse_mode. There are four possible mouse modes:\nMOUSE_MODE_VISIBLE: The mouse is visible and can move freely into and out of the window. This is the default state.\nMOUSE_MODE_HIDDEN: The mouse cursor is invisible, but the mouse can still move outside the window.\nMOUSE_MODE_CAPTURED: The mouse cursor is hidden and the mouse is unable to leave the game window.\nMOUSE_MODE_CONFINED: The mouse is visible, but cannot leave the game window.\n“Captured” is the most commonly used option. You can set the mouse mode at runtime using:\nfunc _ready(): Input.mouse_mode = Input.MOUSE_MODE_CAPTURED When the mouse is captured, mouse input events will still be passed as normal. However, you will find there is a problem. If you want to close the game or switch to another window, you can’t. For this reason, you will want to also include a way to “release” the mouse. For example, to release when the player pressed the Escape key:\nfunc _input(event): if event.is_action_pressed(\"ui_cancel\"): Input.mouse_mode = Input.MOUSE_MODE_VISIBLE So that the game doesn’t respond to mouse movement when you’re in another window, you can test for the capture state in your character controller using:\nif Input.mouse_mode == Input.MOUSE_MODE_CAPTURED: Once the mouse is released, that leaves the need to re-capture it to continue playing. Assuming you have an event in the Input Map for a mouse click, you can do the following:\nif event.is_action_pressed(\"click\"): if Input.mouse_mode == Input.MOUSE_MODE_VISIBLE: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED Since you may also be using a mouse click to shoot or perform some other action, it’s probably a good idea to stop the event from propagating. Add this after setting the mouse mode:\nget_tree().set_input_as_handled() ","description":"","tags":null,"title":"Capturing the Mouse","uri":"/godot_recipes/4.x/input/mouse_capture/index.html"},{"content":"Problem You need to create a 2D top-down car controller.\nSolution When approaching this problem, beginners often wind up creating something that handles nothing like a real car. Some common mistakes you’ll find in amateur car games:\nA car doesn’t rotate around its center. Put another way, a car’s rear wheels don’t slide side-to-side. (Unless it’s drifting, but we’ll talk about that later.) A car can only turn when it’s moving - it can’t spin in place. A car isn’t a train; it’s not on rails. Turning at high speeds should involve some sliding (drifting). There are many approaches to 2D car physics, mainly depending on how “realistic” you want to be. For this solution, we’re going for an “arcade” level of realism, meaning we’ll prioritize action over realism.\nNote The method below is based on the algorithm found here: http://engineeringdotnet.blogspot.com/2010/04/simple-2d-car-physics-in-games.html\nThe recipe below is broken into 5 parts, each adding a different feature to the car’s movement. Feel free to mix-and-match for your needs.\nScene setup Here’s the car scene setup:\nCharacterBody2D Sprite2D CollisionShape2D Camera2D Add whatever sprite texture you like. For this demo, we’ll use art from Kenney’s Racing Pack. CapsuleShape2D is a good choice for the collision, so that the car won’t have sharp corners to get caught on obstacles.\nWe’ll also use four input actions: “steer_right”, “steer_left”, “accelerate”, and “brake” - set them to whatever key inputs you prefer.\nPart 1: Movement The first step is to code the movement based on the algorithm described above.\nStart with a few variables:\nextends CharacterBody2D var wheel_base = 70 # Distance from front to rear wheel var steering_angle = 15 # Amount that front wheel turns, in degrees var steer_direction Set wheelbase to a value that works with your sprite.\nsteer_direction will be the amount that the wheels are turned.\nNote Since we’re using keyboard controls, turning is all-or-nothing. If you’re using an analog joystick, you can instead vary this value based on the distance the stick moves.\nfunc _physics_process(delta): get_input() calculate_steering(delta) move_and_slide() Each frame, we need to check for input and calculate steering. Then we pass the resulting velocity to move_and_slide(). We’ll define those two function next:\nfunc get_input(): var turn = Input.get_axis(\"steer_left\", \"steer_right\") steer_direction = turn * deg_to_rad(steering_angle) velocity = Vector2.ZERO if Input.is_action_pressed(\"accelerate\"): velocity = transform.x * 500 Here we check for user input and set the velocity. Note: the speed of 500 is temporary so that we can test movement. We’ll address it in the next part.\nHere is where we implement the algorithm from the link:\nfunc calculate_steering(delta): # 1. Find the wheel positions var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 # 2. Move the wheels forward rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_direction) * delta # 3. Find the new direction vector var new_heading = rear_wheel.direction_to(front_wheel) # 4. Set the velocity and rotation to the new direction velocity = new_heading * velocity.length() rotation = new_heading.angle() Run the project and the car should move and turn. It’s still very unnatural though - the car starts and stops instantly. To fix that, we’ll add acceleration into the calculation.\nPart 2: Acceleration We’ll need another setting variable and one to track the car’s overall acceleration:\nvar engine_power = 900 # Forward acceleration force. var acceleration = Vector2.ZERO Change the input code to apply acceleration instead of directly changing the car’s velocity.\nfunc get_input(): var turn = Input.get_axis(\"steer_left\", \"steer_right\") steer_direction = turn * deg_to_rad(steering_angle) if Input.is_action_pressed(\"accelerate\"): acceleration = transform.x * engine_power Once we’ve got our acceleration, we can apply it to the velocity like so:\nfunc _physics_process(delta): acceleration = Vector2.ZERO get_input() calculate_steering(delta) velocity += acceleration * delta move_and_slide() Now when you run, the car should gradually increase its speed. Careful: we don’t have any way to slow down yet!\nPart 3: Friction/drag A car experiences two different deceleration forces: friction and drag.\nFriction is the force applied by the ground. It’s very high if driving on sand, but very low if driving on ice. Friction is proportional to velocity - the faster you’re going the stronger the force.\nDrag is the force resulting from wind resistance. It’s based on the car’s cross-section - a large truck or van experiences more drag than a sleek race car. Drag is proportional to the velocity squared.\nThis means that friction is more significant when moving slowly, but drag becomes dominant at high speeds. We’ll add both of these forces to our calculation. As a bonus, the values of these quantities will also give our car a maximum speed - the point where the force from the engine can’t overcome the drag force any longer.\nHere are our starting values for these quantities:\nvar friction = -55 var drag = -0.06 As you can see in this graph, these values mean that at a speed of 600 the drag force overcomes the friction force.\nYou can play with the values here to see how they change: https://www.desmos.com/calculator/e4ayu3xkip\nIn _physics_process() we’ll call a function to calculate the current friction and apply it to the acceleration force.\nfunc _physics_process(delta): acceleration = Vector2.ZERO get_input() apply_friction(delta) calculate_steering(delta) velocity += acceleration * delta velocity = move_and_slide(velocity) func apply_friction(delta): if acceleration == Vector2.ZERO and velocity.length() \u003c 50: velocity = Vector2.ZERO var friction_force = velocity * friction * delta var drag_force = velocity * velocity.length() * drag * delta acceleration += drag_force + friction_force First, we’ll set a minimum speed. This will ensure that the car doesn’t keep creeping forward at very low speeds as friction never quite brings the velocity to zero.\nThen we calculate the two forces and add them to the total acceleration. Since they’re both negative, they’ll affect the car in the opposite direction.\nPart 4: Reverse/Brake We’ll need two more settings variables:\nvar braking = -450 var max_speed_reverse = 250 Add the input to get_input():\nif Input.is_action_pressed(\"brake\"): acceleration = transform.x * braking This is fine for coming to a stop, but we also want to be able to put the car in reverse. Currently, that won’t work, because the acceleration is always being applied in the “heading” direction, which is forward. When we’re reversing, we need to accelerate backward.\nfunc calculate_steering(delta): var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_angle) * delta var new_heading = (front_wheel - rear_wheel).normalized() var d = new_heading.dot(velocity.normalized()) if d \u003e 0: velocity = new_heading * velocity.length() if d \u003c 0: velocity = -new_heading * min(velocity.length(), max_speed_reverse) rotation = new_heading.angle() We can find whether we’re accelerating forward or backward using the dot product. If the two vectors are aligned, the result will be greater than 0. If the movement is in the opposite direction the car’s facing, then the dot product will be less than 0 and we must be moving backward.\nPart 5: Drift/slide We could stop here and you’d have a satisfactory driving experience. However, the car still feels like it’s “on rails”. Even at top speed, the turns are perfect, as if the tires have perfect “grip”.\nAt high speeds (or even low ones, if desired), the turning force should cause the tires to slip and result in a fishtailing/sliding motion.\nvar slip_speed = 400 # Speed where traction is reduced var traction_fast = 2.5 # High-speed traction var traction_slow = 10 # Low-speed traction We’ll apply these values when calculating the steering. Currently, the velocity is instantly set to the new heading. Instead, we’ll use interpolation - lerp() - to cause it to only “turn” partway towards the new direction. The “traction” values will determine how “sticky” the tires are.\nfunc calculate_steering(delta): var rear_wheel = position - transform.x * wheel_base / 2.0 var front_wheel = position + transform.x * wheel_base / 2.0 rear_wheel += velocity * delta front_wheel += velocity.rotated(steer_angle) * delta var new_heading = (front_wheel - rear_wheel).normalized() # choose which traction value to use - at lower speeds, slip should be low var traction = traction_slow if velocity.length() \u003e slip_speed: traction = traction_fast var d = new_heading.dot(velocity.normalized()) if d \u003e 0: velocity = lerp(velocity, new_heading * velocity.length(), traction * delta) if d \u003c 0: velocity = -new_heading * min(velocity.length(), max_speed_reverse) rotation = new_heading.angle() Here, we select which traction value to use and apply lerp() to the velocity.\nAdjustments At this point, we have a large number of settings that control the car’s behavior. Adjusting them can drastically change how the car drives. To make experimenting with different values easier, download the project for this recipe below. When you run the game, you’ll see a set of sliders you can use to change the car’s behavior as you drive (press \u003cTab\u003e to show/hide the slider panel).\nRelated recipes Gamedev Math: Interpolation Download This Project Download the project code here: https://github.com/godotrecipes/2d_car_steering\n","description":"","tags":null,"title":"Car steering","uri":"/godot_recipes/4.x/2d/car_steering/index.html"},{"content":"In the last section, we configured the project and downloaded the game art. Now we’re ready to start coding - starting with the player-controlled ship.\nAdding a script Writing scripts and attaching them to nodes and other objects is how you build behavior and game mechanics into your game. Our Player scene displays the ship, defines its collision hitbox, etc., but it can’t move, and nothing would happen if it collided. We’ll write code to add this functionality to the ship.\nSelect the Player node and click the Attach script button:\nYou don’t need to change any of the options on the Attach Node Script window, so just click Create and you’ll be taken to the script editor.\nLet’s look at the first line of the script, which has automatically been added.\nextends Area2D This line defines what type of object this script should be attached to. It means that the script will have access to all the functionality that an Area2D provides.\nYour extends line should always match the type of node the script is attached to.\nAccessing scripts A script on its own doesn’t do much of anything. Scripts define additional functionality for whatever object they’re attached to. You will never be accessing a variable in some script, you’ll be accessing a property of an object, which is defined by that script. This is a very important distinction.\nMovement We’ll start by making the ship move around the screen. Let’s start with some code that does the following:\nDetect what input(s) the player is pressing Move the ship in the direction of the input @export var speed = 150 func _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") position += input * speed * delta Let’s break this down line-by-line:\nAdding @export in front of a variable allows you to adjust its value in the Inspector. The _process() function is called once every frame by the engine. Any code we place in this function will be executed every frame. Input.get_vector() checks the pressed state of the four given inputs and produces a vector pointing in that direction. Finally, we move the ship’s position by adding that input vector, scaling it to the desired speed, and multipling by delta. Links to more information Understanding vectors: Vector Math What is delta? Understanding delta Run the scene by clicking the Run Current Scene button, and try moving around.\nStaying on screen One problem we have is that if you keep moving, you’ll go off the screen. We need to lock the player’s position property inside the bounds of the screen rectangle. Add this line at the top of the script:\n@onready var screensize = get_viewport_rect().size The @onready here tells Godot not to set the value of the screensize variable until the Player node has entered the scene tree. Effectively, it means “wait until the game starts”, because there’s no window to get the size of until the game is running.\nThe next step is to clamp the position within the bounds of that screensize rectangle. Vector2, which is what position is, has a clamp() method we can use. Put this line right after setting the position:\nfunc _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") position += input * speed * delta position = position.clamp(Vector2.ZERO, screensize) Run the scene again and try moving off the edges. You’ll notice that half of the ship still goes off screen. This is because the ship’s position is the center of the Sprite2D. Since we know our ship is 16x16, we can change the clamp() to include 8 extra pixels:\nposition = position.clamp(Vector2(8, 8), screensize - Vector2(8, 8)) Matching animation to direction Now that the ship is moving, we can choose the “tilted” ship images when moving left or right, as well as the matching “Booster” animation.\nTo tell which direction we’re moving, we can check the x value of the input vector. Depending on whether it’s positive (right), negative (left), or zero (not moving), we can choose the frame value of the Sprite2D and the animation of the AnimatedSprite2D.\nfunc _process(delta): var input = Input.get_vector(\"left\", \"right\", \"up\", \"down\") if input.x \u003e 0: $Ship.frame = 2 $Ship/Boosters.animation = \"right\" elif input.x \u003c 0: $Ship.frame = 0 $Ship/Boosters.animation = \"left\" else: $Ship.frame = 1 $Ship/Boosters.animation = \"forward\" position += input * speed * delta position = position.clamp(Vector2(8, 8), screensize-Vector2(8, 8)) Once again, play the scene and verify that the images change when moving left/right. Verify that everything works as intended before moving to the next step.\nThe next step will be to create the Bullet scene and let the player shoot.\nPrev Next ","description":"","tags":null,"title":"Coding the Player","uri":"/godot_recipes/4.x/games/first_2d/first_2d_03/index.html"},{"content":"In the last part, we covered how to import 3D objects and how to arrange them in a scene. In this installment, we’ll add more objects to the scene, including a user-controlled character.\nBuilding the Scene We’re going to continue using the Kenney Platformer Kit we downloaded in Part 2. Select all the block*.glb files and in the Import tab set their Root Type to StaticBody3D. Uncheck the Root Name property and click Reimport. Select blockLarge.glb and make a new inherited scene. Use the Create Single Convex Collision Sibling option on the mesh using the menu as you did in the last tutorial. Now you can save the scene - I recommend making a separate folder for this, as soon you’re going to have a bunch of scenes representing the differently shaped platform parts.\nOpen the scene from the previous step with the “Ground” plane and the crates. Delete the crates and add an instance of the large block. We want to be able to place these blocks so that they line up. To do this, select “Configure Snap” from the “Transform” menu at the top of the Viewport and set Translate Snap to 0.5. Then click on the “Snap Mode” button (or press the Y key). Now duplicate the block a few times and drag them to arrange.\nIf you like, go ahead and add scenes for some of the other platform blocks and arrange them into a pleasing level. Be creative!\nAdding a Character Now we’re going to make a character so we can walk around on the platforms. Open a new scene and start with a CharacterBody3D named “Character”. This PhysicsBody node behaves very much like its 2D equivalent (you’ve already done the 2D tutorials, right?). It has a move_and_slide() method that we’ll use to perform the movement and collision detection.\nAdd a capsule-shaped MeshInstance3D and a matching CollionShape3D. Remember, you can add a StandardMaterial3D to the mesh and set its Albedo/Color property to change the color.\nThe capsule is nice, but it’s going to be hard to tell what direction it’s facing. Let’s add another mesh, this time with a CylinderMesh3D shape. Set its Top Radius to 0.2, its Bottom Radius to 0.001 and its Height to 0.5, then its x rotation to -90 degrees. Now you have a nice cone shape. Arrange it so it’s pointing out from the body along the negative z axis. (You can tell which way is negative because the gizmo arrows point in the positive direction).\nIn this picture, we’ve also added two sphere meshes for eyes to give a little more character. Feel free to add whatever details you like.\nLet’s also add a Camera3D to the scene, so it will follow the player around. Position the camera behind and above the character, angling it down a bit. Click the “Preview” button to check the camera’s view.\nBefore we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:\nInput Action Key move_forward W move_back S strafe_right D strafe_left A jump Space Now let’s add a script to the body.\nextends CharacterBody3D var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var speed = 4.0 # movement speed var jump_speed = 6.0 # determines jump height var mouse_sensitivity = 0.002 # turning speed func get_input(): var input = Input.get_vector(\"strafe_left\", \"strafe_right\", \"move_forward\", \"move_back\") velocity.x = input.x * speed velocity.z = input.y * speed func _physics_process(delta): velocity.y += -gravity * delta get_input() move_and_slide() The code in _physics_process() is pretty straightforward: add gravity to accelerate in the positive Y direction (downward), call get_input() to check for input, and then use move_and_slide() to move in the direction of the velocity vector.\nIn get_input() we check to see which key is pressed and then move in that direction. Run the program and test:\nThis is all good, but we need to be able to rotate using the mouse. Add the following code to the character’s script:\nfunc _unhandled_input(event): if event is InputEventMouseMotion: rotate_y(-event.relative.x * mouse_sensitivity) This will convert any mouse motion in the x direction into a rotation around the y axis.\nRun the scene and confirm that moving the mouse rotates the character:\nHowever, there’s a problem. No matter which way we’re facing, pressing W moves us along the Z axis of the world. Our movement is using global coordinates, but we need to move in the object’s forward direction.\nThe Power of Transforms This is where transforms come in. A transform is a mathematical matrix that contains the object’s translation, rotation, and scale information all in one. In Godot it’s stored in the Transform data type. The position information is called the transform.origin and the orientation information is in the transform.basis.\nRemember how the 3D gizmo can be set to “Local Space Mode”? When in this mode, the gizmo’s X/Y/Z axes point along the object’s axes. This is the same as the basis of the transform. The basis contains three Vector3 objects called x, y, and z that represent these directions. We can use this to ensure that pressing the W key will always move us in the object’s forward direction.\nChange the get_input() function like so:\nfunc get_input(): var input = Input.get_vector(\"strafe_left\", \"strafe_right\", \"move_forward\", \"move_back\") var movement_dir = transform.basis * Vector3(input.x, 0, input.y) velocity.x = movement_dir.x * speed velocity.z = movement_dir.z * speed By multiplying the input vector by the transform.basis, we apply that transformation to the vector. Since the basis represents the object’s rotation, we’ve now converted forward and back to point along the object’s Z axis, and the strafe keys along its X.\nJumping Let’s add one more movement to the player: jumping.\nAdd these lines to the end of _unhandled_input():\nif event.is_action_pressed(\"jump\") and is_on_floor(): velocity.y = jump_speed Improving the camera You may have noticed that the if the character stands near an obstacle, the camera can “clip” inside the object, which doesn’t look nice. While coding a good 3D camera can be a complex topic on its own, we can use a built-in Godot node to get a pretty good solution.\nDelete the Camera3D from the character scene and add a SpringArm3D. This node can act as a moving arm that holds the camera while detecting collisions. It will move the camera closer if there’s an obstacle.\nIn its properties, set Spring Length to 5, and set its Position to (0, 1, 0), which is at the character’s head. Note the yellow line indicating the Spring Length. The camera will move along this line - at its end whenever possible, but moving closer if an obstacle is there.\nAdd back a Camera3D as a child of the SpringArm3D, and try running the game again. You can experiment with rotating the spring arm (around its x axis to point down slightly, for example) until you find something you like.\nWhat about first person? If you’re curious how you would do this in first person, see the Basic FPS Character recipe. You’ll notice several similarities with the 3rd person script we wrote above.\nWrapping Up In this tutorial you learned how to build a more complex scene, and how to write movement code for a user-controlled character. You also learned about transforms, which are a very important concept in 3D - you’re going to be using a lot in the future.\n","description":"","tags":null,"title":"Creating a 3D Character","uri":"/godot_recipes/4.x/g101/3d/101_3d_03/index.html"},{"content":"Nodes are the basic building blocks for creating games in Godot. A node is an object that can represent some kind of specialized game function. A given type of node might display graphics, play an animation, or represent a 3D model of an object. The node also contains a collection of properties, allowing you to customize its behavior. Which nodes you add to your project will depend on what functionality you need. It’s a modular system designed to give you flexibility in building your game objects.\nWorking with Nodes Nodes are objects, in the programming sense. They encapsulate data and behavior, and they can inherit properties from other nodes. Rather than use one of the default suggestions, let’s click the “Add/Create a New Node” button in the scene dock.\nHere you’ll see the whole hierarchy of node types available in the engine. For example, the nodes with the bluish icons all fall under the “Node2D” category, meaning they will all have the properties of a Node2D. More about that in a moment.\nThe list is long, and it would be frustrating to have to drill down every time to find the node you need. Instead, you can use the search function to find it using a small number of characters. We’re looking for the Sprite2D node, so I’ll just type “sp” and we’ll jump right to it. Click “Create” to add the node.\nNow we have this Sprite2D node in our Scene dock. Make sure it’s selected, and then look at the Inspector dock on the right side. Over here, you’ll see all the properties of whatever node you have selected. Notice that the properties are organized by where they come from. The Sprite2D node inherits from Node2D, which inherits from CanvasItem, which inherits from the plain old Node.\nOver in the viewport, the sprite doesn’t look like much. A sprite’s purpose is to display an image, or texture. As you can see in the Inspector, the Texture property is currently empty. Fortunately, every new Godot project comes with an image we can use: the Godot icon. Drag the icon from the Filesystem dock and drop it in the texture property.\nIn the Inspector, click to expand the “Transform” section, and type (50, 50) in the Position property.\nYou can also click and drag the sprite around in the viewport, and you’ll see the Position values changing as you move.\nOne important property of nodes is that they can be arranged in a parent-child hierarchy. Make sure you have the Sprite2D selected and press the add button again. Add another Sprite2D and also drag the icon into its texture.\nThis new sprite is a child of the first. This means that it’s “attached” to its parent. If the parent sprite moves, so will the child. Click on the child sprite and set its Position to (50, 50). Now click and drag the parent sprite to move it around the screen.\nNotice that the Position of the parent is changing as you move it around. Now check the child: it’s still (50, 50). That’s because its “Transform” properties are relative to its parent.\nScenes Grouping nodes together like this is a powerful tool, enabling you to construct complex objects out of node “building blocks”. For example, a “Player” node in your game might have many child nodes attached to it: a Sprite2D for display, an AnimationPlayer to animate it, a Camera2D to follow it around, and so on.\nA group of nodes arranged in a “tree” structure like this is called a Scene. In the next part, we’ll look at how you can use scenes to organize your game’s objects into independent parts that all work together. You’ll see this in practice was you work through the examples in later lessons.\n","description":"","tags":null,"title":"Nodes: Godot's building blocks","uri":"/godot_recipes/4.x/g101/start/101_03/index.html"},{"content":"Problem You need to implement shooting in an FPS, but moving individual projectiles is impractical.\nSolution Game physics engines often break down when trying to handle very fast-moving objects. The solution is to cast a ray from the shooter’s location and detect the first thing that would be hit.\nThere are two ways to approach raycasting in Godot: the RayCast3D node, or directly casting a ray in space using the physics engine. While they can both accomplish the same thing, each has its uses. The node method tends to be best for situations where you continuously want to check for collisions - a downward-facing ray to check if you’re on the floor, for example.\nWe’ll use the second method, querying the physics state, because we want to know, at the moment we press the “shoot” key, whether we’ve hit anything.\nNote This recipe assumes you already have a working FPS character controller and a world to move around in. If you don’t, see the Basic FPS Character recipe first.\nTo display what we’ve hit, add a CanvasLayer with a Label node to the FPSPlayer scene.\nWe’ll add an input check in the _input() function, which we’re already using to handle mouse input.\nif event.is_action_pressed(\"shoot\"): shoot() Then we’ll define the shoot() method. Whenever it’s called, we want to build a PhysicsRayQueryParameters3D object, which defines the start (position of the camera) and end (position of the camera projected forward by 100 meters) points of the ray. We’ll pass this to the physics engine using the direct_space_state of the world. If we get a returned value (a dictionary containing data about the collision), we’ll update the label so we can see what kind of object we hit.\nfunc shoot(): var space = get_world_3d().direct_space_state var query = PhysicsRayQueryParameters3D.create($Camera3D.global_position, $Camera3D.global_position - $Camera3D.global_transform.basis.z * 100) var collision = space.intersect_ray(query) if collision: $CanvasLayer/Label.text = collision.collider.name else: $CanvasLayer/Label.text = \"\" Related recipes Basic FPS Character Download This Project Download the project code here: https://github.com/godotrecipes/3d_shoot_raycasts\n","description":"","tags":[],"title":"Shooting with Raycasts","uri":"/godot_recipes/4.x/3d/shooting_raycasts/index.html"},{"content":"Problem The delta or “delta time” parameter is a frequently-misunderstood concept in game development. In this tutorial, we’ll explain how it’s used, the importance of frame-rate independent movement, and practical examples of its use in Godot.\nSolution To illustrate the problem, let’s consider a Sprite node moving across the screen. If our screen is 600 pixels wide and we want the sprite to take 5 seconds to cross the screen, we can use the following calculation to find the necessary speed:\n600 pixels / 5 seconds = 120 pixels/second We’ll move the sprite every frame using the _process() function. If the game is running at 60 frames per second, we can find the per-frame movement like so:\n120 pixels/second * 1/60 second/frame = 2 pixels/frame Tip Notice the units are consistent in all the calculations above. Always pay attention to the units in your calculations - it’ll save you from making mistakes.\nHere’s the necessary code:\nextends Node2D # Desired movement in pixels/frame var movement = Vector2(2, 0) func _process(delta): $Sprite.position += movement Run this code and you’ll see the sprite takes 5 seconds to cross the screen.\nMaybe. The trouble begins if there is something else occupying the computer’s time. This is called lag and can come from a variety of sources - the cause could be your code or even other applications running on your computer. If this happens, then the length of a frame might increase. As an extreme example, imagine that the frame rate is halved - each frame took 1/30 instead of 1/60 of a second. Moving at 2 px/frame, it’s now going to take twice as long for the sprite to reach the edge.\nEven small frame rate fluctuations will result in inconsistent movement speed. If this were a bullet or other fast-moving object, we wouldn’t want it slowing down like this. We need the movement to be frame rate independent.\nFixing the frame rate problem When using the _process() function, it automatically includes a parameter called delta that’s passed in from the engine (so does _physics_process(), which is used for physics-related code). This is a floating point value representing the length of time since the previous frame. Typically, this will be approximately 1/60 or 0.0167 seconds.\nWith this information, we can stop thinking about how much to move each frame, and only consider our desired speed in pixels/second (120 from the above calculation).\nMultiplying the engine’s delta value by this number will give us how many pixels to move each frame. The number will automatically adjust if the frame time fluctuates.\n# 60 frames/second 120 pixels/second * 1/60 second/frame = 2 pixels/frame # 30 frames/second 120 pixels/second * 1/30 second/frame = 4 pixels/frame Note that if the frame rate decreases by half (meaning the frame time doubles), then our per-frame movement must also double to keep the desired speed.\nLet’s change the code to use this calculation:\nextends Node2D # Desired movement in pixels/second. var movement = Vector2(120, 0) func _process(delta): $Sprite.position += movement * delta Now when running at 30 frames per second, the travel time is consistent:\nIf the frame rate gets very low, the movement is no longer smooth, but the time remains the same.\nUsing delta with motion equations What if your movement is more complex? The concept remains the same. Keep your units in seconds, not frames, and multiply by delta each frame.\nTip Working in pixels and seconds is much easier to conceptualize too, since it relates to how we measure these quantities in the real world. “Gravity is 100 pixels/second/second, so after the ball falls for 2 seconds, it’s traveling at 200 pixels/second.” If you’re working with frames, then you have to think about acceleration in units of pixels/frame/frame. Go ahead and try - it’s not very natural.\nFor example, if you are applying a gravity, that’s an acceleration - each frame it will increase the velocity by some amount. As in the above example, the velocity then changes the node’s position.\nTry adjusting delta and target_fps in the following code to see the effect:\nextends Node2D # Acceleration in pixels/sec/sec. var gravity = Vector2(0, 120) # Acceleration in pixels/frame/frame. var gravity_frame = Vector2(0, .033) # Velocity in pixels/sec or pixels/frame. var velocity = Vector2.ZERO var use_delta = false var target_fps = 60 func _ready(): Engine.target_fps = target_fps func _process(delta): if use_delta: velocity += gravity * delta $Sprite.position += velocity * delta else: velocity += gravity_frame $Sprite.position += velocity Note that we’re multiplying by our timestep each frame to update both velocity and position. Any quantity that is updated every frame should be multiplied by delta to ensure it changes independent or frame rate.\nUsing kinematic functions In the above examples, we’ve used a Sprite to keep things simple, updating the position every frame. If you’re using a kinematic body (in 2D or 3D), you’ll instead be using one of its movement methods. Specifically in the case of move_and_slide(), there tends to be some confusion, because it uses the velocity vector, not the position. This means you won’t multiply your velocity by delta to find distance - the function does that for you. But you will still need to apply it on any other calculations, such as the acceleration. For example:\n# Sprite movement code: velocity += gravity * delta position += velocity * delta # Kinematic body movement code: velocity += gravity * delta move_and_slide() If you don’t use delta when applying acceleration to your velocity, then your acceleration will be subject to fluctuations in frame rate. This can have a_much more subtle effect on movement - it will be inconsistent, but much more difficult to diagnose.\nTip When using move_and_slide() you still need to apply delta to any other quantities such as gravity, friction, etc.\nRelated Recipes ","description":"","tags":null,"title":"Understanding 'delta'","uri":"/godot_recipes/4.x/basics/understanding_delta/index.html"},{"content":" 3D Tips, tricks, and tutorials on the 3D side of game development.\nIn this section: Working with 3D Assets Basic FPS Character Camera Gimbal Interpolated Camera Shooting with Raycasts CharacterBody3D: Movement 3D Unit Healthbars Rolling Cube Arcade-style Spaceship Arcade-style Car Click to move Smooth rotation CharacterBody3D: Align with Surface ","description":"","tags":null,"title":"3D","uri":"/godot_recipes/4.x/3d/index.html"},{"content":"Problem You need a 2D character that has 8-directional movement, including animation.\nSolution For our example, we’ll use the Isometric Mini-Crusader, which contains 8-directional animations for idle, run, attack, and several other states.\nThe animations are organized in folders, with a separate image for each frame. We’ll use an AnimatedSprite2D and we’ll name each animation based on its direction. For example, idle0 pointing to the right and going clockwise to idle7.\nWhen our character moves, it will pick an animation based on the direction of movement:\nWe’ll use the mouse to move - the character will always face the mouse and run in that direction when we click the mouse button.\nTo choose which animation to play, we need to get the mouse direction and map it to this same range of 0-7. get_local_mouse_position() gives us the position of the mouse relative to the character. We can then use snappedf() to snap the angle of the mouse vector to the closest multiple of 45° (PI/4 radians) giving the following result:\nDivide each value by 45° (PI/4 radians), and we have:\nFinally, we need to map the resulting range to 0-7 using the wrapi() function, and we’ll have our correct values. Adding that value to the end of the animation name (“idle”, “run”, etc) gives us the correct animation:\nfunc _physics_process(delta): current_animation = \"idle\" var mouse = get_local_mouse_position() angle = snappedf(mouse.angle(), PI/4) / (PI/4) angle = wrapi(int(angle), 0, 8) if Input.is_action_pressed(\"left_mouse\") and mouse.length() \u003e 10: current_animation = \"run\" velocity = mouse.normalized() * speed move_and_slide() $AnimatedSprite2D.animation = current_animation + str(a) Testing the movement, we see this:\nKeyboard input If you’re using keyboard controls instead of mouse, you can get the angle of movement based on which keys are being held. The rest of the process works in the same way.\nfunc _process(delta): current_animation = \"idle\" var input_dir = Input.get_vector(\"left\", \"right\", \"up\", \"down\") if input_dir.length() != 0: angle = input_dir.angle() / (PI/4) angle = wrapi(int(a), 0, 8) current_animation = \"run\" velocity = input_dir * speed move_and_slide() $AnimatedSprite2D.play(current_animation + str(angle)) Download This Project Download the project code here: https://github.com/godotrecipes/8_direction_animation\n","description":"","tags":null,"title":"8-Directional Movement/Animation","uri":"/godot_recipes/4.x/2d/8_direction/index.html"},{"content":"Now that the player can move around the screen, our next step will be to implement shooting\nReusable objects The player will fire many “bullets” during the game, but all of them will be identical. A bullet needs to do the following:\nAppear just ahead of the player Travel forward until going off the screen Detect collisions with enemies Since all bullets will do these same things, we can save ourselves a great deal of work by designing one “prototype” bullet, and using that as the blueprint for creating as many duplicates as we need. Godot’s scene system is ideal for this.\nBullet scene Create a new scene by selecting Scene -\u003e New Scene in the menu, or by clicking the + in the tabs on the top of the viewport.\nJust like we did with the Player scene, we need to consider what nodes we’ll need to make the bullet work. We can again use an Area2D, since that will allow us to detect the bullet hitting things. This means we’ll need a collision shape, and a sprite to display the bullet image. Finally, we need a way to detect when the bullet goes offscreen so we can automatically remove it.\nHere’s the node setup:\nArea2D - name this Bullet Sprite2D CollisionShape2D VisibleOnScreenNotifier2D From the asset pack folder, drop the Player_charged_beam (16 x 16).png image on the Texture of the Sprite2D.\nAs with the ship image, there are multiple versions here, so set the *Hframes to 2 so we’ll only see one at a time.\nSet the shape of the CollisionShape2D just like you did earlier in the Player scene.\nBullet script Attach a script to the Bullet node and let’s start with the movement:\nextends Area2D @export var speed = -250 func start(pos): position = pos func _process(delta): position.y += speed * delta This should look fairly familiar, as it’s similar to the player script. We’re only changing the position.y since the bullet should travel straight up.\nNote the start() function we defined. That will let us set the bullet’s starting position, since the player will move around and spawn the bullets at different locations.\nConnecting signals Now select the Bullet node and then click the Node tab next to the Inspector.\nThis is a list of all the signals this node can emit. Signals are how Godot lets you know that something has happened. In this case, we can use the area_entered signal to tell us whenever this bullet touches another Area2D node.\nSelect the area_entered signal and click the Connect… button (you can also double-click the signal name). In the dialog that opens up, just click Connect - we don’t need to change anything there.\nYou’ll notice that you’re back in the script editor, looking at bullet.gd, and a new function as been added. It has a green “connected” icon next to its name to show that a signal is connected to it. This function will be called whenever the area touches something, so let’s add some code here:\nfunc _on_area_entered(area): if area.is_in_group(\"enemies\"): area.explode() queue_free() Here we’ll check if the bullet hit an enemy (more about that later), and if it did, we tell the enemy to explode and then delete the bullet.\nDo the same thing to connect the screen_exited signal of the VisibleOnScreenNotifier2D.\nfunc _on_visible_on_screen_notifier_2d_screen_exited(): queue_free() Next steps This completes the bullet scene, so now we can go back and add shooting to the player.\nPrev Next ","description":"","tags":null,"title":"Bullet Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_04/index.html"},{"content":"Problem You need a player-controlled 3D character body.\nSolution For this recipe, we’ll be using this adorable tank model:\nYou can grab this model on Itch.io: https://gtibo.itch.io/mini-tank or use any other model you’d like. We won’t be doing anything that’s tank-specific here.\nIn the case of this asset, the download includes an OBJ file, and we’ll find it more convenient if we import it as a scene:\nWe can add the model to the scene, but we’ll need a couple of additional nodes:\nFor the collision shape, we’re just going to use a BoxShape aligned and sized with the tank’s treads. CamPos is a Position3D we’ll use to place our following camera. It’s placed behind and above the tank, angled down.\nWe’ve also rotated the individual MeshInstance nodes 180 degrees around the Y axis. This is because they were modeled facing towards +Z, but -Z is the forward direction in Godot, and we don’t want our tank to look like it’s backwards.\nBefore we add a script, open the “Project Settings” and add the following inputs on the “Input Map” tab:\nInput Action Key forward W back S right D left A Now let’s add a script, starting with the required variables:\nextends CharacterBody3D @export var speed = 4.0 @export var turn_speed = 0.8 speed is the tank’s movement speed (forward and back), while rot_speed defines how fast it can turn.\nTip Declaring properties with @export makes it easy to adjust them in the Inspector.\nUsing the move_and_slide() method makes our movement code quite simple:\nfunc _physics_process(delta): velocity.y -= gravity * delta get_input(delta) move_and_slide() With this code, we add the downward acceleration of gravity to the current velocity, get the user’s input (more about that below), and call move_and_slide().\nNext we need to define get_input(), where we’ll process and apply the input actions:\nfunc get_input(delta): var vy = velocity.y velocity = Vector3.ZERO var move = Input.get_axis(\"back\", \"forward\") var turn = Input.get_axis(\"right\", \"left\") velocity += -transform.basis.z * move * speed rotate_y(turn_speed * turn * delta) velocity.y = vy Let’s examine this more closely. Player input should affect horizontal movement: forward/back along the ground, and rotation around the tank’s center. Movement in the Y direction should only be affected by gravity, which means we don’t want to set it to 0 every frame. This is why we’re using the vy variable to temporarily hold that value while we assign a new velocity vector for the horizontal movement, then add it back in at the end.\nFor the forward and back movement, we’re using transform.basis.z so that we’ll move in our body’s local forward direction.\nHere’s the tank in action. We’ve made a test scene with a StaticBody3D plane for the ground and an Camera3D using the Interpolated Camera recipe.\nWrapping up This is the basis of movement for any kind of kinematic character. From here you can add jumping, shooting, AI behavior, etc. See the related recipes for examples that build on this recipe.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples\nRelated recipes Intro to 3D Input Actions ","description":"","tags":null,"title":"CharacterBody3D: Movement","uri":"/godot_recipes/4.x/3d/characterbody3d_examples/index.html"},{"content":"Problem You need a “homing missile” - a projectile that will seek a moving target.\nSolution For this example, we’ll use an Area2D node for the projectile. Areas are typically good choices for bullets because we need to detect when they contact something. If you also need a bullet that bounces/ricochets, one of the PhysicsBody type node might be a better choice.\nThe node setup and behavior of the missile is the same you would use for a “dumb” bullet. If you’re creating many bullet types, you can use inheritance to base all your projectiles on the same core setup.\nThe nodes we’ll use:\nArea2D: Missile Sprite2D CollisionShape2D Timer: Lifetime For the texture, you can use any image you like. Here’s an example one:\nSet up the nodes and configure the sprite’s texture and the collision shape. Make sure to rotate the Sprite2D node by 90° so that it’s pointing to the right, ensuring it matches the parent’s “forward” direction.\nAdd a script and connect the Area2D’s body_entered signal and the Timer’s timeout signal.\nHere’s the starting script:\nextends Area2D export var speed = 350 var velocity = Vector2.ZERO var acceleration = Vector2.ZERO func start(_transform): global_transform = _transform velocity = transform.x * speed func _physics_process(delta): velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta func _on_Missile_body_entered(body): queue_free() func _on_Lifetime_timeout(): queue_free() This creates a “dumb” rocket that travels in a straight line when fired. To use this projectile, instance it and call its start() method with the desired Transform2D to set its position and direction.\nSee the related recipes section below for more information.\nTo change the behavior to seek a target, we’ll use the acceleration. However, we don’t want the missile to “turn on a dime”, so we’ll add a variable to control its “steering” force. This will give the missile a turning radius that can be adjusted for different behavior. We also need a target variable so that the missile knows what to chase. We’ll set that in start() as well:\nexport var steer_force = 50.0 var target = null func start(_transform, _target): target = _target ... To change the missile’s direction to move toward the target, it needs to accelerate in that direction (acceleration is change in velocity). The missile “wants” to move straight towards the target, but its current velocity is pointing in a different direction. Using a little vector math, we can find that difference:\nThe green arrow represents the needed change in velocity (i.e. acceleration). However, if we turn instantly, that will look unnatural, so the “steering” vector’s length needs to be limited. This is the purpose of the steer_force variable.\nThis is the function to calculate that acceleration. Note that if there’s no target, there will be no steering, so the missile remains traveling in a straight line.\nfunc seek(): var steer = Vector2.ZERO if target: var desired = (target.position - position).normalized() * speed steer = (desired - velocity).normalized() * steer_force return steer Finally, the resulting steer force must be applied in _physics_process():\nfunc _physics_process(delta): acceleration += seek() velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta Here’s an example of the results, with a little extra visual flair such as particle smoke and explosions:\nHere’s the full script, including the above effects. See related recipes for details.\nextends Area2D export var speed = 350 export var steer_force = 50.0 var velocity = Vector2.ZERO var acceleration = Vector2.ZERO var target = null func start(_transform, _target): global_transform = _transform rotation += rand_range(-0.09, 0.09) velocity = transform.x * speed target = _target func seek(): var steer = Vector2.ZERO if target: var desired = (target.position - position).normalized() * speed steer = (desired - velocity).normalized() * steer_force return steer func _physics_process(delta): acceleration += seek() velocity += acceleration * delta velocity = velocity.clamped(speed) rotation = velocity.angle() position += velocity * delta func _on_Missile_body_entered(body): explode() func _on_Lifetime_timeout(): explode() func explode(): $Particles2D.emitting = false set_physics_process(false) $AnimationPlayer.play(\"explode\") await $AnimationPlayer.animation_finished queue_free() Related recipes Spritesheet animation Top-down character Transforms ","description":"","tags":null,"title":"Homing missile","uri":"/godot_recipes/4.x/ai/homing_missile/index.html"},{"content":"Problem You want to pick up and move rigid bodies with the mouse.\nSolution Working with rigid bodies can be tricky. Godot’s physics engine controls their movements, and interfering with that can often lead to unexpected results. The key is to make use of the body’s mode property. This applies equally well in 2D or 3D.\nBody setup We’ll start with our rigid body object, adding a Sprite2D and CollisionShape2D. You can also add a PhysicsMaterial if you want to set Bounce and Friction properties.\nWe’re going to use the rigid body’s freeze property to remove it from the control of the physics engine while we’re dragging it. Since we still want it to be movable, we need to set the Freeze Mode to “Kinematic”, rather than the default value of “Static”.\nPlace the body in a group called “pickable”. We’ll use this to allow for multiple instances of the pickable object in the main scene. Attach a script to the body and connect the its _input_event signal.\nextends RigidBody2D signal clicked var held = false func _on_input_event(viewport, event, shape_idx): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: print(\"clicked\") clicked.emit(self) We’ll emit a signal when a mouse click is detected, including a reference to the body. Since there can be many bodies, we’ll let the main scene manage whether a body can be dragged or if there’s already one in the held state.\nIf the body is being dragged, we update its position to follow the mouse.\nfunc _physics_process(delta): if held: global_transform.origin = get_global_mouse_position() Finally, these are the two functions to call when the body is picked up and dropped. Changing the freeze to true removes the body from physics engine processing. Note that other objects can still collide with it. If you don’t want that, you can disable the collision_layer and/or collision_mask here as well. Just remember to re-enable them when dropping.\nfunc pickup(): if held: return freeze = true held = true func drop(impulse=Vector2.ZERO): if held: freeze = false apply_central_impulse(impulse) held = false In the drop function, after we change freeze back to `false, the body will return to the physics engine’s control. By passing in an optional impulse value, we can add the ability to “throw” the object on release.\nMain scene Create a main scene with some static body obstacles or a TileMap and instance a few copies of the pickable body.\nHere’s the script for the main scene. We start by connecting the clicked signal on any pickable bodies that are in the scene.\nextends Node2D var held_object = null func _ready(): for node in get_tree().get_nodes_in_group(\"pickable\"): node.clicked.connect(_on_pickable_clicked) Next, we have the function we connect the signal to. The connected function sets held_object so that we know something is currently being dragged, and calls the body’s pickup() method.\nfunc _on_pickable_clicked(object): if !held_object: object.pickup() held_object = object Lastly, when the mouse is released during dragging, we can perform the reverse actions.\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if held_object and !event.pressed: held_object.drop(Input.get_last_mouse_velocity()) held_object = null Note the use of get_last_mouse_velocity() to pass the impulse to the object - be careful with this! You may find yourself launching the rigid bodies at high speeds, especially if the bodies have low mass values. It’s probably a good idea to scale this to a reasonable value and clamp() it to some maximum. Experiment to find out what works for you.\nDownload This Project Download the project code here: https://github.com/godotrecipes/rigidbody_drag_drop\nRelated recipes ","description":"","tags":null,"title":"RigidBody2D: Drag and Drop","uri":"/godot_recipes/4.x/physics/rigidbody_drag_drop/index.html"},{"content":"Problem You need to save and load local data between game sessions.\nSolution Godot’s file I/O (input/output) system is based around the FileAccess object. You open a file by calling open().\nvar file = FileAccess.open(\"user://myfile.name\", File.READ) Warning User data should only be stored in the user:// path. While res:// can be used when running from the editor, when your project is exported, the res:// path becomes read-only.\nThe second argument after the file path is the “Mode Flag”, which can be one of the following:\nFileAccess.READ - Open for reading. FileAccess.WRITE - Open for writing. Creates the file if it doesn’t exist and truncates if it does. FileAccess.READ_WRITE - Open for reading and writing. Doesn’t truncate the file. FileAccess.WRITE_READ - Open for reading/writing. Creates the file if it doesn’t exist and truncates if it does. Storing data You can save data using its specific data type (store_float(), store_string(), etc.), or using the generic store_var(), which will use Godot’s built-in serialization to encode your data, including complex data like objects (more on this later).\nLet’s start with a small example: saving the player’s high score. We can write a function that we can call whenever the score needs to be saved:\nvar save_path = \"user://score.save\" func save_score(): var file = FileAccess.open(save_path, FileAccess.WRITE) file.store_var(highscore) We’re saving our score, but we need to be able to load it when the game starts:\nfunc load_score(): if FileAccess.file_exists(save_path): print(\"file found\") var file = FileAccess.open(save_path, FileAccess.READ) highscore = file.get_var() else: print(\"file not found\") highscore = 0 Don’t forget to check for the file’s existence before attempting to read from it - it may not be there! If that’s the case, you can use a default value.\nYou can store_var() and get_var() as many times as you need for any number of values.\nSaving Resources The above technique works great when all you need to save are a few values. For more complex situations, you can save your data in a Resource, just like Godot does. Godot saves all its data Resources as .tres files (Animations, TileSets, Shaders, etc.) and you can too!\nTo save and load Resources, use the ResourceSaver and ResourceLoader Godot classes.\nFor this example, let’s say you have all the data about your character’s stats stored in a Resource like this:\nextends Resource class_name PlayerData var level = 1 var experience = 100 var strength = 5 var intelligence = 3 var charisma = 2 You can then save and load like so:\nfunc load_character_data(): if ResourceLoader.exists(save_path): return load(save_path) return null func save_character_data(data): ResourceSaver.save(data, save_path) Resources can contain subresources, so you could have your player’s inventory Resource included as well, and so on.\nWhat about JSON? I see it very often (and some readers may be asking it already): “What if I want to use JSON to save my data?” This is my response:\nDon’t use JSON for your save files!\nWhile Godot has JSON support, saving game data is not what JSON is for. JSON is a data interchange format - its purpose is to allow systems using different data formats and/or languages to exchange data between each other.\nThis means JSON has limitations that are negatives for you when it comes to saving your game data. JSON doesn’t support many data types (no int vs. float, for example) so you have to do a lot of converting and validating to try and save/load your data. It’s cumbersome and time consuming.\nDon’t waste your time. Using Godot’s built-in serialization, you can store native Godot objects - Nodes, Resources, even Scenes - without any effort, which means less code and fewer errors.\nThere’s a reason that Godot itself doesn’t use JSON for saving scenes and resources.\nWrapping up This article just scratches the surface of what you can do with FileAccess. For the full list of available FileAccess methods, see the FileAccess documentation.\n","description":"","tags":null,"title":"Saving/loading data","uri":"/godot_recipes/4.x/basics/file_io/index.html"},{"content":"Problem Many 2D games use a “3/4 view” perspective, giving the impression that the camera is looking at the world at an angle. To make this work, objects that are “farther” away need to be rendered behind “nearer” objects. In practice, that means we want to “y-sort” - making the drawing order tied to the object’s y coordinate. The higher on the screen, the farther away and therefore lower the render order.\nHere’s an example of the problem:\nThese objects are being drawn in the default render order: tree order. They are arranged like this in the scene tree:\nSolution Godot has a built-in option to change the render order: on any CanvasItem node (Node2D or Control), we can enable the Y Sort Enabled property. When this is enabled, all child nodes are then y-sorted.\nIn the above example, we can enable the property on the TileMap node. However, there’s still a problem:\nThe draw order is based on each object’s y coordinate. By default, that is the object’s center:\nSince we want to give the impression that the objects are on the “ground”, we can solve this by offsetting each object’s sprite so that the object’s position is aligned with the bottom of the sprite:\nNow things look a lot better:\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/using_ysort\n","description":"","tags":null,"title":"Using Y-Sort","uri":"/godot_recipes/4.x/2d/using_ysort/index.html"},{"content":"Problem You want a floating “healthbar” for your 3D game objects (mobs, characters, etc.).\nSolution For this solution, we’re going to re-use a 2D healthbar based on a TextureProgressBar node. It’s already set up with textures and code for updating the value and color. If you already have something similar, feel free to use it here. In the example, we’ll name this scene “Healthbar2D”.\nIf you need some assets, here are the three images used in the bar:\nNote Re-using existing objects can save you a lot of time. Don’t re-invent the wheel everytime you need a healthbar, camera, or other common object.\nProject setup For our example “mob”, we’ll start with a CharacterBody3D node. It’s programmed to spawn and travel in a straight line. It also has the following code to handle damage:\nfunc _on_input_event(_camera, event, _position, _normal, _shape_idx): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: health -= 1 if health \u003c= 0: queue_free() Clicking on a unit deals one damage. Do ten damage, and the unit is destroyed. Now we need a visual representation of that using our 2D bar.\n2D in 3D We can display a 2D image in 3D using a Sprite3D. Add one to a new scene and name it “Healthbar3D”. First, we’ll get it configured and sized, so set the Texture property to the green bar image.\nThe Sprite3D acts like any other 3D object - as we pan the camera around, our perspective on it changes. However, we want the healthbar to always “face” toward the camera so that we can see it.\nIn the Inspector, under Flags, set Billboard to “Enabled”.\nNow try moving the camera to confirm that the texture is always facing you.\nAdd an instance of this scene to the Mob scene and position the bar above the mob’s body.\nViewport texture We don’t want the Sprite3D to show a static texture - we want it to display the 2D TextureProgressBar. We can do that using a SubViewport node, which can export a texture.\nAdd a SubViewport as a child of the Sprite3D. In the Inspector set Transparent BG to On.\nWe also need to set the size of the viewport to match the size of the healthbar texture, which is (200, 26).\nInstance the HealthBar2D as a child of the Viewport. Your scene should look like this:\nIf the SubViewport were not a child of the Sprite3D, we could set it as the sprite’s texture directly in the Inspector. Since it’s a child, it won’t be ready at the right time, so we’ll need to set it in a script attached to the Sprite3D:\nextends Sprite3D func _ready(): texture = $SubViewport.get_texture() Connecting it all together In the mob’s _on_input_event() method, add the following after reducing the health:\n$HealthBar3D.update(health, max_health) Add the following to HealthBar3D.gd:\nfunc update_health(_value, _max_value): $SubViewport/HealthBar2D.update_health(_value, _max_value) This calls the update method that already exists on the 2D bar, setting the progress bar’s value and selecting the bar color:\nfunc update_health(_value, _max_value): value = _value if value \u003c _max_value: show() texture_progress = bar_green if value \u003c 0.75 * _max_value: texture_progress = bar_yellow if value \u003c 0.45 * _max_value: texture_progress = bar_red Click on the mobs to see the health bars change.\nWrapping up You can use this technique to display any other Node2D or Control nodes, such as Label, VideoStreamPlayer, etc. You can even use the SubViewport to “project” an entire 2D game in 3D space.\nDownload This Project Download the project code here: https://github.com/godotrecipes/3d_object_healthbars\n","description":"","tags":null,"title":"3D Unit Healthbars","uri":"/godot_recipes/4.x/3d/healthbars/index.html"},{"content":" Animation Using Godot’s animation system.\nIn this section: Spritesheet animation Using the AnimationTree StateMachine ","description":"","tags":null,"title":"Animation","uri":"/godot_recipes/4.x/animation/index.html"},{"content":"Problem You’ve got a rigged, animated 3D character (either made by you or downloaded from a third party) and you want to set up its animations in Godot.\nSolution In this recipe, we’ll assume you’ve already imported your character model and animations. If you haven’t yet, see Importing Assets for details. As a reminder, we’re using the art packs linked in the section description.\nPrepping the character We’ve chosen CharacterBody3D for our character, so your scene should look like this (I’ve collapsed the Rig node since the mesh list is so long):\nThe first thing you probably noticed is that the character’s hands are full! The artist has helpfully provided all the weapons \u0026 shields attached and oriented at the correct points. You can go down the list and hide the ones you don’t want to see.\nAbout the AnimationTree With all of the animations we have available, it’s going to quickly get very complicated to handle all of them in code. Think about how many if statement’s we’d need to decide which animation to play at which time, depending on what the player is doing. While this is not bad if you only have a few animations, it quickly gets out of hand and becomes impractical.\nAlso, consider when the character is standing still: it should be playing the “Idle” animation. When the player presses “forward”, the character should move and switch to playing the “Walking” animation. This sudden transition is going to look jarring, so we’d prefer if the two animations can be “blended” into a smoother transition.\nThe solution to these complex animation issues is to use the AnimationTree node. This node is designed to control an AnimationPlayer and has functionality to control how animations transition and blend together.\nAdd an AnimationTree to the scene. In the Inspector, set Tree Root to a new AnimationNodeStateMachine, in Anim Player select the character’s AnimationPlayer node, and check the box next to Active.\nNote You may notice that when the AnimationTree is active, you can’t choose animations in the AnimationPlayer. If you need to make any changes or test the animations, uncheck the tree’s Active property while doing so.\nThe Idle/Walk/Run Cycle There are a lot of animations provided with these models. For this example, we’re going to focus on the idle-walk-run cycle, jumping, and attacking. If you want to include other animations, they’ll be handled in a similar way.\nIn the AnimationPlayer, find the “Idle”, “Running_A”, “Walking_Backwards”, and “Running_Strafe_Left”/“Running_Strafe_Right” animations. Make sure they’re all set to loop - you can test them by pressing the “Play” button: (▶). If any of them are not, reimport the character after setting them (see Importing Assets).\nSelect the AnimationTree node and you’ll see the panel open at the bottom of the window:\nAs an example, right-click in the empty space and choose Add Animation → Idle, then add the “1H_Melee_Attack_Chop” animation as well.\nSelect the Connect Nodes button and draw a connection from Start to Idle. You should immediately see the “Idle” animation playing.\nNow, we want to be able to transition from idle to attack and then back to idle when the attack animation finishes. Draw two more connection arrows to and from the attack. It won’t quite work, however, you’ll just be rapidly flickering between the two animations, because both are set to immediately transition.\nTo change the transition conditions, change to Select mode using the icon and then click on one of the connections. In the Inspector, you’ll see the connection properties. For the connection from idle to attack, we want Advance/Mode to be “Enabled” (not “Auto”). This means it happens only when told to. Notice that the icon on the connection line changes color.\nFor the connection from attack to idle, set Switch Mode to “At End” and Advance Mode to “Auto”.\nNow, when you press the ▶ button on the attack node, it will play and then transition back to idle as soon as it completes.\nThis gives you an idea how to set up different animations and transition between them. However, we want to do a little more here, so delete the two animations using the trash can icon, and let’s set up a blendspace.\nBlendspaces Right-click in the empty space to create a new BlendSpace2D. Click on its name to rename it to IWR (for idle-walk-run). Add a transition from Start so that the blendspace will start playing automatically.\nClick the pencil icon to edit the blend space.\nThis 2D space represents the character’s horizontal movement vector. When standing still that’s (0, 0), so click the Create Points button and click in the center of the grid to Add Animation → Idle.\nAt the center-top, add the “Running_A” animation, and center-bottom, “Walking_Backwards”. At the two horizontal ends, add the strafe animations.\nNow click the crosshair button to set the blend position and click to drag it around the grid. You should see the animations transition smoothly between the extremes.\nWhen you’re done experimenting with the blendspace, click “Root” in the Path at the top of the panel to return to the root of the tree.\nSetting up the state machine The IWR looping animations can be thought of as the “heart” of the animation tree. The character will spend most of its time playing these animations. Any other animations will branch off from it (like we did earlier with the attack).\nIn the image below, I’ve done that with several other animations. Note the transition properties are set as we did in the example above.\nYou can also click to change the names the animations, as some of them are quite long.\nThe one animation that’s different is jumping. The jump animation is split into three parts: “start\"and “land”, which are played when the character starts jumping, and when the jump ends. The “idle” portion of the jump is a looping animation that plays as long as the character is in the air - if they fall a long way, for example.\nAdd the three jumping animations and link them like this:\nWe need to be able to go straight from IWR to Jump_Idle in the event of falling off a ledge, but if pressing “jump”, we’ll go through Jump_Start first.\nIn addition, we’ve left the transition from IWR to Jump_Start as “Auto”. Instead of changing it to “Enabled”, we’ve added a Condition of jumping to the transition:\nSimilarly, the transition between Jump_Idle and Jump_Land has a condition of grounded.\nWe’ll be able to set these conditions in code to trigger the transition.\nFinally, if you’re looking closely, you may notice that the transition from Jump_Land to IWR does not look smooth, because the last frame and first frame of the two animations don’t quite match up. We can solve this by selecting the transition between them and setting a small Xfade Time of 0.1, which will smooth it out nicely.\nWrapping up We’ve now set up our 3D character’s animations and they’re ready to use. By setting up the AnimationTree, it will now be much easier to select and transition between animations in the character’s movement code.\nSee the section description for more examples of working in 3D and for example Godot projects you can download.\nCompanion Video https://youtu.be/YrNQCB34PAc\n","description":"","tags":null,"title":"Character Animation","uri":"/godot_recipes/4.x/3d/assets/character_animation/index.html"},{"content":"Problem You want your character body to interact with rigid bodies.\nSolution Note This recipe applies equally well in both 2D and 3D nodes.\nBy default, a CharacterBody2D moved with move_and_slide() or move_and_collide() will not push any RigidBody2D it collides with. The rigid body doesn’t react at all, and behaves just like a StaticBody2D.\nIn some cases, this might be all you need. However, if you want to be able to push the bodies, you’ll need to make some changes.\nFor this example, we’ll use the 2D character described in the Platform character recipe. This example uses the most common movement method for character bodies: move_and_slide(). If you’re using move_and_collide(), you’ll need to adjust the examples below accordingly.\nYou have two options when deciding how to interact with rigid bodies:\nYou can just push them, ignoring physics. If you’re familiar with Godot 3.x, this is equivalent to the “infinite inertia” option. You can give them a push based on the character’s imagined “mass” and velocity. This will give you a “realistic” result - pushing heavy bodies a little, and lighter bodies a lot. We’ll try out both options below.\nInfinite Inertia This option has its pros and cons. The biggest pro is, you don’t need any extra code. You just need to correctly set the collision layers/masks of the objects. For this example, we’ve defined three physics layers:\nFor the rigid body, we’ve placed it on the “items” layer (layer 3), and left the mask at the default (masking all layers):\nThen, we’ve placed the player on the “player” layer (layer 2), and configured the mask to ignore the “items”:\nRunning the game, we now see we can push the boxes around. Note that the mass of the box doesn’t matter - they’ll all be pushed the same.\nHere, you can also see the downside of this option. Because the physics of the boxes is being ignored, they can clip through walls and you can’t jump on top of them.\nFor some games, this will be fine. If you want to prevent the clipping, you’ll need to go with option 2.\nApplying impulses To give the colliding body a “push” we’ll need to apply an impulse. An impulse is an instantaneous “kick” - think of a bat hitting a ball. This is as opposed to a force, which is a continuous “push” on an object.\n# This represents the player's inertia. var push_force = 80.0 func _physics_process(delta): # after calling move_and_slide() for i in get_slide_collision_count(): var c = get_slide_collision(i) if c.get_collider() is RigidBody2D: c.get_collider().apply_central_impulse(-c.get_normal() * push_force) The collision normal points out of the rigid body, so we reverse it to point away from the character and apply the push_force factor. Now pushing works again, but it won’t force the rigid bodies through walls:\nYou’ll need to adjust the push_force in relation to the mass of your rigid bodies. Too high a force will still cause clipping, while too low will prevent pushing at all.\nExperiment to find the settings that work for your particular game.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/character_vs_rigid\nRelated recipes Platform character Watch Video ","description":"","tags":null,"title":"Character to Rigid Body Interaction","uri":"/godot_recipes/4.x/physics/character_vs_rigid/index.html"},{"content":"Problem Your platformer jumping feels “off”. Players don’t have good control and sometimes they “miss” jumping off the edge of platforms.\nSolution The answer to this problem is to use a technique called “coyote time”. This gives the player a greater feeling of control and a little “wiggle room” around the process of jumping from the edges of platforms.\n“Coyote time” works like this:\nIf the player walks off the edge of a platform, for a few frames afterward, we still allow them to jump as if they were still on the ground.\nOrigins The name “coyote time” comes from the famous cartoon coyote, who wouldn’t fall until he looked down:\nWe’re going to add this to an already existing platform character. See the Platform character recipe for how to set one up.\nTo handle the timing, we’ll add a Timer node called CoyoteTimer and set it to One Shot.\nThere are a few new variables we’ll need to keep track of coyote time:\nvar coyote_frames = 6 # How many in-air frames to allow jumping var coyote = false # Track whether we're in coyote time or not var last_floor = false # Last frame's on-floor state Since we’re using frames to set the duration, we can translate that to time when setting the Timer’s length in _ready():\n$CoyoteTimer.wait_time = coyote_frames / 60.0 Each frame we’ll store the current value of is_on_floor() to be used in the following frame, so put this in _physics_process() after the move_and_slide():\nlast_floor = is_on_floor() When we detect the jump input, we need to check if the character is on the floor or in coyote time:\nif Input.is_action_just_pressed(\"jump\") and (is_on_floor() or coyote): velocity.y = jump_speed jumping = true Coyote time begins if the player walks off the edge of a platform. That means that they are no longer on the floor, but were on the floor in the previous frame. We can check that like this, and start the timer if we did just transition from on- to off-floor:\nif !is_on_floor() and last_floor and !jumping: coyote = true $CoyoteTimer.start() The CoyoteTimer tells us when the coyote state ends:\nfunc _on_coyote_timer_timeout(): coyote = false Implementing in 3D You can apply the same process to 3d characters.\nDownload This Project The character in the Moving Platforms project has coyote time implemented.\nDownload the project code here: https://github.com/godotrecipes/2d_moving_platforms\nRelated recipes Platform character ","description":"","tags":null,"title":"Coyote Time","uri":"/godot_recipes/4.x/2d/coyote_time/index.html"},{"content":"Problem You need to display a heart container bar (or other icon-based bar).\nSolution A common way of displaying the player’s health is via a series of icons (typically hearts) that disappear as the player takes damage.\nIn this recipe, we’re going to explore three ways of displaying this information, which I’m labeling “simple”, “empty”, and “partial”:\nThis image shows what the bar displays when the player has 3 health.\nsimple: Only the hearts are displayed. empty: Empty heart containers are displayed. partial: The player can have partially filled containers. Setting up the bar The heart images I’m using are 53x45. You can get them here:\nKenney.nl: Platformer Art Deluxe\nIdeally, your heart bar will be easy to drop into your overall HUD/UI. It therefore makes sense to make it a separate scene. We’ll start with an HBoxContainer which will keep things aligned. Set the Theme Overrides/Constants/Separation to 5.\nAdd a TextureRect child. Drag your heart texture into the Texture property and set the Stretch Mode to “Keep”. Name the node “1” and then press “Ctrl-D” to duplicate the node for as many hearts as you need (5 in this example). Your node setup should look like this:\nAdding a script The script below will cover all three bar configurations for flexibility. You’ll probably only need one in your game, so you can remove the code relating to the other modes.\nTo begin, we’re going to load the textures we need and define our three bar modes:\nextends HBoxContainer enum modes {SIMPLE, EMPTY, PARTIAL} var heart_full = preload(\"res://assets/hud_heartFull.png\") var heart_empty = preload(\"res://assets/hud_heartEmpty.png\") var heart_half = preload(\"res://assets/hud_heartHalf.png\") @export var mode : modes func update_health(value): match mode: MODES.simple: update_simple(value) MODES.empty: update_empty(value) MODES.partial: update_partial(value) Calling update_health() on the bar will cause it to display the passed value, based on the selected mode.\nNote We’re not going to do any bounds checking on the value input. There are many ways you may have health implemented in your game, and so that’s left to you.\nFirst, the update_simple() method. Here, we loop through the heart containers and set the visibility of each TextureRect:\nfunc update_simple(value): for i in get_child_count(): get_child(i).visible = value \u003e i update_empty() is very similar, except instead of hiding the icon, we change its texture to the empty container:\nfunc update_empty(value): for i in get_child_count(): if value \u003e i: get_child(i).texture = heart_full else: get_child(i).texture = heart_empty Finally, for the partially filled containers, we have a third texture and twice the number of possible values:\nfunc update_partial(value): for i in get_child_count(): if value \u003e i * 2 + 1: get_child(i).texture = heart_full elif value \u003e i * 2: get_child(i).texture = heart_half else: get_child(i).texture = heart_empty Here’s an example using each of the bar modes:\nWrapping up Use this heart bar setup as a basis for your own HUD. This technique can be expanded to support a wide variety of information displays.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/heart_bars\n","description":"","tags":null,"title":"Heart Containers: 3 Ways","uri":"/godot_recipes/4.x/ui/heart_containers_3/index.html"},{"content":" Input Handling input - from keyboard and mouse to game controllers and touchscreens.\nIn this section: Input Actions Mouse Input Adding Input Actions in code Capturing the Mouse Mouse: Drag-select multiple units ","description":"","tags":null,"title":"Input","uri":"/godot_recipes/4.x/input/index.html"},{"content":" Intro to 3D A gentle introduction to the 3D side of Godot development.\nIn this section: The 3D Editor Importing 3D Objects Creating a 3D Character ","description":"","tags":null,"title":"Intro to 3D","uri":"/godot_recipes/4.x/g101/3d/index.html"},{"content":"This is an evolving list of the main changes and “gotchas” to look out for if you’re transitioning to 4.0.\nNew Names One of the biggest changes in Godot 4 is a whole bunch of renaming - of nodes, functions, and property names. Most of it is done to make things consistent or clear. Here are a few of the biggest ones to watch out for:\n2D/3D nodes - In Godot 3.x, 2D nodes had the “2D” suffix, but 3D nodes had none. This has been made consistent - they all now have “2D” or “3D” suffixes. For example: RigidBody2D vs. RigidBody3D.\nAlso in the category of 3D, the Spatial node is renamed to Node3D to match.\nOne of the most popular nodes, KinematicBody, has been renamed to CharacterBody2D/CharacterBody3D. See below for further changes with this node’s API.\nPackedScene’s instance() function has been renamed to instantiate().\nThe position and global_position properties replace translation and global_translation in 3D, making them consistent with 2D.\nSignals and Callables Working with signals is much more streamlined in 4.0. Signal is a native type now, so you’ll be using fewer strings, meaning you get autocomplete and error checking. This applies to functions as well, which can now be directly referenced rather than using strings.\nHere’s an example of defining, connecting, and emitting a signal.\nextends Node signal my_signal func _ready(): my_signal.connect(signal_handler) func _input(event): if event.is_action_pressed(\"ui_select\"): my_signal.emit() func signal_handler(): print(\"signal received\") Tweens If you started using SceneTreeTween in Godot 3.5, then you’ll be familiar with Godot 4.0’s Tween usage.\nTween is no longer a node. Instead, you create one-off tween animation objects whenever you need them. Once you get used to it, it’s a lot more powerful and easier to use than the old method.\nAnimatedSprite[2D|3D] The biggest change that catches people who are familiar with the 3.x version of this node is that the playing property is gone. It’s now much more consistent with AnimationPlayer’s usage - to automatically play an animation, you can toggle autoplay in the SpriteFrames panel. In code, use play() and stop() to control playback.\nCharacterBody[2D|3D] The biggest change in this node is in using move_and_slide(). It no longer takes any parameters - they are all now built-in properties. This includes a native velocity property, so you no longer need to declare your own.\nFor detailed examples of using these nodes, see Platform Character and/or Basic FPS Character.\nTileMap The TileMap node is completely overhauled for 4.0. Just about everything, from how you create TileSets to how you draw and interact with tiles is 100% new.\nOur “Using TileMaps” guide is coming soon.\nRNG There are a few changes to GDScript’s built-in random number generator functions:\nYou no longer need to call randomize() - this is automatic. If you do want repeatable “randomness”, use seed() to set it to a preselected value.\nrand_range() is now replaced with either randf_range() (for floats) or randi_range() (for ints).\nRaycasting When casting rays in code, there’s a new API. PhysicsDirectSpaceState[2D|3D].intersect_ray() now takes a special object as a parameter. This object specifies the ray properties. For example, to cast a ray in 3D:\nvar space = get_world_3d().direct_space_state var ray = PhysicsRayQueryParameters3D.create(position, destination) var collision = space.intersect_ray(ray) if collision: print(\"ray collided\") ","description":"","tags":null,"title":"Migrating from 3.x","uri":"/godot_recipes/4.x/basics/migrating/index.html"},{"content":"Problem You need moving platforms in your 2D platformer.\nSolution There are several ways to approach this problem. In this recipe, we’ll use AnimatableBody2Ds for our platform and move it with a Tween. This allows for a variety of movement styles while minimizing the amount of code we need to write.\nInfo You can also implement this moving platform technique using an AnimationPlayer rather than a tween. Much of the setup will be the same, but rather than tween code, you’ll animate the body’s position property.\nSetting up We’ll start with a basic platformer setup using the Platform character recipe. The basic movement from that recipe will work fine with the platforms. If you’ve modified it or used your own, everything should still work the same.\nCreating the platform The platform scene contains the following nodes:\nNode2D (“MovingPlatform”): The Node2D parent is there to act as the “anchor” or start point for the platform. We’ll animate the platform’s position relative to this parent node. AnimatableBody2D: This represents the platform itself. This is the node that will move. Sprite2D: You can use a sprite sheet here, individual images, or even a TileMap. CollisionShape2D: Don’t make the hitbox too big, or the player will appear to be “hovering” off the edge of the platform. Set up the Sprite2D’s Texture and the collision shape appropriately. In the AnimatableBody2D, set the Sync to Physics property “On”. Since we’re moving the body in code, this ensures that it’s moved during the physics step, keeping it in sync with the player and other physics bodies.\nNow add a script to the root Node2D:\nextends Node2D @export var offset = Vector2(0, -320) @export var duration = 5.0 func _ready(): start_tween() func start_tween(): var tween = get_tree().create_tween().set_process_mode(Tween.TWEEN_PROCESS_PHYSICS) tween.set_loops().set_parallel(false) tween.tween_property($AnimatableBody2d, \"position\", offset, duration / 2) tween.tween_property($AnimatableBody2d, \"position\", Vector2.ZERO, duration / 2) We’ve used a few of Tween’s options here to make everything work smoothly:\nset_process_mode(): ensures that all movement takes place during the physics processing step. set_loops(): this makes the tween repeat. set_parallel(false): by default, all tween_property() changes would happen at that same time. This makes the two happen one after another: moving to one end of the offset, then back to the start. Using the two exported properties, you can adjust the platform’s movement. Set the offset to determine where the tween moves relative to its starting point, and the duration to determine how long it takes to complete the cycle.\nAdd some platforms in your level/world and try them out:\nDownload This Project Download the project code here: https://github.com/godotrecipes/2d_moving_platforms\nRelated recipes Platform character ","description":"","tags":null,"title":"Moving Platforms","uri":"/godot_recipes/4.x/2d/moving_platforms/index.html"},{"content":"Problem You have a grid-based environment and you’d like to set up pathfinding to allow navigation.\nSolution Godot provides a number of methods for pathfinding. For this recipe, we’ll consider the A* algorithm.\nAbout A* A* is a widely-used algorithm for finding the shortest path between two points. It can be used in any graph-based data structure, not just a grid.\nAStarGrid2D is a specialized version of Godot’s more generic AStar2D class. Because it’s specialized for using with a grid, it’s quicker and easier to set up because you don’t have to manually add all the individual grid cells and their connections.\nSetting up the Grid The most important configuration decision is the size of the cells and the size of the grid itself. We’ll use (64, 64) for this example, and we’ll use the window size to determine how many cells fit on the screen, but everything will work the same regardless of cell size.\nAdd this code to a Node2D.\nextends Node2D @export var cell_size = Vector2i(64, 64) var astar_grid = AStarGrid2D.new() var grid_size func _ready(): initialize_grid() func initialize_grid(): grid_size = Vector2i(get_viewport_rect().size) / cell_size astar_grid.size = grid_size astar_grid.cell_size = cell_size astar_grid.offset = cell_size / 2 astar_grid.update() In this code, we divide the size of the screen by the cell_size to calculate how big the whole grid will be. This lets us set the size property of the AStarGrid2D.\nThe offset property will come into play when we ask for a path between two points. Using cell_size / 2 means the path will be calculated from the center of each cell rather than the corners.\nFinally, we need to call update() after setting or changing any of the AStarGrid2D’s properties.\nDrawing the Grid For the purposes of this demo, we’ll draw the grid on the screen in code. In a game application, you’ll probably have a TileMap or some other visual representation of your world.\nHere’s some code to draw the grid:\nfunc _draw(): draw_grid() func draw_grid(): for x in grid_size.x + 1: draw_line(Vector2(x * cell_size.x, 0), Vector2(x * cell_size.x, grid_size.y * cell_size.y), Color.DARK_GRAY, 2.0) for y in grid_size.y + 1: draw_line(Vector2(0, y * cell_size.y), Vector2(grid_size.x * cell_size.x, y * cell_size.y), Color.DARK_GRAY, 2.0) This gives us a nice visual of the grid:\nDrawing the Path In order to find a path, we need a start and end point. Add these variables at the top of the script:\nvar start = Vector2i.ZERO var end = Vector2i(5, 5) And a couple of lines in _draw() to show them:\ndraw_rect(Rect2(start * cell_size, cell_size), Color.GREEN_YELLOW) draw_rect(Rect2(end * cell_size, cell_size), Color.ORANGE_RED) We can find the path between the two points using the get_point_path() method, but we also need to visualize it. We can use a Line2D, so add one to the scene.\nHere’s how we can get the path, and add the resulting points to the Line2D:\nfunc update_path(): $Line2D.points = PackedVector2Array(astar_grid.get_point_path(start, end)) Here’s the result:\nNote that we have a diagonal line between the two points. This is because, by default, the path will use diagonals. This can be modified by changing the diagonal_mode:\nDIAGONAL_MODE_ALWAYS - The default value, uses diagonals. DIAGONAL_MODE_NEVER - All movement is orthogonal. DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE - This allows diagonals, but prevents the path going “between” diagonally placed obstacles. DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES - This allows diagonals only in “open” areas, not near obstacles. Modifying this property can give you very different results, so make sure to experiment based on your setup. Let’s add this in the initialize_grid() function:\nastar_grid.diagonal_mode = AStarGrid2D.DIAGONAL_MODE_NEVER Now we only have orthogonal moves:\nAdding Obstacles We can also add obstacles to the grid. By marking a cell as “solid”, the path will not include that cell. A cell can be toggled solid/not solid by using the set_point_solid() function.\nLet’s add some code to draw our walls (when they exist), by finding any solid cells and coloring them in:\nfunc fill_walls(): for x in grid_size.x: for y in grid_size.y: if astar_grid.is_point_solid(Vector2i(x, y)): draw_rect(Rect2(x * cell_size.x, y * cell_size.y, cell_size.x, cell_size.y), Color.DARK_GRAY) Call this function in _draw().\nThen, we can use the mouse to click on cells and toggle their state:\nfunc _input(event): if event is InputEventMouseButton: # Add/remove wall if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: var pos = Vector2i(event.position) / cell_size if astar_grid.is_in_boundsv(pos): astar_grid.set_point_solid(pos, not astar_grid.is_point_solid(pos)) update_path() queue_redraw() Note that we’re checking is_in_boundsv() first - this will prevent errors from being thrown if we click outside the grid boundaries.\nNow we can see the effect of obstacles on the path:\nChoosing a Heuristic A big factor that affects the resulting path is what heuristic you choose to use. The term “heuristic” refers to a “best guess”, and in the context of pathfinding just means: what direction should we try first when moving toward the goal?\nFor example, the Euclidean distance uses the Pythagorean theorem to estimate the path to try:\nWhile Manhattan distance only considers distance in N/S or E/W directions:\nAnd the Octile heuristic results in a path like this:\nYou can choose the heuristic using this property:\nastar_grid.default_estimate_heuristic = AStarGrid2D.HEURISTIC_OCTILE Which of these works best (results in the most pleasing paths) depends on the nature of your environment. Is it mostly wide-open spaces with few obstacles scattered around? Or is it a maze of twisty passages? Make sure to experiment with your specific project.\nDownload the example project below to experiment with this setup yourself. In addition to placing walls, you can use the right/middle mouse buttons to move the end/start locations.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/grid_pathfinding\n","description":"","tags":null,"title":"Pathfinding on a 2D Grid","uri":"/godot_recipes/4.x/2d/grid_pathfinding/index.html"},{"content":"The Bullet scene provides us with a reusable object we can instantiate whenever the player shoots.\nAdding to the player Let’s head back to the Player script and add a few new variables:\n@export var cooldown = 0.25 @export var bullet_scene : PackedScene var can_shoot = true The two @export variables let you configure them in the Inspector so that you can adjust the cooldown time. Set the bullet_scene by clicking the property and choosing the bullet.tscn file.\ncan_shoot is what programmers call a flag - a Boolean variable that controls a certain condition. In this case it determines whether the player is allowed to shoot or not. During the cooldown period, this variable will be false.\nNext, we’ll add a start() function similar to the one we made for the Bullet. This will let us set initial values for the player, as well as resetting them when the game restarts.\nfunc _ready(): start() func start(): position = Vector2(screensize.x / 2, screensize.y - 64) $GunCooldown.wait_time = cooldown This places the player at the bottom center of the screen - a good place to start. It also ensures that the cooldown timer has the correct wait time.\nThe shoot() function will be called whenever we press the “shoot” input.\nfunc shoot(): if not can_shoot: return can_shoot = false $GunCooldown.start() var b = bullet_scene.instantiate() get_tree().root.add_child(b) b.start(position + Vector2(0, -8)) The first thing this function does is check if the player is allowed to shoot. If it isn’t, return will end the function immediately.\nIf the player is allowed to shoot, then we set the flag to false, and start the cooldown timer. Then we create a new bullet and add it to the game, calling its start() function to make sure it’s placed in the correct position (just above the player’s ship).\nWe can call this function when the player is pressing the key. Add this to the end of the _process() function, after the position.clamp() line:\nif Input.is_action_pressed(\"shoot\"): shoot() We’ll also need to connect the timeout signal of GunCooldown.\nfunc _on_gun_cooldown_timeout(): can_shoot = true When the cooldown ends, we can allow shooting again.\nGo ahead and run the scene and try pressing the shoot action.\nAdding instances to the tree Notice that we’ve added the new bullets as children of the SceneTree root (get_tree().root), and not to the player ship. This is important because if we made the bullets children of the ship, then they would be “attached” to it when it moves.\nNext steps Shooting’s no fun without something to shoot at. We’ll start making the enemies soon, but first we need a scene where we can bring the player, enemies, and other game objects together.\nPrev Next ","description":"","tags":null,"title":"Shooting","uri":"/godot_recipes/4.x/games/first_2d/first_2d_05/index.html"},{"content":" UI Building user interfaces.\nIn this section: Heart Containers: 3 Ways Level Select Menu Minimap/radar ","description":"","tags":null,"title":"UI","uri":"/godot_recipes/4.x/ui/index.html"},{"content":"Problem A common situation: you have a large number of animations, and it’s becoming difficult to manage transitions between them. Your code has become full of if statements, and every time you change something, it all breaks.\nSolution Use an AnimationTree to create an animation state machine. This will allow us to organize our animations and most importantly, control the transitions between them.\nGetting started For this demo, we’ll be using the excellent “Adventurer” sprite by Elthen. You can get this and lots of other great art at https://elthen.itch.io/.\nWe’ll also assume you’ve already set up the character’s animations using AnimationPlayer. Using the above spritesheet, we have the following animations: “idle”, “run”, “attack1”, “attack2”, “hurt”, and “die”.\nAnimationTree Add an AnimationTree node to the scene. In its Tree Root property, choose “New AnimationNodeStateMachine”.\nAn AnimationTree is a node that controls animations created in AnimationPlayer. To let it access the existing animations, click “Assign” in the Anim Player property and select your animation node.\nNow we can begin to set up our state machine in the AnimationTree panel:\nNote the warning. Set the Active property to “On” in the Inspector.\nRight-click and choose “Add Animation”. Choose “idle”, and you’ll see a small box representing that animation. Press its “Play” button and you should see the animation play. Do the same to add boxes for the other animations.\nNow we can add connections. Click the “Connect nodes” button and drag between nodes to connect them. As an example, let’s use the two attack animations:\nWhen you select an animation, the tree will follow the connected path from the current node to the destination. However, in the configuration above, if you play “attack2” you won’t see “attack1” along the way. That’s because the default “switch mode” for a connection is “Immediate”. Click the “Move/select” button and then click on the connection between “attack1” and “attack2”. In the Inspector, change Switch Mode to “At End”. Do the same with “attack2” to “idle”. The connection icon changes from to .\nNow, with “idle” playing, if you click “attack2”, you’ll see the two attacks play in sequence.\nBut now the animation stops on “attack2”. On its connection, set the Advance/Mode property to “Auto”. This will make the tree go back to “idle” after playing both animations. Note that the connection icon turns green to show this.\nNow the animations are played in sequence whenever they’re triggered.\nCalling states in code Here is the full tree for all of the animations:\nNow let’s set up the character to use these animations in a script.\nextends CharacterBody2D var state_machine var run_speed = 80.0 var attacks = [\"attack1\", \"attack2\"] @onready var state_machine = $AnimationTree[\"parameters/playback\"] state_machine holds a reference to the state machine, which is an AnimationNodeStateMachinePlayback. To call a specific animation, you use travel(), which will follow the connections to the given animation.\nfunc hurt(): state_machine.travel(\"hurt\") func die(): state_machine.travel(\"die\") set_physics_process(false) Here we have examples of functions we would call if the player is hurt or killed. For the other animations (running, attacking, etc.), we’ll need to combine them with our input and movement code. velocity determines whether we should be showing “run” or “idle”.\nfunc get_input(): var current = state_machine.get_current_node() velocity = Input.get_vector(\"move_left\", \"move_right\", \"move_up\", \"move_down\") * run_speed if Input.is_action_just_pressed(\"attack\"): state_machine.travel(attacks.pick_random()) return # flip the character sprite left/right if velocity.x != 0: $Sprite2D.scale.x = sign(velocity.x) # choose animation if velocity.length() \u003e 0: state_machine.travel(\"run\") else: state_machine.travel(\"idle\") move_and_slide() Note that we’re using return after traveling to the attack animations. This is so that we won’t instead travel to the “run” or “idle” animations further down in the function.\nYou can use the AnimationTreeStateMachine to handle\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos\nRelated recipes Spritesheet animation Top-down character ","description":"","tags":null,"title":"Using the AnimationTree StateMachine","uri":"/godot_recipes/4.x/animation/using_animation_sm/index.html"},{"content":" Gamedev Math Math is a big part of game development. Some of it you may remember from school, or it may be something you’ve never encountered before. Here you’ll find guides to help you get up to speed and examples of how these concepts are applied to making games.\nIn this section: Interpolation Transforms Vectors: Using Dot and Cross Product ","description":"","tags":null,"title":"Gamedev Math","uri":"/godot_recipes/4.x/math/index.html"},{"content":" AI/Behavior Automated behavior and (sometimes) smarter entities.\nIn this section: Chasing the player Homing missile Pet Following ","description":"","tags":null,"title":"AI/Behavior","uri":"/godot_recipes/4.x/ai/index.html"},{"content":"Before we can make enemies, powerups, or any other game objects, we need a place where they can all exist together with the player. In most games, this would be called a “level” or “main” scene, and that’s what we’ll call it here.\nStart the scene with a Node2D called “Main” and save it.\nCreating the background Add a Sprite2D child. Name this sprite “Background” and add the Space_BG (2 frames) (64 x 64).png as its texture.\nThis image has two frames, each 64x64 pixels in size. We’d like the image to tile across the full size of the screen, so start with the following settings:\nUnder Offset set Centered to “off”. This makes the image’s top left corner start at the origin rather than its center.\nUnder Region, turn Enabled “on”, and then set the Rect to a width of 240 and a height of 320. This makes the image stretch to the size of the screen.\nUnder Texture change Repeat to Enabled. This causes the image to repeat over the full size of the screen.\nNow add the player to the scene by selecting the Main node and clicking the Instantiate Child Scene button.\nAnimating the background We can make the scene more dynamic by animating the background. While we could do this in code by changing the region_rect property every frame, we’ll use an AnimationPlayer node instead; add one as a child of Main.\nAt the bottom of the editor window, you’ll see the Animation panel. There’s a lot of information there, so let’s look at how it’s laid out:\nClick the Animation button and choose New Animation. You can name the new animation scroll. Set its Length to 2 and toggle the Looping and Autoplay buttons.\nAnimations work by adding tracks that represent properties that you want the AnimationPlayer to control. In the timeline of the player, you’ll add keyframes that define what value you want the property to have at that particular time.\nWe can add keyframes to the animation by clicking the key icon that now appears next to every property in the Inspector. Make sure the scrubber (the blue indicator on the timeline) is at time 0, then select the Background and click the key next to Region/Rect. You’ll be asked if you want to create a new track and then you’ll see the new track added to the animation panel, with a small dot representing the keyframe you’ve just added. Drag the scrubber to time 2 and then change the y value of the Region/Rect property to 64. Click the key to add another keyframe.\nNow when you press Play on the animation, you should see the background slowly scrolling behind the player.\nNext steps The main scene is now ready for us to add enemies. In the next step we’ll make a single enemy scene, as we did with the bullets, and then instantiate that multiple times.\nPrev Next ","description":"","tags":null,"title":"Main Scene","uri":"/godot_recipes/4.x/games/first_2d/first_2d_06/index.html"},{"content":" Physics Learn how to use Godot’s physics nodes.\nIn this section: RigidBody2D: Look at Target RigidBody2D: Drag and Drop Character to Rigid Body Interaction Asteroids-style Physics (using RigidBody2D) ","description":"","tags":null,"title":"Physics","uri":"/godot_recipes/4.x/physics/index.html"},{"content":"Problem You want to make a rolling cube in 3D.\nSolution Rolling a cube is trickier than it seems. You can’t just rotate the cube around its center:\nInstead, the cube needs to be rotated around its bottom edge.\nHere’s the tricky part: which bottom edge? It depends on which direction the cube is rolling.\nIn preparing this recipe, I experimented with a few different solutions to this problem:\nPure math - calculating and applying rotation transforms AnimationPlayer - using animations to key the rotations and offsets Helper nodes - using Spatial(s) as rotation helpers They all worked fine, but I found the last option the most flexible and easiest to adapt, so that’s what we’ll do here.\nNode setup Cube: CharacterBody3D Pivot: Node3D Mesh: MeshInstance3D Collision: CollisionShape3D Tip You can do this with RigidBody3D, CharacterBody3D, or Area3D as your collision node. There will be minor differences in how you handle movement. Which node you choose should depend on what other behavior you want in your game. For this recipe, we’re only concerned with the movement.\nBy default, everything is centered at (0, 0, 0) so the first thing we’re going to do is offset everything so that the bottom center of the cube is the CharacterBody3D’s position.\nThe default size of a BoxMesh3D is (1, 1, 1), so do this, move the mesh and collision nodes both up to (0, 0.5, 0), leaving the rest where they are. Now when you select the root node, its position will be the bottom of the cube:\nNow when you want to roll the cube, you’ll need to move the Pivot 0.5 in the direction you want to move. Since the mesh is attached, you need to move it the opposite amount. For example, to roll to the right (+X), you’ll end up with this:\nNow the pivot node is at the correct edge and rotating it will also rotate the mesh.\nMovement script The movement is broken in to 3 steps:\nStep 1 Here we apply the two offsets shown above: shift the Pivot in the direction of movement, and shift the Mesh in the opposite direction.\nStep 2 In this step we animate the rotation. We find the axis of rotation using the cross product of the direction and the down vector. Then we use a Tween to animate rotating the pivot’s transform.\nStep 3 Finally, once the animation has finished, we need to reset everything so that it’s ready to happen again. In the end, we want to have the cube moved 1 unit in the chosen direction (for a cube of size 1) and have the pivot and mesh back at their original positions.\nextends CharacterBody3D @onready var pivot = $Pivot @onready var mesh = $Pivot/MeshInstance3D var cube_size = 1.0 var speed = 4.0 var rolling = false func _physics_process(delta): var forward = Vector3.FORWARD if Input.is_action_pressed(\"ui_up\"): roll(forward) if Input.is_action_pressed(\"ui_down\"): roll(-forward) if Input.is_action_pressed(\"ui_right\"): roll(forward.cross(Vector3.UP)) if Input.is_action_pressed(\"ui_left\"): roll(-forward.cross(Vector3.UP)) func roll(dir): # Do nothing if we're currently rolling. if rolling: return rolling = true # Step 1: Offset the pivot. pivot.translate(dir * cube_size / 2) mesh.global_translate(-dir * cube_size / 2) # Step 2: Animate the rotation. var axis = dir.cross(Vector3.DOWN) var tween = create_tween() tween.tween_property(pivot, \"transform\", pivot.transform.rotated_local(axis, PI/2), 1 / speed) await tween.finished # Step 3: Finalize the movement and reset the offset. transform.origin += dir * cube_size var b = mesh.global_transform.basis pivot.transform = Transform3D.IDENTITY mesh.position = Vector3(0, cube_size / 2, 0) mesh.global_transform.basis = b rolling = false If your cube’s texture isn’t symmetrical, you may notice that it’s resetting after every roll. To preserve the rotation of the mesh, add the following:\nIn Step 1:\nChange mesh.translate(-dir) to mesh.global_translate(-dir).\nIn Step 3:\nAdd two lines to keep the mesh rotation after reset:\n# Step 3: Finalize the movement and reset the offset. transform.origin += dir * cube_size var b = mesh.global_transform.basis # Save the mesh rotation. pivot.transform = Transform3D.IDENTITY mesh.position = Vector3(0, cube_size / 2, 0) mesh.global_transform.basis = b # Restore the mesh rotation. Checking for collisions If you plan to have obstacles in your game, you can check for collisions before moving (similar to any other grid-based movement scheme). Add a raycast check before Step 1 of the move:\n# Cast a ray before moving to check for obstacles var space = get_world_3d().direct_space_state var ray = PhysicsRayQueryParameters3D.create(mesh.global_position, mesh.global_position + dir * cube_size, collision_mask, [self]) var collision = space.intersect_ray(ray) if collision: return Note You could also use a RayCast3D node. Just remember to call force_raycast_update() before checking.\nPlaying with transitions You can add a lot of “personality” to the cube’s rolling behavior by changing which TransitionType you use. The default is Tween.TRANS_LINEAR, which results in a constant speed throughout the movement.\nBy setting a different transition type, you can get a very different feel. For example:\nvar tween = create_tween().set_trans(Tween.TRANS_CUBIC).set_ease(Tween.EASE_IN) Download This Project Download the project code here: https://github.com/godotrecipes/rolling_cube\nRelated recipes Transforms ","description":"","tags":null,"title":"Rolling Cube","uri":"/godot_recipes/4.x/3d/rolling_cube/index.html"},{"content":" Audio Helpful recipes for adding sound effects and music to your game.\nIn this section: Audio Manager ","description":"","tags":null,"title":"Audio","uri":"/godot_recipes/4.x/audio/index.html"},{"content":"Now that our player can shoot, let’s give them something to shoot at.\nSetting up the scene We’ll use an Area2D for the enemy, since we need it to detect overlap - either with the player’s bullets, or with the player itself.\nHere’s are the nodes we’ll need:\nEnemy: Area2D Sprite2D CollisionShape2D AnimationPlayer MoveTimer: Timer ShootTimer: Timer Select the area node and click the Node tab next to the Inspector. Under Groups, type “enemies” an click Add. Remember the code we wrote on the bullet? It looks for objects in the “enemies” group.\nIn the sprite’s Texture, add Bon_Bon (16 x 16).png and set its Animation/Hframes to 4.\nAs you’ve done before, add a rectangular collision shape and size it to fit. Enable One Shot on both timer nodes.\nIn the AnimationPlayer, add an animation called “bounce” and set it to looping and autoplay. Set the Snap at the bottom of the animation panel to 0.05.\nSelect the sprite node and press the key icons next to Texture and Hframes to create tracks for them. We’re doing this because later we’ll add an “explosion” animation that will use different values for these properties.\nNow we’ll key the individual Frames values we want. Start with keying Frames each .1 seconds to values in this order2, 1, 0, 3. Finally, key 0 again and put it immediately after. This will make a “pulsing” animation where the sprite grows and then bounces a little at the end. The animation setup should look like this:\nPress the play button to see it in action. Feel free to adjust it if you’d like.\nNow add another animation called “explode”. Set its length to 0.4 seconds.\nChange the sprite’s Texture to Explosion (16 x 16).png and keyframe that property. Since this image has a different number of frames than the enemy image, we also need to change Hframes to 6 and keyframe that.\nNow keyframe Frame to 0 at time 0 and to 5 at time 0.4. Play the animation to see it in action.\nEnemy script The enemies will spawn at the top of the screen in a grid. After a random amount of time, they’ll descend toward the player and then return to the top if they weren’t destroyed. Periodically, they’ll also shoot at the player.\nAdd a script, and start with the variables:\nextends Area2D var start_pos = Vector2.ZERO var speed = 0 @onready var screensize = get_viewport_rect().size The start_pos variable is going to keep track of the enemy’s starting position so that after it moves, it can return to its original location. We’ll set it when the enemy is spawned and we call its start() function.\nfunc start(pos): speed = 0 position = Vector2(pos.x, -pos.y) start_pos = pos await get_tree().create_timer(randf_range(0.25, 0.55)).timeout var tween = create_tween().set_trans(Tween.TRANS_BACK) tween.tween_property(self, \"position:y\", start_pos.y, 1.4) await tween.finished $MoveTimer.wait_time = randf_range(5, 20) $MoveTimer.start() $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() When we spawn our enemies we’ll call this function and pass it a position vector representing where on the screen the enemy should go. Note that we actually spawn it above the top of the screen (negative y value). This is so that we can animate it coming onto the screen using a tween. We also randomize the two timers so that all enemies won’t be moving and shooting at the same time.\nConnect both of the timers’ timeout signals.\nfunc _on_timer_timeout(): speed = randf_range(75, 100) func _on_shoot_timer_timeout(): $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() We can start moving when the timer runs out, and we’ll also shoot, but we haven’t made a bullet yet, so that part will come later. Now that we’re changing the speed, we can move using it.\nfunc _process(delta): position.y += speed * delta if position.y \u003e screensize.y + 32: start(start_pos) Now if the speed isn’t 0, we’ll see the enemy move down the screen. When it goes off the bottom, we start it all over again.\nWe’ve already written the code in the bullet scene that calls explode() on the enemies it hits, so let’s add that too.\nfunc explode(): speed = 0 $AnimationPlayer.play(\"explode\") set_deferred(\"monitoring\", false) died.emit(5) await $AnimationPlayer.animation_finished queue_free() In this function, we stop moving, play the explosion animation, and then delete the enemy when it’s finished. The set_deferred() call makes sure to turn off monitoring on the enemy. This is so that while the enemy is exploding, another bullet can’t hit it again.\nAdd the died signal at the top of the script:\nsignal died We’ll use that signal to let the main scene know that the player just earned some points.\nSpawning enemies Now let’s go to the Main scene and add these enemies to the game. Add a script to Main and start by loading the enemy scene:\nextends Node2D var enemy = preload(\"res://enemy.tscn\") var score = 0 Spawning enemies ordinarily won’t happen until we’ve pressed the “Start” button to begin the game, but since we haven’t made that yet, we’ll just spawn them immediately:\nfunc _ready(): spawn_enemies() func spawn_enemies(): for x in range(9): for y in range(3): var e = enemy.instantiate() var pos = Vector2(x * (16 + 8) + 24, 16 * 4 + y * 16) add_child(e) e.start(pos) e.died.connect(_on_enemy_died) This makes 27 enemies and positions them in a grid in the top half of the screen. We also make sure to connect the died signal of each, so we need to create that function:\nfunc _on_enemy_died(value): score += value We don’t have a way to display the score yet, but we’ll get to that soon.\nPlay the scene and you should see a bunch of enemies appear at the top and periodically fall down the screen. Next, we’ll make them shoot.\nPrev Next ","description":"","tags":null,"title":"Enemies","uri":"/godot_recipes/4.x/games/first_2d/first_2d_07/index.html"},{"content":"Problem You want to click-and-drag to select multiple units, RTS style.\nSolution Realtime strategy (RTS) games often require giving orders to many units at once. A typical style of selecting multiple units is to click-and-drag a box around them. Once the units are selected, clicking on the map commands them to move.\nHere’s an example of what we’re going for:\nUnit setup To test this out, we’ll need some basic RTS-style units. They are set up to move towards a target and to avoid running into each other. We won’t go into too much detail on them in this tutorial. The unit script is commented if you’d like to use it as a base for creating your own RTS units. See below for a link to download the project.\nWorld setup Processing the unit selection will happen in the world. We’ll start with a Node2D called “World” and add a few Unit instances in it. Attach a script to the World node and add the following variables:\nextends Node2D var dragging = false # Are we currently dragging? var selected = [] # Array of selected units. var drag_start = Vector2.ZERO # Location where drag began. var select_rect = RectangleShape2D.new() # Collision shape for drag box. Note that once we’ve drawn the box, we’ll need a way to find what units are inside it. The RectangleShape2D will allow us to query the physics engine and see what we collided with.\nDrawing the box We’ll be using the left mouse button for this. Clicking starts a drag and then letting go ends it. During dragging, we’ll draw the rectangle for visibility.\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: # If the mouse was clicked and nothing is selected, start dragging if selected.size() == 0: dragging = true drag_start = event.position # If the mouse is released and is dragging, stop dragging elif dragging: dragging = false queue_redraw() if event is InputEventMouseMotion and dragging: queue_redraw() func _draw(): if dragging: draw_rect(Rect2(drag_start, get_global_mouse_position() - drag_start), Color.YELLOW, false, 2.0) Selecting the units Now that we’ve got a selection box, we need to find the units that are inside it. When we release the button and the drag ends, we must query the physics space to find the units. Note that the units are CharacterBody2D, but Area2D or other bodies would work as well.\nWe’ll use PhysicsDirectSpaceState2D.intersect_shape() to find the units. This requires a shape (our rectangle) and a transform (our location). See Godot docs for details.\nelif dragging: dragging = false queue_redraw() var drag_end = event.position select_rect.extents = abs(drag_end - drag_start) / 2 We start by recording the location when we released the button, and use that to set the RectangleShape2D’s extents (remember: extents are measured from the rectangle’s center, so they’re half the full width/height).\nvar space = get_world_2d().direct_space_state var query = PhysicsShapeQueryParameters2D.new() query.shape = select_rect query.collision_mask = 2 # Units are on collision layer 2 query.transform = Transform2D(0, (drag_end + drag_start) / 2) selected = space.intersect_shape(query) Now we get a reference to the physics state and set up our shape query using PhysicsShapeQueryParameters2D, assigning it our shape, and using the center of the dragged area as the origin for the query’s transform. Our result after calling intersect_shape() is an array of dictionaries, which looks like this:\n[{ \"rid\": RID(4093103833089), \"collider_id\": 32145147326, \"collider\": Unit2:\u003cCharacterBody2D#32145147326\u003e, \"shape\": 0 }, { \"rid\": RID(4123168604162), \"collider_id\": 32229033411, \"collider\": Unit3:\u003cCharacterBody2D#32229033411\u003e, \"shape\": 0 }] Each of those collider items is a reference to a unit, so we can use this to notify them that they’ve been selected, activating the outline shader:\nfor item in selected: item.collider.selected = true Commanding the units Finally, we can command the selected units to move by clicking somewhere on the screen:\nfunc _unhandled_input(event): if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT: if event.pressed: # If the mouse was clicked and nothing is selected, start dragging if selected.size() == 0: dragging = true drag_start = event.position # Otherwise a click tells the selected units to move else: for item in selected: item.collider.target = event.position item.collider.selected = false selected = [] The else clause here triggers if we click the mouse when selected is greater than 0. Each item’s target is set, and we make sure to deselect the units so we can start again.\nWrapping up This technique can be expanded to a wide range of RTS or other game styles. Download the full project below and use it as a base for your own game.\nDownload This Project Download the project code here: https://github.com/godotrecipes/multi_unit_select\nRelated recipes Mouse Input ","description":"","tags":null,"title":"Mouse: Drag-select multiple units","uri":"/godot_recipes/4.x/input/multi_unit_select/index.html"},{"content":"Now that our enemy can shoot, let’s give them something to shoot at.\nEnemy bullet scene Make a new EnemyBullet scene just like you made the player bullet earlier. We won’t go into all the steps here, but you can refer back to that part if you’re stuck. The only difference here is that you can use the Enemy_projectile (16 x 16).png image instead.\nThe script will be a little bit different:\nextends Area2D @export var speed = 150 func start(pos): position = pos func _process(delta): position.y += speed * delta Connect the screen_exited and area_entered signals of the VisibleOnScreenNotifier2D and Area2D, respectively:\nfunc _on_visible_on_screen_notifier_2d_screen_exited(): queue_free() func _on_area_entered(area): if area.name == \"Player\": queue_free() Notice that we’re detecting the hit on the player, but it’s not doing anything yet. We’ll come back to that once we add a way for the player to take damage.\nAdding shooting to the enemy At the top of the enemy’s script, load the new bullet:\nvar bullet_scene = preload(\"res://enemy_bullet.tscn\") Then update the shooting function:\nfunc _on_shoot_timer_timeout(): var b = bullet_scene.instantiate() get_tree().root.add_child(b) b.start(position) $ShootTimer.wait_time = randf_range(4, 20) $ShootTimer.start() Play the Main scene again and you should have some random enemy bullets appearing.\nPrev Next ","description":"","tags":null,"title":"Enemy Shooting","uri":"/godot_recipes/4.x/games/first_2d/first_2d_08/index.html"},{"content":"Problem You want to make a 3D spaceship that flies in an arcade/cinematic way. You’re not looking for realistic physics, but more of a dog-fighting, “Star Wars”-style of spaceflight.\nSolution To accomplish this, we’ll use a CharacterBody3D for the ship. The three axis inputs (pitch, roll, and yaw) will rotate the body’s basis around the corresponding axis. The direction of motion will always point forward.\nNote You can do this with RigidBody3D and get the same results. See the example project linked below, which includes a rigid body version as well.\nAssets Spaceship models are from this asset pack:\nUltimate Spaceships Pack by Quaternius\nI’ve chosen the “Executioner” ship model:\nFeel free to choose your favorite design.\nSetup Select the gltf file of the ship you want, and click the Import tab. Change the Root Type to CharacterBody3D and click “Reimport”. Then double-click the gltf and you’ll have a new inherited scene with a CharacterBody3D root and a MeshInstance child. Add a CollisionShape3D to the body.\nIn Project Settings -\u003e Input Map, set up the following inputs:\nroll_right / roll_left pitch_up / pitch_down yaw_right / yaw_left throttle_up / throttle_down You can assign keys or controller inputs. Analog stick inputs will work best.\nMovement To start the script, let’s handle the forward movement. Pressing the throttle buttons smoothly increases/decreases the speed.\nextends CharacterBody @export var max_speed = 50.0 @export var acceleration = 0.6 var forward_speed = 0 func get_input(delta): if Input.is_action_pressed(\"throttle_up\"): forward_speed = lerp(forward_speed, max_speed, acceleration * delta) if Input.is_action_pressed(\"throttle_down\"): forward_speed = lerp(forward_speed, 0, acceleration * delta) func _physics_process(delta): get_input(delta) velocity = -transform.basis.z * forward_speed move_and_collide(velocity * delta) Make a test scene with a Camera3D to try it out. You can use a stationary camera or a chase camera. Check that the ship accelerates and slows before moving on to the next step.\nRotation Now we can handle rotation in the three axes. Add the following variables at the top of the script:\n@export var pitch_speed = 1.5 @export var roll_speed = 1.9 @export var yaw_speed = 1.25 var pitch_input = 0.0 var roll_input = 0.0 var yaw_input = 0.0 The three axis speeds will affect the “handling” of the ship. Experiment to find values the work for you and your desired flight style.\nNext, add these lines to get_input() to capture the three axis inputs:\npitch_input = Input.get_axis(\"pitch_down\", \"pitch_up\") roll_input = Input.get_axis(\"roll_right\", \"roll_left\") yaw_input = Input.get_axis(\"yaw_right\", \"yaw_left\") Finally, we need to rotate the ship’s Basis according to the inputs. Note how each input affects one axis of rotation:\ntransform.basis = transform.basis.rotated(transform.basis.z, roll_input * roll_speed * delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(transform.basis.y, yaw_input * yaw_speed * delta) transform.basis = transform.basis.orthonormalized() Improvements Currently the rotations are a little to “sharp”. The ship starts and stops rotating instantly, which feels a bit too unnatural. We can solve this with lerp(), and by adding one more configuration variable to set how “floaty” we’d like the controls to be:\n@export var input_response = 8.0 Change the three axis inputs in get_input() to the following:\npitch_input = lerp(pitch_input, Input.get_axis(\"pitch_down\", \"pitch_up\"), input_response * delta) roll_input = lerp(roll_input, Input.get_axis(\"roll_right\", \"roll_left\"), input_response * delta) yaw_input = lerp(yaw_input, Input.get_axis(\"yaw_right\", \"yaw_left\"), input_response * delta) Now when stopping or changing direction, there’s a little bit of inertia.\nLinking roll/yaw One problem with this control scheme is that it’s awkward. Having to use a separate stick for the yaw input makes it difficult to control, especially when also shooting and using other controls. Many games solve this by linking the roll input to also apply a small amount of yaw. To do this, change the yaw_speed to around 1/4 to 1/2 of the roll_speed.\nIn the get_input() function, change the line getting yaw_input to the following:\nyaw_input = roll_input This is another fun place to experiment by changing the roll and yaw speeds. For example, what if yaw was primary and roll smaller? What if other axes were linked? If your game has different ships, you can give them different values for variety in flight styles/performance.\nWrapping up That’s it, now you can fly! This controller is a great start for whatever space-based game you might have in mind. Add some other ships, and a few effects, and you’re ready go:\nFull script Here’s the complete script:\nextends CharacterBody3D @export var max_speed = 50.0 @export var acceleration = 0.6 @export var pitch_speed = 1.5 @export var roll_speed = 1.9 @export var yaw_speed = 1.25 # Set lower for linked roll/yaw @export var input_response = 8.0 var forward_speed = 0.0 var pitch_input = 0.0 var roll_input = 0.0 var yaw_input = 0.0 func get_input(delta): if Input.is_action_pressed(\"throttle_up\"): forward_speed = lerp(forward_speed, max_speed, acceleration * delta) if Input.is_action_pressed(\"throttle_down\"): forward_speed = lerp(forward_speed, 0.0, acceleration * delta) pitch_input = lerp(pitch_input, Input.get_axis(\"pitch_down\", \"pitch_up\"), input_response * delta) roll_input = lerp(roll_input, Input.get_axis(\"roll_right\", \"roll_left\"), input_response * delta) # yaw_input = lerp(yaw_input, Input.get_axis(\"yaw_right\", \"yaw_left\"), input_response * delta) yaw_input = roll_input func _physics_process(delta): get_input(delta) transform.basis = transform.basis.rotated(transform.basis.z, roll_input * roll_speed * delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(transform.basis.y, yaw_input * yaw_speed * delta) transform.basis = transform.basis.orthonormalized() velocity = -transform.basis.z * forward_speed move_and_collide(velocity * delta) Related recipes Interpolated Camera Download This Project Download the project code here: https://github.com/godotrecipes/3d_spaceship\n","description":"","tags":[],"title":"Arcade-style Spaceship","uri":"/godot_recipes/4.x/3d/spaceship/index.html"},{"content":"The last main piece of our game is the user interface (UI). We need a way to show the player the score and other information. To do this, we’ll use a variety of Control nodes - the nodes Godot provides for building UIs.\nUI scene Start the scene with a MarginContainer and name it UI.\nContainers are Control nodes that are designed to control the size and position of their children. Using them makes it easier to position and move Control nodes without having to do it manually. The MarginContainer makes sure its children don’t get too close to the edge.\nIn the Inspector under Theme Overrides/Constants set all four Margin values to 10. Then, in the menu bar at the top of the viewport, set the anchors to the Top Wide preset.\nNext, we’ll add an HBoxContainer. This type of container organizes its children horizontally. Under that, add a TextureProgressBar, which will represent our ship’s shield level. Name it ShieldBar.\nUnfortunately, there’s not a good image in the art pack to use for a progress bar (there is one, but it isn’t formatted in an easy way to work with). Instead, we’ll use the two images below. One is a green bar and the other is a white outline. Save them in your project folder.\nIn the Texture section, drag the foreground image to the Progress and the background image to the Under texture. The first thing you’ll notice is that it’s very small. Let’s first under Layout set Custom Minimum Size to (80, 16). You’ll notice that the orange selection rectangle got bigger, but the image didn’t. Well, we don’t want the image to just stretch, or it would look bad. Instead we’ll check the Nine Patch Stretch box, and then set the four Stretch Margin values to 3.\nYou should now see a long, unfilled bar. To see what it looks like when filled, change the Value property in the Range section to anything between 0 and 100.\nOn the right side, we’d like to show the score. Now, we could just use a Label node and add a font, but that’s not very fun. The art pack includes a lovely pixel set of digits that we could use instead. We’ll just need to do a little coding to chop it up and show the corect digit(s).\nScore counter Start a new scene and add an HBoxContainer. Name it ScoreCounter then set it to Top Wide and set the Alignment to “End”. Also, set the Theme Overrides/Constants/Separation to 0 (you need to check the box next to the property).\nIn this container, we’ll have a string of TextureRect nodes showing each digit. We’ll start by adding one and then duplicating it.\nName the TextureRect Digit0. Under Texture, select “New AtlasTexture”, then click the box to open it. Drag Number_font (8 x 8).png into the Atlas property, then set the Region to (32, 8, 8, 8). Set Stretch Mode to “Keep Aspect Centered”.\nSelect the Digit0 node and press Ctrl-D 7 times to create duplicates of the node. The picture below shows what you should see after this step:\nWe now have an issue, though. Even though we’ve duplicated the TextureRect to create 8 unique copies, they are all using the same AtlasTexture in the Texture property. This means that when we change the Region to show a different digit, it will change on all the digits.\nThis is because Resource objects (such as Texture) are loaded into memory and then shared - there’s really only one texture. While this is very efficient, because you don’t waste memory loading the same image multiple times, it means that when we do want things to be unique, we have to specify it.\nOn each of the nodes, click the down arrow next to the AtlasTexture and select “Make Unique”.\nNow we’ll add a script to ScoreCounter that will choose the correct Region values for whichever digit it needs to display.\nextends HBoxContainer var digit_coords = { 1: Vector2(0, 0), 2: Vector2(8, 0), 3: Vector2(16, 0), 4: Vector2(24, 0), 5: Vector2(32, 0), 6: Vector2(0, 8), 7: Vector2(8, 8), 8: Vector2(16, 8), 9: Vector2(24, 8), 0: Vector2(32, 8) } func display_digits(n): var s = \"%08d\" % n for i in 8: get_child(i).texture.region = Rect2(digit_coords[int(s[i])], Vector2(8, 8)) We start by making a list of the coordinates in the image where each digit is found. Then, display_digits() will format the number to an 8 digit number (for example, 258 would become \"00000258\"). Then, for each digit, we can apply the correct coordinates from the array.\nScripting the UI Go back to the UI scene and add the ScoreCounter to the HBoxContainer, then add a script to UI.\nextends MarginContainer @onready var shield_bar = $HBoxContainer/ShieldBar @onready var score_counter = $HBoxContainer/ScoreCounter func update_score(value): score_counter.display_digits(value) func update_shield(max_value, value): shield_bar.max_value = max_value shield_bar.value = value We’ll call these functions from Main whenever we need to update the score or the shield.\nAdding the UI to main Now in the Main scene add a CanvasLayer node, and instance the UI as its child. The CanvasLayer node creates another drawing layer, so our UI will be drawn on top of the rest of the game.\nChange this function in main.gd:\nfunc _on_enemy_died(value): score += value $CanvasLayer/UI.update_score(score) Run the game and see that your score goes up when shooting enemies.\nPlayer shield We can also add the shield to the player’s script. Add these new lines at the top of player.gd:\nsignal died signal shield_changed @export var max_shield = 10 var shield = max_shield: set = set_shield This set = syntax tells Godot that we want to call the set_shield() function whenever the shield variable has its value set.\nfunc set_shield(value): shield = min(max_shield, value) shield_changed.emit(max_shield, shield) if shield \u003c= 0: hide() died.emit() We can also connect the ship’s area_entered signal so that we can detect when an enemy hits the ship:\nfunc _on_area_entered(area): if area.is_in_group(\"enemies\"): area.explode() shield -= max_shield / 2 And in the enemy bullet, add some damage to the shield when it hits:\nfunc _on_area_entered(area): if area.name == \"Player\": queue_free() area.shield -= 1 Finally, we need to connect the player’s shield_changed signal to the function in the UI that updates the shield bar. You can do this in the Inspector by selecting the Player node in the Main scene. Under the Node tab, double-click the shield_changed signal to open the “Connect a Signal” window. In this window, select the UI node and type update_shield in the Receiver Method box.\nRun the game again and check that your shield depletes when you get hit by a bullet or an enemy.\nNext steps We’re almost done with the basic functionality. We just need a way to start and end the game.\nPrev Next ","description":"","tags":null,"title":"UI and Score","uri":"/godot_recipes/4.x/games/first_2d/first_2d_09/index.html"},{"content":"Problem You’ve imported a rigged, animated 3D character in Godot and set up its animations using AnimationTree. Now you need to implement movement: you need a character controller.\nSolution In this recipe, we’ll assume you’ve already imported your character model and animations, and that you’re set up AnimationTree to handle transitioning and blending the animations. If you haven’t yet, see Importing Assets and Character Animation for details. As a reminder, we’re using the art packs linked in the section description.\nAdding collision We’ve chosen CharacterBody3D as the root node of the imported scene, and it’s complaining about a missing collision shape, so let’s fix that first. Add a CollisionShape3D child and choose CapsuleShape3D as its Shape property.\nSize and position the capsule to enclose the character’s body. For reference, here are the values I used:\nNote that the imported rig is positioned so that its feet are on the “ground”, ie at the body’s position. This will be helpful later, as the player’s position will represent its position on the ground, rather than floating in mid-air if it were at the center of its body.\nIf you’re familiar with Godot’s 3D orientation, you’ll also notice that the character is facing the +Z direction, which is backwards. Select the Skeleton3D node and set its Y Rotation to 180 to correct this.\nInput actions In the Input Map, we’re using the following inputs: forward, back, left, right, and jump. Assign them to whatever keys/buttons you prefer.\nCamera There are many ways to handle a 3D camera that follows the player. For this example, we’ll use a SpringArm3D as the camera “mount”.\nThe SpringArm3D node works by casting a ray and then moving its children to the collision point. Using this for a camera means nothing can get between the camera and the player, and we can implement zoom by varying this length.\nAdd one as a child of the root node, and then add a Camera3D as a child of that.\nIn the spring arm’s properties, set Spring Length to 5, the Margin to 0.1, and the Position to (0, 2.5, 0).\nWe don’t want the spring arm to collide with the player’s capsule shape, so in the root CharacterBody3D set the collision layer to 2. Since the spring arm is checking collision layer 1, that will prevent the camera hitting the player’s head.\nCollision Layers Eventually, we’ll want to organize our collision layers for various game objects: player, environment, enemies, etc.\nMovement Now we are ready to add a script to the player. We’ll start with the variables we’ll need:\nextends CharacterBody3D class_name Knight @export var speed = 5.0 @export var acceleration = 4.0 @export var jump_speed = 8.0 var gravity = ProjectSettings.get_setting(\"physics/3d/default_gravity\") var jumping = false And then, some references to the nodes we’ll need to access:\n@onready var spring_arm = $SpringArm3D @onready var model = $Rig @onready var anim_tree = $AnimationTree @onready var anim_state = $AnimationTree.get(\"parameters/playback\") We’ll use the anim_tree reference to set the blend position for the Idle/Walk/Run blendspace and the trigger conditions for jumping. Select the AnimationTree and you can see these properties in the Inspector:\nanim_state is a reference to the animation state machine, which we can use to call transitions between animations. See the Character Animation recipe for how we set these up.\nMovement is a matter of getting the player’s input and calling move_and_slide():\nfunc _physics_process(delta): velocity.y += -gravity * delta get_move_input(delta) move_and_slide() The player’s input should be applied to the horizontal motion only (X and Z axes), since gravity is acting on the Y axis. For that reason, we’ll temporarily zero out the velocity.y, set the input, and then restore the value when we’re done.\nNote that we’re rotating the input vector using the camera’s rotation - our character is going to move forward in whatever direction the camera is facing.\nfunc get_move_input(delta): var vy = velocity.y velocity.y = 0 var input = Input.get_vector(\"left\", \"right\", \"forward\", \"back\") var dir = Vector3(input.x, 0, input.y).rotated(Vector3.UP, spring_arm.rotation.y) velocity = lerp(velocity, dir * speed, acceleration * delta) velocity.y = vy Before we do anything else, this is a good point to test things out. You can make a quick test scene with a big StaticBody3D for the ground, or start making a scene using the dungeon pack assets.\nYou should be able to move forward/back/left/right (without any animations yet).\nCamera Control Now let’s get the camera working. We want to control the camera with mouse movement. We’ll add a variable that lets us adjust the sensitivity.\n@export var mouse_sensitivity = 0.0015 Then, we want to detect mouse motion and rotate the spring arm accordingly. Rotating the arm around the X axis tilts it up and down (using the mouse’s y motion), and rotating it around Y changes its facing direction (using the mouse’s x motion). We also clamp the camera’s tilt so that it doesn’t go too far up/down.\nfunc _unhandled_input(event): if event is InputEventMouseMotion: spring_arm.rotation.x -= event.relative.y * mouse_sensitivity spring_arm.rotation_degrees.x = clamp(spring_arm.rotation_degrees.x, -90.0, 30.0) spring_arm.rotation.y -= event.relative.x * mouse_sensitivity Try it out and you should see when pressing “forward”, the character moves in the direction the camera faces.\nNow we need to rotate the character so they face in the direction of movement.\nWe’ll add a variable for the rotation speed, so that we don’t snap instantly to the new heading.\n@export var rotation_speed = 12.0 And then add this in _physics_process(), after move_and_slide():\nif velocity.length() \u003e 1.0: model.rotation.y = lerp_angle(model.rotation.y, spring_arm.rotation.y, rotation_speed * delta) Using lerp_angle() ensures we’ll always rotate the shortest direction to the new angle (rather than going the long way around from a 359° rotation to a 1° rotation, for example).\nIWR Animations Now that we have movement and rotation, we need to choose animations. The idea is to take the character’s horizontal velocity (the x/z movement) and use it to set the blend position in the IWR blendspace we created.\nIn get_move_input(), we’re setting the player’s velocity. Just after that, we can set the blend position:\nvelocity = lerp(velocity, dir * speed, acceleration * delta) var vl = velocity * model.transform.basis anim_tree.set(\"parameters/IWR/blend_position\", Vector2(vl.x, -vl.z) / speed) Since velocity is in global space, but the character model is rotating, we need to transform velocity into model space using the model’s basis. Once we have that, we need to map that 3D vector to the 2D vector of the blend space, dividing by speed so that we’ll get values between -1 and 1. Also, -z is forward, but +y represents the blendspace forward animation, so we negate the value to make them match.\nNote that you can get that parameter path by looking at the Inspector for the AnimationTree - you can even drag it into the script window to fill it in.\nAttacks We can handle attacks by first adding an input action called \"attack\", which I’ve assigned to the left mouse button.\nSince we have 3 separate attacks in the AnimationTree, we’ll make a list of them:\nvar attacks = [ \"1h_slice_diagonal\", \"1h_slice_horizontal\", \"1h_attack_chop\" ] Then, in _unhandled_input(), pick a random animation from the list when the action is pressed:\nif event.is_action_pressed(\"attack\"): anim_state.travel(attacks.pick_random()) Jumping Jumping is a little bit more involved, because it involves three separate animations. As a reminder, this is how we set up the state machine:\nFirst, we want to transition to the “Jump_Start” animation by setting jumping = true. This triggers the transition in the state machine.\nif is_on_floor() and Input.is_action_just_pressed(\"jump\"): velocity.y = jump_speed jumping = true anim_tree.set(\"parameters/conditions/grounded\", false) anim_tree.set(\"parameters/conditions/jumping\", jumping) Next, we need to know when we touch the ground, so we can transition out of the “Jump_Idle” animation. To do this, we need to keep track of our grounded status by comparing it with the previous frame. Add a new variable at the top:\nvar last_floor = true And then this if statement after the first one above:\n# We just hit the floor after being in the air if is_on_floor() and not last_floor: jumping = false anim_tree.set(\"parameters/conditions/grounded\", true) last_floor = is_on_floor() Finally, there’s the direct transition to “Jump_Idle” that happens if we step off a ledge:\n# We're in the air, but we didn't jump if not is_on_floor() and not jumping: anim_state.travel(\"Jump_Idle\") anim_tree.set(\"parameters/conditions/grounded\", false) Wrapping up We’ve now got a functional, controllable character with a chase camera and multiple animations. What’s next?\nSee the section description for more examples of working in 3D and for example Godot projects you can download.\nCompanion Video ","description":"","tags":null,"title":"Character Controller","uri":"/godot_recipes/4.x/3d/assets/character_controller/index.html"},{"content":"Problem You need to have a game entity such as a pet or minion, follow a character.\nSolution We start by adding a Marker2D to the character. This will represent the place where the pet wants to “hang out” near the character.\nIn this example, we’ve made it a child of the Sprite2D, because the character’s code uses $Sprite2D.scale.x = -1 to flip the horizontal direction when the character moves left. Since the marker is a child of the sprite, it will flip too.\nPet script Here’s the script for the pet.\nextends CharacterBody2D @export var parent : CharacterBody2D var speed = 25 @onready var follow_point = parent.get_node(\"Sprite2D/FollowPoint\") The parent variable holds a reference to the character the pet should follow. We then get the FollowPoint node from that so we can get its position in _physics_process():\nfunc _physics_process(delta): var target = follow_point.global_position velocity = Vector2.ZERO if position.distance_to(target) \u003e 5: velocity = position.direction_to(target) * speed if velocity.x != 0: $Sprite2D.scale.x = sign(velocity.x) if velocity.length() \u003e 0: $AnimationPlayer.play(\"run\") else: $AnimationPlayer.play(\"idle\") move_and_slide() If it’s close to the target point, we stop the pet’s movement.\nNavigating obstacles Depending on your world, you may find the pet gets stuck on obstacles. For more robust following, you can use navigation. See TileMap Navigation for an example.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ai_behavior_demos\n","description":"","tags":null,"title":"Pet Following","uri":"/godot_recipes/4.x/ai/pet_following/index.html"},{"content":"Our last step is to add a start button and a “game over” state to the game.\nStarting the game Currently when we run the game, it starts immediately. Let’s add a button to start it.\nIn Main as a child of the CanvasLayer, add a CenterContainer and set its layout to Full Rect. Then add a TextureButton child. Name this button Start and add the START (48 x 8).png image as its Normal texture.\nAdd a reference at the top of the script:\n@onready var start_button = $CanvasLayer/CenterContainer/Start Connect this button’s pressed texture to Main and add this code:\nfunc _on_start_pressed(): start_button.hide() new_game() The new_game() function handles starting the game, so change _ready() so that it no longer spawns enemies, but just ensures the button is showing:\nfunc _ready(): start_button.show() #\tspawn_enemies() Now add the new_game() function:\nfunc new_game(): score = 0 $CanvasLayer/UI.update_score(score) $Player.start() spawn_enemies() Now the button should show when you run the scene, and pressing it starts the game.\nEnding the game Add a TextureRect as a child of the CenterContainer and name the node GameOver. Use the GAME_OVER (72 x 8).png image. It will overlap with the start button, but that’s ok, we’re only ever going to show one at a time.\nAdd another reference at the top of the script:\n@onready var game_over = $CanvasLayer/CenterContainer/GameOver And add game_over.hide() to _ready().\nConnect the player’s died signal in Main.\nfunc _on_player_died(): get_tree().call_group(\"enemies\", \"queue_free\") game_over.show() await get_tree().create_timer(2).timeout game_over.hide() start_button.show() This will show the “game over” image for 2 seconds, then switch back to the start button so you can play again. Try it out and see if you can play a few games.\nPrev Next ","description":"","tags":null,"title":"Starting and Ending the Game","uri":"/godot_recipes/4.x/games/first_2d/first_2d_10/index.html"},{"content":"Problem You need a dynamic camera that moves and zooms to keep multiple objects on screen at the same time.\nAn example might be in a 2 player game, keeping both players on-screen as they move farther and closer together, like so:\nSolution In a single-player game, you’re probably used to attaching the camera to the player, so that it automatically follows them. We can’t really do this here because we have 2 (or more) players or other game objects that we want to keep on the screen at all times.\nWe need our camera to do 3 things:\nAdd/remove any number of targets. Keep the camera’s position centered at the midpoint of the targets. Adjust the camera’s zoom to keep all targets on screen. Create a new scene with a Camera2D and attach a script. We’ll add this camera to our game once we’re done.\nLet’s break down how the script works.\nNote You can see the full script at the end of the article.\nHere’s how the script starts:\nextends Camera2D @export var move_speed = 30 # camera position lerp speed @export var zoom_speed = 3.0 # camera zoom lerp speed @export var min_zoom = 5.0 # camera won't zoom closer than this @export var max_zoom = 0.5 # camera won't zoom farther than this @export var margin = Vector2(400, 200) # include some buffer area around targets var targets = [] # Array of targets to be tracked. @onready var screen_size = get_viewport_rect().size These settings will let you adjust the camera’s behavior. We’ll lerp() all camera changes, so setting the move/zoom speeds to lower values will introduce some delay in the camera “catching up” to sudden changes.\nMaximum and minimum zoom values will also depend on the size of objects in your game and how close or far you want to get. Adjust to suit.\nThe margin property is going to add some extra space around the targets so they’re not right on the edge of the viewable area.\nLastly, we have our array of targets and we get the viewport size so that we can properly calculate the scale.\nfunc add_target(t): if not t in targets: targets.append(t) func remove_target(t): if t in targets: targets.erase(t) For adding and removing targets, we have two helper functions. You can use these during gameplay to change what targets are being tracked (“Player 3 has entered the game!”). Note that we don’t want to have the same target tracked twice, so we reject it if it’s already there.\nMost of the functionality happens in _process(). First, moving the camera:\nfunc _process(delta): if !targets: return # Keep the camera centered between the targets var p = Vector2.ZERO for target in targets: p += target.position p /= targets.size() position = lerp(position, p, move_speed * delta) Here, we loop through the targets’ positions and find the common center. Using lerp() we make sure it moves there smoothly.\nNext, we’ll handle the zoom:\n# Find the zoom that will contain all targets var r = Rect2(position, Vector2.ONE) for target in targets: r = r.expand(target.position) r = r.grow_individual(margin.x, margin.y, margin.x, margin.y) var z if r.size.x \u003e r.size.y * screen_size.aspect(): z = 1 / clamp(r.size.x / screen_size.x, min_zoom, max_zoom) else: z = 1 / clamp(r.size.y / screen_size.y, min_zoom, max_zoom) zoom = lerp(zoom, Vector2.ONE * z, zoom_speed) The key functionality here comes from Rect2. We want to find a rectangle that encloses all the targets, which we can get with the expand() method. We then grow the rect by the margin.\nHere you can see the rectangle being drawn (press “Tab” in the demo project to enable this drawing):\nThen, depending whether the rectangle is wider or taller (relative to the screen’s aspect ratio), we find the scale and clamp it in the max/min range we’ve defined.\nFull script extends Camera2D @export var move_speed = 30 # camera position lerp speed @export var zoom_speed = 3.0 # camera zoom lerp speed @export var min_zoom = 5.0 # camera won't zoom closer than this @export var max_zoom = 0.5 # camera won't zoom farther than this @export var margin = Vector2(400, 200) # include some buffer area around targets var targets = [] @onready var screen_size = get_viewport_rect().size func _process(delta): if !targets: return # Keep the camera centered among all targets var p = Vector2.ZERO for target in targets: p += target.position p /= targets.size() position = lerp(position, p, move_speed * delta) # Find the zoom that will contain all targets var r = Rect2(position, Vector2.ONE) for target in targets: r = r.expand(target.position) r = r.grow_individual(margin.x, margin.y, margin.x, margin.y) var z if r.size.x \u003e r.size.y * screen_size.aspect(): z = 1 / clamp(r.size.x / screen_size.x, max_zoom, min_zoom) else: z = 1 / clamp(r.size.y / screen_size.y, max_zoom, min_zoom) zoom = lerp(zoom, Vector2.ONE * z, zoom_speed * delta) # For debug get_parent().draw_cam_rect(r) func add_target(t): if not t in targets: targets.append(t) func remove_target(t): if t in targets: targets.remove(t) Download This Project Download the project’s example code here: https://github.com/godotrecipes/multitarget_camera\n","description":"","tags":null,"title":"Multitarget Camera","uri":"/godot_recipes/4.x/2d/multi_target_camera/index.html"},{"content":"Problem You want to make an arcade-style car game, so you’re looking for simplicity over realistic physics. In this recipe, you’ll learn how to make a fun, driveable car using a rolling sphere.\nSolution There are a lot of ways to make a driving game. Different games need different levels of realism. If you’re trying to make a light, arcade-style car, you don’t need all of the features that Godot’s VehicleBody3D node provides, such as supension, independently modeled wheels, etc.\nInstead, we’re going to use a single RigidBody3D sphere to handle the driving physics. The sphere will be invisible, and the car mesh will be placed at the sphere’s location, making it look like it’s the car that’s driving.\nAs you can see in the preview clip above, the result looks remarkably good (and feels great to play!). Read on, and you’ll see that the amount of code required is also surprisingly small.\nInputs For control, we’re going to add four inputs to the Input Map:\naccelerate brake steer_left steer_right You can use keyboard input, game controller, or both. However, we recommend going with the analog stick for better steering.\nNode setup The car is made with two main nodes: a RigidBody3D sphere for the physics, and a MeshInstance3D to display the car body. Here’s the scene layout:\nRigidBody3D (Car) CollisionShape3D (Sphere) CarMesh (Imported model) Here’s how these nodes will interact: pressing “accelerate” will apply a force on the RigidBody3D in the direction the CarMesh is facing, while the turning inputs will rotate the CarMesh. As the ball rolls, it will carry the car mesh along with it (we’ll ignore the ball’s rotation).\nCarMesh Here’s the car model we’ll use:\nNote You can find this and other car models in Kenney’s “Car Kit”, available here: https://kenney.nl/assets/car-kit. Download the whole kit; you can use any of them that you choose. Note that this kit includes the models in multiple formats - you won’t need all of them for your project. GLTF is the recommended format for use with Godot.\nIf you use the GLTF models, you shouldn’t have adjust anything in the import settings.\nHere’s what the node tree looks like when importing the “suv” model:\nNote that the wheels \u0026 body are separate meshes. This will make it easy to add some visual appeal - like turning the wheels when steering.\nBall Add a sphere shape to the CollisionShape3D. We’re using a radius of 1 here, but you’ll want to experiment with the size of the ball to get different driving behaviors.\nHere’s how to adjust the settings on the body:\nAngular Damp: 10 - this property will have a huge effect on the driving feel. A higher value will bring the car to a stop much faster. Gravity Scale: 5 - Default gravity in Godot (9.8) feels a bit floaty, especially when going for an action feel. This will really matter if you plan to have jumps, hills, etc. in your world. You can set this globally in the Project Settings instead, if you prefer. Physics Material/Bounce: 0.1 - Playing around with this value can be a lot of fun. Be careful going above 0.5, though! For the demo, we’ve also added a spherical mesh to the collision shape for debugging purposes. You don’t need this, but it helps when troubleshooting to have a visual of the ball rolling.\nRayCast Finally, add a RayCast3D node as a child of the CarMesh. Set its Target Position to (0, -1, 0).\nWe’re going to use this for ground detection. When the car’s in the air, steering and acceleration won’t work. We can also use it to align the car mesh to a slope (if your game’s track isn’t flat).\nNow we’re ready to start coding.\nScript We’ll begin the script with some node references we’ll need:\nextends RigidBody3D @onready var car_mesh = $CarMesh @onready var body_mesh = $CarMesh/suv2 @onready var ground_ray = $CarMesh/RayCast3D @onready var right_wheel = $CarMesh/suv2/wheel_frontRight @onready var left_wheel = $CarMesh/suv2/wheel_frontLeft Next, some variables configuring the car’s behavior. See the comments describing each one’s purpose.\n# Where to place the car mesh relative to the sphere var sphere_offset = Vector3.DOWN # Engine power var acceleration = 35.0 # Turn amount, in degrees var steering = 18.0 # How quickly the car turns var turn_speed = 4.0 # Below this speed, the car doesn't turn var turn_stop_limit = 0.75 # Variables for input values var speed_input = 0 var turn_input = 0 You can @export these if you’d like to adjust them from the Inspector.\nIn _physics_process() we add a force to the body based on the direction the car is pointing, as well as keeping the car mesh positioned at the ball’s position:\nfunc _physics_process(delta): car_mesh.position = position + sphere_offset if ground_ray.is_colliding(): apply_central_force(-car_mesh.global_transform.basis.z * speed_input) The next step is to get the inputs, but we’ll also check if the ray is colliding with the ground first:\nfunc _process(delta): if not ground_ray.is_colliding(): return speed_input = Input.get_axis(\"brake\", \"accelerate\") * acceleration turn_input = Input.get_axis(\"steer_right\", \"steer_left\") * deg_to_rad(steering) right_wheel.rotation.y = turn_input left_wheel.rotation.y = turn_input Tip At this point, you can try it out. You should be able to accelerate forward and back (but not steer yet).\nNext, still in the _process() function, we’ll rotate the car mesh based on the rotation input. We’ll use slerp() (spherical linear interpolation) to do this smoothly:\n# rotate car mesh if linear_velocity.length() \u003e turn_stop_limit: var new_basis = car_mesh.global_transform.basis.rotated(car_mesh.global_transform.basis.y, turn_input) car_mesh.global_transform.basis = car_mesh.global_transform.basis.slerp(new_basis, turn_speed * delta) car_mesh.global_transform = car_mesh.global_transform.orthonormalized() Warning Because of floating point imprecision, repeatedly rotating a transform will eventually cause it to become distorted. The scale can drift or the axes can become no-perpendicular. In any script where you’re regularly rotating a transform, it’s a good idea to use orthonormalized() to correct any error before it accumulates.\nYou should try playing again at this point. You’ll be able to control the car and drive around, and everything works pretty much as expected. However, there are a few more things to add that will improve the “feel” of the driving.\nFinal touches 1. Align with slopes FIX THIS\nIf you’ve tried driving on a slope, you’ve seen that the car mesh doesn’t tilt at all, it always remains level. That looks unnatural, so let’s use the process described in KinematicBody: Align with Surface to fix that.\nAdd this code after rotating the mesh in _process():\nif ground_ray.is_colliding(): var n = ground_ray.get_collision_normal() var xform = align_with_y(car_mesh.global_transform, n) car_mesh.global_transform = car_mesh.global_transform.interpolate_with(xform, 10.0 * delta) And the align function (notice how we’re using orthonormalized() again?):\nfunc align_with_y(xform, new_y): xform.basis.y = new_y xform.basis.x = -xform.basis.z.cross(new_y) xform.basis = xform.basis.orthonormalized() return xform.orthonormalized() 2. Turn the wheels It looks nice if the front wheels turn when you steer. Add some references to the front wheel meshes at the top of the script:\n@onready var right_wheel = $CarMesh/suv2/wheel_frontRight @onready var left_wheel = $CarMesh/suv2/wheel_frontLeft And right after getting input, add the following:\n# rotate wheels for effect right_wheel.rotation.y = rotate_input left_wheel.rotation.y = rotate_input 3. Tilt the body This one adds lots of visual appeal. We’re going to tilt the car’s body based on the speed of the turn. Add a variable at the top of the script:\nvar body_tilt = 35 The smaller this number, the more extreme the tilt effect will be. Between 35 and 40 works well for the SUV model.\nNow add the following right after rotating the car mesh (in the if statement):\n# tilt body for effect var t = -rotate_input * ball.linear_velocity.length() / body_tilt body_mesh.rotation.z = lerp(body_mesh.rotation.z, t, 10 * delta) Observe the difference:\nCredits The demo project seen here uses the following open-source/creative commons assets:\nCars: Kenney Car Kit by Kenney Track: Modular Racekart Track by Keith at Fertile Soil Productions Download This Project Download the project code here: https://github.com/godotrecipes/3d_car_sphere\nRelated recipes Input Actions ","description":"","tags":null,"title":"Arcade-style Car","uri":"/godot_recipes/4.x/3d/3d_sphere_car/index.html"},{"content":"Problem You want to use a RigidBody2D to create a semi-realistic spaceship, a la Asteroids.\nSolution Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc, and we’ll refer to it as we work through this example.\nFor this example, we’ll use the following node setup:\nRigidBody2D (Ship) Sprite2D CollisionShape2D Sprite orientation Don’t forget to orient your sprite correctly. An object that is not rotated should be pointing along the +X axis, i.e. to the right. If your sprite’s art is drawn facing in another direction, rotate the Sprite2D (not the parent body) to align it correctly.\nWe’ll use the following inputs in the Input Map:\nInput Key thrust w or ↑ rotate_right d or → rotate_left a or ← Add a script to the body, and let’s define some variables:\nextends RigidBody2D @export var engine_power = 800 @export var spin_power = 10000 var thrust = Vector2.ZERO var rotation_dir = 0 The first two variables are how we’ll control the ship’s “handling”. engine_power is going to affect acceleration and top speed. spin_power controls how fast the ship rotates.\nthrust and rotation_dir are going to be set by pressing the inputs. Let’s do that next:\nfunc get_input(): thrust = Vector2.ZERO if Input.is_action_pressed(\"thrust\"): thrust = transform.x * engine_power rotation_dir = Input.get_axis(\"rotate_left\", \"rotate_right\") If we’re pressing the \"thrust\" input, we’ll set the thrust vector to the ship’s forward direction, while rotation_dir will be +/-1 based on the rotate inputs.\nWe can start flying by applying those values in _physics_process():\nfunc _physics_process(_delta): get_input() constant_force = thrust constant_torque = rotation_dir * spin_power It works, but you’ll notice that it’s very hard to control. The rotation is too fast, and it accelerates to a high speed before going offscreen. This is where we want to break from “real” space physics. In space, there’s no friction, but our Asteroids-style ship will be a lot easier to control if it coasted to a stop when we’re not thrusting. We can control this with damping.\nIn the RigidBody2D properties, you’ll find Linear/Damp and Angular/Damp. Set these to 1 and 2 respectively, and they’ll slow the movement/rotation as well as causing them to stop.\nFeel free to experiment with these values and how they interact with the engine_power and spin_power\nScreen wrapping Wrapping around the screen is really teleportation: when the ship goes off the right side of the screen, you teleport it to the left side. However, if you just tried to change the position, you’d find that it instantly snapped back. This is because the physics engine is trying to control the position as well.\nThe solution to this is to use the _integrate_forces() callback of the rigid body. In this function, you can safely update the physics properties of the object without conflicting with what the physics engine is doing.\nLet’s get the screensize at the top of the script:\n@onready var screensize = get_viewport_rect().size Then add the new function:\nfunc _integrate_forces(state): var xform = state.transform xform.origin.x = wrapf(xform.origin.x, 0, screensize.x) xform.origin.y = wrapf(xform.origin.y, 0, screensize.y) state.transform = xform As you can see, the _integrate_forces() function includes a parameter called state. This object is the PhysicsDirectBodyState2D of our body. It contains all of the current physics properties such as the forces, velocity, position, etc.\nFrom the state, we grab the current transform, modify it to wrap around the screen using wrapf(), and then set it back to the current state.\nHere’s how it looks:\nWarping Let’s look at one more example of using _integrate_forces() to alter the body’s state without issues. Let’s add a “warp” mechanic - when the player presses the \"warp\" input, the ship will teleport to a random spot on the screen.\nFirst, we’ll add a new variable for this:\nvar teleport_pos = null Then, in get_input(), we’ll set a random position:\nif Input.is_action_just_pressed(\"warp\"): teleport_pos = Vector2(randf_range(0, screensize.x), randf_range(0, screensize.y)) Finally, in _integrate_forces(), if there’s a teleport_position set, we’ll use it and then clear it:\nif teleport_pos: physics_state.transform.origin = teleport_pos teleport_pos = null Download This Project Download the project’s example code here: https://github.com/godotrecipes/asteroids_physics\n","description":"","tags":null,"title":"Asteroids-style Physics (using RigidBody2D)","uri":"/godot_recipes/4.x/physics/asteroids_physics/index.html"},{"content":"Problem You want to move a 3D object to a clicked position.\nSolution We’ll start with a flat plane for our world. Our actor will move on this plane.\nThe actor for this demo is a triangular prism mesh:\nHere is the code for the movement. If given a target, the object will turn and move toward it.\nextends CharacterBody3D @export var speed = 5 @export var gravity = -5 var target = Vector3.ZERO func _physics_process(delta): velocity.y += gravity * delta if target: look_at(target, Vector3.UP) rotation.x = 0 velocity = -transform.basis.z * speed if transform.origin.distance_to(target) \u003c .5: target = Vector3.ZERO velocity = Vector3.ZERO move_and_slide() We’ve also added a MeshInstance3D called “Marker” to the scene. This will be moved to indicate the clicked position.\nMouse -\u003e 3D Now we need a way to map mouse position into our 3D world. If you imagine the screen as a window into the 3D world, the mouse is trapped on the glass. To select something in 3D, we must project a ray from our eye (the camera), through the mouse’s position and into the world.\nWhile this can be done manually using the Camera3D’s project_ray methods, we can take advantage of the fact that CollisionObject3D nodes do this automatically. All we need to do is connect our StaticBody3D ground’s input_event signal:\nfunc _on_StaticBody_input_event(camera, event, click_position, click_normal, shape_idx): if event is InputEventMouseButton and event.pressed: $Marker.transform.origin = click_position $Player.target = click_position We set the position of the marker and the Player’s target to the clicked position:\nWrapping up You can use this technique to detect clicks on any objects in your 3D world.\n","description":"","tags":null,"title":"Click to move","uri":"/godot_recipes/4.x/3d/click_to_move/index.html"},{"content":"Problem Your game needs a “level select” menu, where the user can choose from a grid of options.\nSolution As shown in the example above, we’ll make a scrolling grid of level “boxes” that the player can choose from. Let’s start with the individual level boxes:\n1: Level box Here’s the node setup:\nLevelBox: PanelContainer Label MarginContainer TextureRect The TextureRect is for displaying the lock icon, and the Label for displaying the level number. When one is showing, the other is hidden.\nYou can style these as you like, here’s an example:\nMake sure to set the LevelBox’s Custom Minimum Size in the Inspector. We’re using (110, 110) in the example, but it depends on what size layout you’re going for.\nNow add a script and connect the gui_input signal.\n@tool extends PanelContainer signal level_selected @export var locked = true: set = set_locked @export var level_num = 1: set = set_level @onready var lock = $MarginContainer/Lock @onready var label = $Label func set_locked(value): locked = value if not is_inside_tree(): await ready lock.visible = value label.visible = not value func set_level(value): level_num = value if not is_inside_tree(): await ready label.text = str(level_num) func _on_gui_input(event): if locked: return if event is InputEventMouseButton and event.pressed: level_selected.emit(level_num) print(\"Clicked level \", level_num) We’re using @tool here so that we can make changes to the properties in the inspector and see them right away, without running the scene. Go ahead and try clicking the Locked property and verify that you see the lock appear/disappear.\nSince we don’t have actual levels to load in this project, the print() statement can help test that the click is being detected.\n2: Grid Once you have the box scene completed, add a new scene with a GridContainer. Add any number of LevelBox instances under it, making sure to set the Columns value. Here’s one with 6 columns:\nIn this example Theme Overrides/Constants/H Separation and V Separation are set to 10.\nSave this scene as LevelGrid. In the menu, we’ll use multiple instances to display the desired number of levels.\n3: Menu screen Now we can put together the final menu.\nHere’s the basic layout we’re going for:\nWe’ll create it with these nodes:\nLevelMenu: MarginContainer VBoxContainer Title: Label HBoxContainer BackButton: TextureButton ClipControl: Control NextButton: TextureButton Adjust the node properties:\nLevelMenu Theme Overrides/Constants/Margins: 20 VBoxContainer Theme Overrides/Constants/Separation: 50 Title Style the font however you like BackButton / NextButton Ignore Texture Size: On Stretch Mode: Keep Centered Layout/Container Sizing/Horizontal/Expand: On ClipControl Layout/Clip Contents: On Layout/Custom Minimum Size: (710, 350) (size of the LevelGrid) The ClipControl node is where the grid goes. Enabling Clip Contents means that if the contents are larger than the control, they’ll be cropped. That will allow us to make a horizontally scrolling set of grids. Add an HBoxContainer called GridBox to ClipControl, and instance 3 (or more) LevelGrids inside it.\nMake sure to set Theme Overrides/Constants/Separation to 0.\nYour layout should look something like this (we’ve disabled Clip Contents in order to show what’s happening):\nWith Clip Content, the three grids are all there, but the ClipControl only shows one at a time.\nNow, to scroll the menu, we need to shift the GridBox by 710 pixels to the left/right.\n110 (width of each LevelBox) * 6 (grid columns) + 10 (grid spacing) * 5 == 710 Info You may be wondering why we’re not using a ScrollContainer here. You certainly can, but we don’t want continuous scrolling, and we don’t want to see a scrollbar.\nAdd a script to the LevelMenu and connect the pressed signals of the two buttons.\nextends MarginContainer var num_grids = 1 var current_grid = 1 var grid_width = 710 @onready var gridbox = $VBoxContainer/HBoxContainer/ClipControl/GridBox func _ready(): # Number all the level boxes and unlock them # Replace with your game's level/unlocks/etc. # You can also connect the \"level_selected\" signals here num_grids = gridbox.get_child_count() for grid in gridbox.get_children(): for box in grid.get_children(): var num = box.get_position_in_parent() + 1 + 18 * grid.get_position_in_parent() box.level_num = num box.locked = false func _on_BackButton_pressed(): if current_grid \u003e 1: current_grid -= 1 gridbox.rect_position.x += grid_width func _on_NextButton_pressed(): if current_grid \u003c num_grids: current_grid += 1 gridbox.rect_position.x -= grid_width When you run the scene, try clicking the “Next” and “Back” buttons and verify that it’s scrolling as expected. Clicking the individual level boxes should print to the console.\nDownload the example project to see the whole thing in action, including some tweens for the scrolling action (because tweens make everything better).\nDownload This Project Download the project code here: https://github.com/godotrecipes/ui_level_select\n","description":"","tags":null,"title":"Level Select Menu","uri":"/godot_recipes/4.x/ui/level_select/index.html"},{"content":"Problem You want a minimap or radar-style UI item showing the locations of objects outside of the player’s view.\nSolution Here’s an example of what we are going for: Project setup To illustrate this feature, we’ll start with a simplified top-down game using the Autotile recipe and a player based on the Top-down character recipe. See the linked recipes for details on how these parts work.\nNote The art in this project comes from kenney.nl, which you can download here: Minimap Assets.\nOur main scene setup looks like this:\nThe CanvasLayer node is there to hold our UI, including the minimap/radar we’re making in this recipe.\nUI Layout The first step will be to create the layout for the minimap. In order to work with whatever other UI elements exist in the game, it must resize smoothly, and integrate well with a container-based layout.\nAdd a MarginContainer first. Set its Theme Overrides/Constants all to 5. This control will hold the rest of the nodes and ensure it doesn’t bleed over into any other elements. Name it “Minimap” and save the scene.\nNext, add a NinePatchRect node. This node is similar to a TextureRect but handles resizing differently by not stretching the corners/edges. Drop the panel_woodDetail_blank.png image from the asset folder into the Texture property. This is a 128x128 image and if we scale the root MarginContainer, the image becomes stretched and ugly:\nUsing the NinePatchRects’s properties, we can ensure that the frame remains the same size when stretched. You can define these properties graphically in the “TextureRegion” panel, but it’s sometimes easier to enter the values directly. Set all four properties in the Patch Margin section to 64 and change the node’s name to “Frame”.\nNow observe what happens when we change the size:\nNext, we’d like to fill in the inner part of the frame with the grid pattern pattern_blueprintPaper.png:\nHowever, we need it to tile automatically no matter what size we make the frame. Also, since this grid area is where our minimap markers will appear, we don’t want the grid extending past the edges of the frame.\nAs a child of the MiniMap (and a sibling of the Frame), add another MarginContainer. Set all four margin properties in Theme Overrides/Constants to 20. As a child of this node, add a TextureRect and assign its Texture to the above image. Set its Stretch Mode to “Tile”. Name this node “Grid”.\nTry changing the size of your root node to see the effect:\nFor now, let’s leave the minimap’s size at (200, 200) - you can check the root node’s Size property in the Layout section to confirm.\nAt this point, your scene tree should look like the following:\nMap Markers As a child of Grid, add a Sprite2D node named “PlayerMarker” and give it the minimapIcon_arrowA.png texture. Note the sprite’s Transform/Position property: (0, 0), which places it exactly in the top-left corner of the Grid:\nIf our Grid size is currently (150, 150) (you can check this in its Size property), then its center will be (75, 75). Put the PlayerMarker’s Position there:\nDon’t worry, we’ll automate this later.\nAdd two more Sprite2D nodes: “MobMarker” and “AlertMarker”, using the minimapIcon_jewelRed.png and minimapIcon_exclamationYellow.png textures.\nThese will represent two different types of objects in the game world. Click the “Toggle Visibility” button next to each so that they won’t appear by default.\nScripting the map markers At this point, we have some decisions to make. How we approach populating the minimap with the objects in the world has a lot to do with how the game is set up. Since this is a very minimal demonstration project, we’re going keep the process simple. In a larger game, you may need to use a more robust approach.\nFor this demo, we have two game objects: a Mob, which wanders around the map randomly, and a Crate, which the player can pick up. Many of these are scattered around the main scene. Each will need to be represented by one of the map markers we made.\nAdd each item that you want to appear on the minimap to a group named “minimap_objects”. In each object’s script, assign it a minimap_icon property:\n# In the mob's script: var minimap_icon = \"mob\" # In the crate's script: var minimap_icon = \"alert\" Now we can begin adding a script to the Minimap. First, a player reference that can be assigned in the Inspector when the minimap is added to the main scene and a zoom property to calibrate the scale - how far the minimap can “see”. We also have some @onready variables to make it more convenient to access the nodes we need.\nextends MarginContainer class_name Minimap @export var player: Player @export var zoom = 1.5 @onready var grid = $MarginContainer/Grid @onready var player_marker = $MarginContainer/Grid/PlayerMarker @onready var mob_marker = $MarginContainer/Grid/MobMarker @onready var alert_marker = $MarginContainer/Grid/AlertMarker Next, we’ll use a dictionary to map the minimap_icon tags we gave our units to the corresponding marker:\n@onready var icons = { \"mob\": mob_marker, \"alert\": alert_marker } Then we need a variable to hold the calculated ratio of map size to world size. We’ll use another dictionary to assign active markers to each object. The key will be the object (ie the Mob or Crate instance) and the value the assigned marker.\nvar grid_scale var markers = {} In _ready() we’ll center the player’s marker at the center of the grid. and calculate the scale factor. (Note: you’ll need to connect the resized signal and do both of these things in the callback if you have a dynamically sized UI).\nfunc _ready(): await get_tree().process_frame player_marker.position = grid.size / 2 grid_scale = grid.size / (get_viewport_rect().size * zoom) Nodes in Containers Due to the way that Container nodes handle their children, at _ready() time you won’t get the correct value for the child’s size. For this reason, we need to wait until the next frame to get the Grid’s size.\nWe’ll also create markers for every game object (using the “minimap_objects” group) by duplicating the matching marker node and tying the marker to the object via the markers dictionary:\nvar map_objects = get_tree().get_nodes_in_group(\"minimap_objects\") for item in map_objects: var new_marker = icons[item.minimap_icon].duplicate() grid.add_child(new_marker) new_marker.show() markers[item] = new_marker Now that we have created the markers and linked each one to an object, we can update their positions in _process(). If no player is assigned, we’ll do nothing:\nfunc _process(delta): if !player: return If there is a player, we’ll first rotate the player marker to match the player’s heading. Since our PlayerMarker sprite points upwards rather than along the x axis, we must add 90 degrees:\nplayer_marker.rotation = player.rotation + PI/2 Next, we’ll find each object’s position relative to the player and use that to find the marker’s position (remembering to offset by grid.size / 2 because the control’s origin is in the top left corner).\nfor item in markers: var obj_pos = (item.position - player.position) * grid_scale + grid.size / 2 markers[item].position = obj_pos The problem with this is that markers can be placed outside the grid:\nTo fix this, after calculating obj_pos, but before setting the marker’s position, clamp it to the grid’s rectangle:\nobj_pos = obj_pos.clamp(Vector2.ZERO, grid.size) We can also decide what to do about markers that are “off-screen” - when they would be outside the grid’s rectangle. Choose one of the following options (do this also before using clamp()). The first option is to hide them:\nif grid.get_rect().has_point(obj_pos + grid.position): markers[item].show() else: markers[item].hide() The second is to change their appearance, in this case we’ll make them smaller to show they’re at a farther distance:\nif grid.get_rect().has_point(obj_pos + grid.position): markers[item].scale = Vector2(1, 1) else: markers[item].scale = Vector2(0.75, 0.75) Removing objects If a mob gets killed or a crate picked up, the game will crash because the marker reference is no longer valid. We need a way to ensure markers are removed when the object is. Here’s a quick way to do this in our rudimentary demo setup:\nAdd signal removed to any object that you’ve put in the “minimap_objects” group. Emit this signal when the object is destroyed (or collected), along with a reference to itself so the map can identify it:\nremoved.emit(self) In the _ready() of the main script, connect these signals to the minimap:\nfunc _ready(): for object in get_tree().get_nodes_in_group(\"minimap_objects\"): object.removed.connect(minimap._on_object_removed) Now add the receiving function to the minimap script to free the marker and remove the reference:\nfunc _on_object_removed(object): if object in markers: markers[object].queue_free() markers.erase(object) Adjusting zoom If you’ve stuck with it this far, we have one more feature to add: adjustable zoom level. With this, scrolling the mouse wheel when hovering over the map will zoom its scale in and out.\nFirst, add a setter to the zoom property:\n@export var zoom = 1.5: set = set_zoom func set_zoom(value): zoom = clamp(value, 0.5, 5) grid_scale = grid.size / (get_viewport_rect().size * zoom) On the MiniMap node, connect the _gui_input signal in the Inspector so we can process the scroll wheel events:\nfunc _on_gui_input(event): if event is InputEventMouseButton and event.pressed: if event.button_index == MOUSE_BUTTON_WHEEL_UP: zoom += 0.1 if event.button_index == MOUSE_BUTTON_WHEEL_DOWN: zoom -= 0.1 That’s it - observe the effect of scrolling in and out:\nWrapping up While this is a pretty big recipe, I’ve tried to make it flexible enough for you to incorporate into whatever project you’re working on.\nSome other things you might want to add:\nMore marker types for different game objects. Adding new units when they’re spawned (hint: use a signal just like we did for removing units). Clicking on a marker to get info about it. Use a picture of your map as the minimap background instead of the grid. Download This Project Download the project’s example code here: https://github.com/godotrecipes/minimap\nRelated recipes Top-down character ","description":"","tags":null,"title":"Minimap/radar","uri":"/godot_recipes/4.x/ui/minimap/index.html"},{"content":"Problem You want to smoothly rotate a 3D object to point in a new direction.\nSolution When you first encounter this problem, you may find yourself thinking in terms of Euler angles - the three values representing the angles to the x/y/z axes. While Godot will allow you to see the object’s Euler angles in the rotation property, it is not recommended to use them to work in 3D. There are a number of reasons why this the case, such as a problem called “gimbal lock”, where you lose one degree of freedom when one of your rotations reaches 90 degrees.\nInfo If you’re interested in the background behind Euler angles and the problems they introduce, like gimbal lock, here’s a video that explains it well.\nWe can avoid using 3D Euler angles in Godot by using the object’s transform property. This property represents the body’s position and orientation in space. It uses a mathematical construct called a matrix to do this, but you don’t really need to understand the underlying math in order to make use of it.\nlook_at() Let’s say you have a 3D object such as a missile or arrow and you want it to point at its target. You can do this using the Node3D method look_at():\nfunc _process(delta): var target_position = $Target.transform.origin $Arrow.look_at(target_position, Vector3.UP) This code would make our node ($Arrow) always point at the target’s position, no matter how it moves.\nNote that look_at() requires 2 parameters: the target position, and an “up vector”. Imagine an airplane pointing its nose towards a target - there are an infinite number of ways it could be oriented, because the plane could roll about its axis. This second parameter is how you define what you want the final orientation to be.\nSmooth rotation The above code works, but it snaps the rotation instantly to the target. This might be fine if you have a very slow-moving target, but looks unnatural. It would look better if we move smoothly, or “interpolated”, the rotation smoothly between the starting orientation and the ending.\nGodot has us covered here too. Rather than look_at(), we can use the Transform object’s looking_at() method, which doesn’t rotate the node, but returns the transform that would be looking at the target. Combine this with the interpolate_with() method, which returns an intermediate transform between a current one and a target one, and we can smoothly transition between the current orientation and our desired one.\nvar speed = 5 func _process(delta): var target_position = $Target.transform.origin var new_transform = $Arrow.transform.looking_at(target_position, Vector3.UP) $Arrow.transform = $Arrow.transform.interpolate_with(new_transform, speed * delta) Note that since interpolate_with() operates on the transform, it can be used to interpolate both rotation and position of an object.\nWrapping up That’s it! Use this handy method to rotate your 3D objects, and stop thinking about angles!\nRelated recipes ","description":"","tags":null,"title":"Smooth rotation","uri":"/godot_recipes/4.x/3d/rotate_interpolate/index.html"},{"content":"Problem You’d like to understand what is meant by dot product and cross product.\nSolution In this recipe we’ll introduce the concept of vector dot product and cross product and how they might be used.\nDot product Dot product is an operation on two vectors that returns a scalar. It is often visualized as the projection of vector A onto vector B:\nThis is the formula for calculating the dot product:\nWhere θ is the angle between the two vectors and ||A|| is the magnitude of A.\nThis is very useful when both vectors are normalized (i.e. their magnitudes are 1), then the formula simplifies to:\nThis shows that the dot product is directly related to the angle between the two vectors. Since cos(0) == 1 and cos(180) == -1, the result of the dot product can tell you how closely aligned two vectors are:\nSee below for how we can apply this fact in a practical example.\nCross product The cross product of two vectors is a third vector that is perpendicular to both of them. Its magnitude is related to their magnitudes and the angle between them.\nOnce again, if we’re using normalized vectors, the result is simplified: it will be directly related to the angle and its magnitude will range from -1 to 1.\nNote Since the cross product is perpendicular to both vectors, we would need to be working in 3D. In most 2D frameworks, including Godot, the 2D Vector2.cross() method returns a scalar value representing the result’s magnitude.\nPractical applications Consider this animation, showing how the results of Vector2.dot() and Vector2.cross() change in relation to the changing angle:\nThis demonstrates two common applications of these methods. If the red vector is our object’s forward direction, and the green shows the direction towards another object:\nDot product: Using the result, we can tell if the object is in front of (\u003e 0) or behind (\u003c 0) us. Cross product: Using the result, we can tell if the object is to the left (\u003e 0) or right (\u003c 0). ","description":"","tags":null,"title":"Vectors: Using Dot and Cross Product","uri":"/godot_recipes/4.x/math/dot_cross_product/index.html"},{"content":"Problem You need your character body to align with the surface or terrain.\nSolution This recipe builds on the basic CharacterBody3D controller described in the CharacterBody3D: Movement recipe, so read that one first.\nFirst, we’ve added some terrain to the scene. You can download the terrain from here: https://fertile-soil-productions.itch.io/modular-terrain-pack. This is low-poly terrain, but you can use or make any terrain you like for this technique.\nAs you can see, the movement still works with the terrain, but the tank seems to “float” above the slopes because it doesn’t change its orientation.\nInstead, we need to rotate the tank so that its treads are aligned with the ground, even as the slope changes. To do that, we need to know which way is up.\nSurface normals A surface normal is a unit vector (“normal vector” and “unit vector” mean the same thing) perpendicular to a surface. It shows which way the surface is facing. In the case of a mesh, every surface has a normal pointing outward.\nIn Godot, when a body collides, you can get the normal of the collision. This will be the colliding body’s normal at the point of contact.\nOnce we have the surface normal, we need to align the tank’s Y axis with it. Note that we can’t use Transform3D.looking_at(), because that will align the -Z (forward) axis with the normal.\nTo do this, we’ll use the following function:\nfunc align_with_y(xform, new_y): xform.basis.y = new_y xform.basis.x = -xform.basis.z.cross(new_y) xform.basis = xform.basis.orthonormalized() return xform Given a transform and a new Y direction vector, this function returns the transform rotated so that its basis.y is aligned with the given normal.\nNote If you’re unfamiliar with the cross product or other vector math, there’s a great vector math intro in the Godot Docs.\nWe can update the tank’s movement code to call this function when it collides with a surface:\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) move_and_slide() for i in get_slide_count(): var c = get_slide_collision(i) global_transform = align_with_y(global_transform, c.get_normal()) This doesn’t work quite as expected:\nThe problem is that the tank’s collision shape could be colliding with more than one of the terrain’s faces. Also, move_and_slide() can result in more than one collision in a single frame. This leads to the jittering. We need to choose one face and stick with it.\nAdd a RayCast3D child to the tank and set its Target Position to (0, -1, 0).\nSince this raycast is pointing down from the exact center of the tank, we’ll align with the individual surface that it collides with - the one directly beneath the tank.\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) move_and_slide(v) var n = $RayCast3D.get_collision_normal() global_transform = align_with_y(global_transform, n) This is much better, but because we are instantly snapping to the new alignment every time the tank crosses an edge, it still looks a little jarring:\nWe can solve this last problem by interpolating to the new transform rather than snapping immediately to it.\nfunc _physics_process(delta): velocity += gravity * delta get_input(delta) velocity = move_and_slide_with_snap(velocity, Vector3.DOWN*2, Vector3.UP, true) var n = $RayCast.get_collision_normal() var xform = align_with_y(global_transform, n) global_transform = global_transform.interpolate_with(xform, 12 * delta) The result is much smoother and more pleasing:\nYou can get even better results with two raycasts - one at the front and one at the back. Get the average normal from them:\nvar n = ($FrontRay.get_collision_normal() + $RearRay.get_collision_normal()) / 2.0 Feel free to experiment with the interpolation amount. We found 12 to work well in this situation, but you might find a higher or lower value works better for your setup.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/characterbody3d_examples\nRelated recipes CharacterBody3D: Movement Math: Interpolation Math: Transforms ","description":"","tags":null,"title":"CharacterBody3D: Align with Surface","uri":"/godot_recipes/4.x/3d/3d_align_surface/index.html"},{"content":" Games Demo games and tutorials.\nUpdating to Godot 4.0 We’re working on new content for Godot 4.0. In the meantime, we recommend new learners stick with Godot 3.x, which has a lot more resources and learning materials available.\nIn this section: Your First 2D Game ","description":"","tags":null,"title":"Game Tutorials","uri":"/godot_recipes/4.x/games/index.html"},{"content":"If you’ve been following along, you’ve learned a lot of the fundamentals of building games in Godot. We’re going to end the tutorial here, since we’ve completed the basic game.\nThe secret to learning effectively Here’s my big secret for getting the most out of tutorials like this and others you may find online. At the end, once you’ve finished building the project, immediately delete it and start over. This time, try and re-create it without looking at the tutorial. If you get stuck, look at just that part, then close it again.\nIt may sound repetitive, but that is how we learn: by doing things repeatedly. If you follow this tip, you’ll be amazed at how quickly you level up your gamedev skills.\nAdding to the game If you’re feeling comfortable with the techniques used to make this game, then you’re ready to branch out. Try adding a single new feature to this game.\nIf you’re stuck coming up with an idea, here are some suggestions:\nAdditional enemy types - there is art for other enemies in the art pack. How do they move and shoot?\nWaves - make more enemies spawn every time you clear the screen\nBoss enemies - what if a big enemy appears?\nBoosts - powerups could appear for the player to collect. There’s some art for those too.\nShield recharge - collect these to power up the shield Weapon upgrades - shoot more bullets, patterns, etc. Sound and music - give everything a lot more personality with some sound effects and background music.\nLearning more Ready for more? Here are some suggestions for your next learning adventure:\nGodot 101: Getting started in 3D - if you’re interested in making things in 3D, check out this introduction to Godot’s 3D features.\nCheck out the rest of the content on this website. There are lots of examples, tutorials, and code snippets to help you learn how to make your dream game.\nDownload This Project on GitHub Download the project code here:\nhttps://github.com/godotrecipes/8_direction_animation\n","description":"","tags":null,"title":"Wrapping up","uri":"/godot_recipes/4.x/games/first_2d/first_2d_end/index.html"},{"content":" Godot Recipes Godot’s nodes are your ingredients. What can you cook up?\nOn this site you’ll find a collection of solutions and examples to help you make whatever game system you need.\nGodot 4.0 Godot 4.0 has been released!\nGodot 4.0 is the latest stable release version of the engine.\nThere is a limited amount of learning material available, so if you’re looking to make a game or learn the engine, we recommend you stick with 3.x for now. Don’t worry - what you learn will still apply when you’re ready to move to the newer version!\nThis site has lots of learning material for Godot 3 - but not all of it has been updated for version 4 yet. You can click the ribbon in the top-right to toggle the Godot Recipes version, or click the button below:\nGodot 3 Recipes Are you ready to learn game development? Whether it’s as a hobby or working towards your dream career, there’s never been a better time to get started. Modern programming languages and tools have made it easier than ever to build high-quality games and distribute them to the world. One of these tools is the Godot game engine. For beginners, it offers a friendly way to learn gamedev techniques. For experienced developers, it’s a powerful, customizable and open tool for bringing your visions to life.\nOn this site you’ll find a gentle introduction to the Godot game engine, as well as a wide variety of gamedev tips and techniques. Feel free to browse the categories in the sidebar and see what catches your interest.\nIf you’re new to Godot, start here: What is Godot?.\nHow to use this site Beginners If you’re new to game development, start with the “Godot 101: Basics” section. There you’ll find an introduction to the Godot application, and a step-by-step guide to creating your first project. There is a lot of material to absorb here. Don’t feel discouraged if you feel you don’t get it at first. Repetition is the key to learning complex topics; the more you work with Godot’s features, the more familiar and easy they will start to feel.\nInfo It’s assumed that you have at least some general programming experience. If you’re completely new to programming, click here for tips on how to get started.\nExperienced Developers If you’re an experienced developer and/or you’re familiar with other modern game engine(s), feel free to explore the menu on the left. You’ll find a number of useful guides and tutorials to show you how to do things the “Godot Way”. Code samples and example projects are available for all articles.\n","description":"","tags":null,"title":"Home","uri":"/godot_recipes/4.x/index.html"},{"content":"","description":"","tags":null,"title":"Categories","uri":"/godot_recipes/4.x/categories/index.html"},{"content":"RayCast2D Raycasting is a common technique in game development. “Casting a ray” means extending a line from a point until it collides with something or reaches its limit.\nNode properties Add a RayCast2D node and take a look at the Inspector:\nHere are the main properties you’ll need to understand:\nEnabled Turn this off to disabled the raycast work.\nExclude Parent This property causes the ray to ignore collisions with the parent object. Enabled by default.\nTarget Position This is the destination point of the ray. Note: This is in local coordinates.\nAlso, take note of the Collide With section. By default the ray will only detect bodies, so you’ll need to go here if you want to detect areas as well or instead.\nUseful functions You can see the full list of the node’s functions in the API Documentation. Here are the some of the most useful ones:\nis_colliding() Boolean function, lets you know if the ray is colliding with something.\nget_collision_point() If the ray is colliding, this will return the position of the collision (in global coordinates).\nget_collider() If the ray is colliding, this function will return a reference to the colliding object.\nget_collision_normal() Another useful piece of information, this is the normal of the collided object at the point of collision.\nExample uses There are many uses for raycasts: visibility (can A see B, or is there an obstacle between?), proximity (am I close to a wall/ground/obstacle?), etc. Here are a couple of practical examples in use:\n1. Shooting Fast-moving projectiles often have the problem of “tunneling” through obstacles - they are moving too fast for the collision to be detected in a single frame. As an alternative, you can use a Raycast2D to represent the path (or a laser, etc.).\nHere’s a player sprite with a raycast attached to the end of the gun. The target_position is set to (250, 0).\nWhen the player shoots, you check to see if the ray is colliding with something:\nfunc _input(event): if event.is_action_pressed(\"shoot\"): if $RayCast2D.is_colliding(): print($RayCast2D.get_collider().name) 2. Edge detection Consider a platformer enemy that walks on platforms, but you don’t want it to fall off the edges. Add two downward-pointing raycasts to the mob like so:\nIn the mob’s script, check for when the ray stops colliding. That means you’ve found the edge and should turn around:\nfunc _physics_process(delta): velocity.y += gravity * delta if not $RayRight.is_colliding(): dir = -1 if not $RayLeft.is_colliding(): dir = 1 velocity.x = dir * speed $AnimatedSprite.flip_h = velocity.x \u003e 0 velocity = move_and_slide(velocity, Vector2.UP) Here’s what it looks like in action:\n","description":"","tags":null,"title":"RayCast2D","uri":"/godot_recipes/4.x/kyn/raycast2d/index.html"},{"content":"","description":"","tags":null,"title":"Tags","uri":"/godot_recipes/4.x/tags/index.html"}] \ No newline at end of file diff --git a/docs/4.x/input/custom_actions/index.html b/docs/4.x/input/custom_actions/index.html index c2389b6b..50934038 100644 --- a/docs/4.x/input/custom_actions/index.html +++ b/docs/4.x/input/custom_actions/index.html @@ -1,5 +1,5 @@ -Adding Input Actions in code :: Godot 4 Recipes - +Adding Input Actions in code :: Godot 4 Recipes +

    Adding Input Actions in code

    Problem

    You need to add actions to the InputMap at runtime.

    Solution

    Typically, you’ll add actions to the InputMap via Project Settings, as shown in Recipe: Input Actions. However, you may find yourself needing to add one or more actions directly in a script. The InputMap singleton has methods to help you do this.

    Here’s an example that would add a new action called “attack” using the space key:

    func _ready():
         InputMap.add_action("attack")
    @@ -28,17 +28,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/index.html b/docs/4.x/input/index.html index d02e216a..0672eb26 100644 --- a/docs/4.x/input/index.html +++ b/docs/4.x/input/index.html @@ -1,19 +1,19 @@ -Input :: Godot 4 Recipes - +Input :: Godot 4 Recipes +
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/input_actions/index.html b/docs/4.x/input/input_actions/index.html index 1c25a8c7..6ca55062 100644 --- a/docs/4.x/input/input_actions/index.html +++ b/docs/4.x/input/input_actions/index.html @@ -1,5 +1,5 @@ -Input Actions :: Godot 4 Recipes - +Input Actions :: Godot 4 Recipes +

    Input Actions

    Problem

    You want to understand Godot’s “input action” system.

    Solution

    Let’s say you’re making a top-down character and you write code using InputActionKey that uses the arrow keys for movement. You’ll quickly find that many players prefer to use “WASD” style controls. You can go back into your code and add the additional key checks, but this would result in duplicated/redundant code.

    Input actions can help to make your code more configurable. Rather than hard-coding specific keys, you’ll be able to modify and customize them without changing the code.

    Creating inputs

    You define input actions in the “Project Settings” under the “Input Map” tab. Here, you can create new actions and/or assign inputs to them.

    You’ll see when you click on the tab there are already some default actions configured. They are all named “ui_*” to indicate that they are the default interface actions. “Tab” for next UI element, for example.

    Generally speaking, you should create your own actions for your game, rather than use the existing ones.

    For this example, let’s say you want to allow the player to control the game with the keyboard or the mouse. They need to be able to shoot by pressing either the left mouse button or the spacebar.

    Create the new action “shoot” by typing the name in the “Action” field at the top and clicking “Add” (or pressing enter). Scroll to the bottom and you’ll see the new action has been added to the list.

    Now you can assign inputs to this action by clicking the “+” sign to the right. Inputs can be keys, mouse buttons, or joy/gamepad inputs. Choose “Key” and you can press the key on the keyboard you want to assign - let’s press the spacebar - and click “OK”.

    Click “+” to add another input, and this time choose “Mouse Button”. The default of “Device 0” and “Left Button” is fine, but you can select others if you like.

    Using input actions

    You can check for the action either by polling the Input singleton every frame:

    func _process(delta):
         if Input.is_action_pressed("shoot"):
    @@ -10,17 +10,17 @@
     

    There are several functions you can use for checking input state:

    • is_action_pressed(): This function returns true if the action is currently in the pressed state.

    • is_action_released(): This function returns true if the action is not In the pressed state.

    • is_action_just_pressed() / is_action_just_released(): These methods work like the above, but only return true on the single frame after the event occurs. This is useful for non-recurring actions like shooting or jumping where the user needs to let go and then press the key again to repeat the action.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/mouse_capture/index.html b/docs/4.x/input/mouse_capture/index.html index 5db94371..d1a3d3c4 100644 --- a/docs/4.x/input/mouse_capture/index.html +++ b/docs/4.x/input/mouse_capture/index.html @@ -1,5 +1,5 @@ -Capturing the Mouse :: Godot 4 Recipes - +Capturing the Mouse :: Godot 4 Recipes +

    Capturing the Mouse

    Problem

    You want to hide the mouse cursor and keep the mouse from leaving the game window. This is common in many 3D games (and some 2D ones).

    Solution

    You can set the mouse state using Input.mouse_mode. There are four possible mouse modes:

    • MOUSE_MODE_VISIBLE: The mouse is visible and can move freely into and out of the window. This is the default state.

    • MOUSE_MODE_HIDDEN: The mouse cursor is invisible, but the mouse can still move outside the window.

    • MOUSE_MODE_CAPTURED: The mouse cursor is hidden and the mouse is unable to leave the game window.

    • MOUSE_MODE_CONFINED: The mouse is visible, but cannot leave the game window.

    “Captured” is the most commonly used option. You can set the mouse mode at runtime using:

    func _ready():
         Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
    @@ -14,17 +14,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/mouse_input/index.html b/docs/4.x/input/mouse_input/index.html index 29d9e65f..220a3604 100644 --- a/docs/4.x/input/mouse_input/index.html +++ b/docs/4.x/input/mouse_input/index.html @@ -1,5 +1,5 @@ -Mouse Input :: Godot 4 Recipes - +Mouse Input :: Godot 4 Recipes +

    Mouse Input

    Problem

    You want to detect mouse input.

    Solution

    InputEventMouse is the base class for mouse events. It contains position and global_position properties. Inheriting from it are two classes: InputEventMouseButton and InputEventMouseMotion.

    Note

    You can assign mouse button events in the InputMap, so you can use them with is_action_pressed().

    InputEventMouseButton

    @GlobalScope.ButtonList contains a list of BUTTON_* constants for each possible button, which will be reported in the event’s button_index property. Note that the scrollwheel also counts as a button - two buttons, to be precise, with both BUTTON_WHEEL_UP and BUTTON_WHEEL_DOWN being separate events.

    Tip

    Unlike regular buttons, mouse wheel clicks only produce pressed events. There is no concept of a mouse wheel click being “released”.

    func _unhandled_input(event):
         if event is InputEventMouseButton:
    @@ -19,17 +19,17 @@
     
    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/multi_unit_select/index.html b/docs/4.x/input/multi_unit_select/index.html index fdd20d99..29ce367e 100644 --- a/docs/4.x/input/multi_unit_select/index.html +++ b/docs/4.x/input/multi_unit_select/index.html @@ -1,8 +1,8 @@ -Mouse: Drag-select multiple units :: Godot 4 Recipes - +Mouse: Drag-select multiple units :: Godot 4 Recipes +

    Mouse: Drag-select multiple units

    Problem

    You want to click-and-drag to select multiple units, RTS style.

    Solution

    Realtime strategy (RTS) games often require giving orders to many units at once. A typical style of selecting multiple units is to click-and-drag a box around them. Once the units are selected, clicking on the map commands them to move.

    Here’s an example of what we’re going for:

    alt -alt

    Unit setup

    To test this out, we’ll need some basic RTS-style units. They are set up to move towards a target and to avoid running into each other. We won’t go into too much detail on them in this tutorial. The unit script is commented if you’d like to use it as a base for creating your own RTS units. See below for a link to download the project.

    World setup

    Processing the unit selection will happen in the world. We’ll start with a Node2D called “World” and add a few Unit instances in it. Attach a script to the World node and add the following variables:

    extends Node2D
    +

    Mouse: Drag-select multiple units

    Problem

    You want to click-and-drag to select multiple units, RTS style.

    Solution

    Realtime strategy (RTS) games often require giving orders to many units at once. A typical style of selecting multiple units is to click-and-drag a box around them. Once the units are selected, clicking on the map commands them to move.

    Here’s an example of what we’re going for:

    alt +alt

    Unit setup

    To test this out, we’ll need some basic RTS-style units. They are set up to move towards a target and to avoid running into each other. We won’t go into too much detail on them in this tutorial. The unit script is commented if you’d like to use it as a base for creating your own RTS units. See below for a link to download the project.

    World setup

    Processing the unit selection will happen in the world. We’ll start with a Node2D called “World” and add a few Unit instances in it. Attach a script to the World node and add the following variables:

    extends Node2D
     
     var dragging = false  # Are we currently dragging?
     var selected = []  # Array of selected units.
    @@ -33,16 +33,16 @@
         select_rect.extents = abs(drag_end - drag_start) / 2
     

    We start by recording the location when we released the button, and use that to set the RectangleShape2D’s extents (remember: extents are measured from the rectangle’s center, so they’re half the full width/height).

        var space = get_world_2d().direct_space_state
         var query = PhysicsShapeQueryParameters2D.new()
    -    q.shape = select_rect
    -    q.collision_mask = 2  # Units are on collision layer 2
    -    q.transform = Transform2D(0, (drag_end + drag_start) / 2)
    +    query.shape = select_rect
    +    query.collision_mask = 2  # Units are on collision layer 2
    +    query.transform = Transform2D(0, (drag_end + drag_start) / 2)
         selected = space.intersect_shape(query)
     

    Now we get a reference to the physics state and set up our shape query using PhysicsShapeQueryParameters2D, assigning it our shape, and using the center of the dragged area as the origin for the query’s transform. Our result after calling intersect_shape() is an array of dictionaries, which looks like this:

    [{ "rid": RID(4093103833089), "collider_id": 32145147326, "collider": Unit2:<CharacterBody2D#32145147326>, "shape": 0 },
     { "rid": RID(4123168604162), "collider_id": 32229033411, "collider": Unit3:<CharacterBody2D#32229033411>, "shape": 0 }]
     

    Each of those collider items is a reference to a unit, so we can use this to notify them that they’ve been selected, activating the outline shader:

        for item in selected:
             item.collider.selected = true
    -

    alt -alt

    Commanding the units

    Finally, we can command the selected units to move by clicking somewhere on the screen:

    func _unhandled_input(event):
    +

    alt +alt

    Commanding the units

    Finally, we can command the selected units to move by clicking somewhere on the screen:

    func _unhandled_input(event):
         if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
             if event.pressed:
                 # If the mouse was clicked and nothing is selected, start dragging
    @@ -58,17 +58,17 @@
     

    The else clause here triggers if we click the mouse when selected is greater than 0. Each item’s target is set, and we make sure to deselect the units so we can start again.

    Wrapping up

    This technique can be expanded to a wide range of RTS or other game styles. Download the full project below and use it as a base for your own game.

    Download This Project

    Download the project code here: https://github.com/godotrecipes/multi_unit_select

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/input/processing_inputs/index.html b/docs/4.x/input/processing_inputs/index.html new file mode 100644 index 00000000..28d36b89 --- /dev/null +++ b/docs/4.x/input/processing_inputs/index.html @@ -0,0 +1,19 @@ +Godot 4 Recipes + +

    Examples w/the flowchart

    If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more.

    If the control wants to “consume” the event, it will call Control.accept_event() and the event will not spread any more

    + + \ No newline at end of file diff --git a/docs/4.x/kyn/index.html b/docs/4.x/kyn/index.html index 7ddcfa0c..254b0fd0 100644 --- a/docs/4.x/kyn/index.html +++ b/docs/4.x/kyn/index.html @@ -1,19 +1,19 @@ -Know Your Nodes :: Godot 4 Recipes - +Know Your Nodes :: Godot 4 Recipes +

     Know Your Nodes

    In the “Know Your Nodes” series, we go in-depth with a single one of Godot’s nodes. Learn what makes it tick and see some examples of how it’s used.

    In this section:

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/kyn/raycast2d/index.html b/docs/4.x/kyn/raycast2d/index.html index f6bdf6a1..1432f956 100644 --- a/docs/4.x/kyn/raycast2d/index.html +++ b/docs/4.x/kyn/raycast2d/index.html @@ -1,14 +1,14 @@ -RayCast2D :: Godot 4 Recipes - +RayCast2D :: Godot 4 Recipes +

    RayCast2D

    RayCast2D

    Raycasting is a common technique in game development. “Casting a ray” means extending a line from a point until it collides with something or reaches its limit.

    Node properties

    Add a RayCast2D node and take a look at the Inspector:

    alt -alt

    Here are the main properties you’ll need to understand:

    • Enabled

    Turn this off to disabled the raycast work.

    • Exclude Parent

    This property causes the ray to ignore collisions with the parent object. Enabled by default.

    • Target Position

    This is the destination point of the ray. Note: This is in local coordinates.

    Also, take note of the Collide With section. By default the ray will only detect bodies, so you’ll need to go here if you want to detect areas as well or instead.

    Useful functions

    You can see the full list of the node’s functions in the API Documentation. Here are the some of the most useful ones:

    • is_colliding()

    Boolean function, lets you know if the ray is colliding with something.

    • get_collision_point()

    If the ray is colliding, this will return the position of the collision (in global coordinates).

    • get_collider()

    If the ray is colliding, this function will return a reference to the colliding object.

    • get_collision_normal()

    Another useful piece of information, this is the normal of the collided object at the point of collision.

    Example uses

    There are many uses for raycasts: visibility (can A see B, or is there an obstacle between?), proximity (am I close to a wall/ground/obstacle?), etc. Here are a couple of practical examples in use:

    1. Shooting

    Fast-moving projectiles often have the problem of “tunneling” through obstacles - they are moving too fast for the collision to be detected in a single frame. As an alternative, you can use a Raycast2D to represent the path (or a laser, etc.).

    Here’s a player sprite with a raycast attached to the end of the gun. The target_position is set to (250, 0).

    alt -alt

    When the player shoots, you check to see if the ray is colliding with something:

    func _input(event):
    +

    RayCast2D

    RayCast2D

    Raycasting is a common technique in game development. “Casting a ray” means extending a line from a point until it collides with something or reaches its limit.

    Node properties

    Add a RayCast2D node and take a look at the Inspector:

    alt +alt

    Here are the main properties you’ll need to understand:

    • Enabled

    Turn this off to disabled the raycast work.

    • Exclude Parent

    This property causes the ray to ignore collisions with the parent object. Enabled by default.

    • Target Position

    This is the destination point of the ray. Note: This is in local coordinates.

    Also, take note of the Collide With section. By default the ray will only detect bodies, so you’ll need to go here if you want to detect areas as well or instead.

    Useful functions

    You can see the full list of the node’s functions in the API Documentation. Here are the some of the most useful ones:

    • is_colliding()

    Boolean function, lets you know if the ray is colliding with something.

    • get_collision_point()

    If the ray is colliding, this will return the position of the collision (in global coordinates).

    • get_collider()

    If the ray is colliding, this function will return a reference to the colliding object.

    • get_collision_normal()

    Another useful piece of information, this is the normal of the collided object at the point of collision.

    Example uses

    There are many uses for raycasts: visibility (can A see B, or is there an obstacle between?), proximity (am I close to a wall/ground/obstacle?), etc. Here are a couple of practical examples in use:

    1. Shooting

    Fast-moving projectiles often have the problem of “tunneling” through obstacles - they are moving too fast for the collision to be detected in a single frame. As an alternative, you can use a Raycast2D to represent the path (or a laser, etc.).

    Here’s a player sprite with a raycast attached to the end of the gun. The target_position is set to (250, 0).

    alt +alt

    When the player shoots, you check to see if the ray is colliding with something:

    func _input(event):
         if event.is_action_pressed("shoot"):
             if $RayCast2D.is_colliding():
                 print($RayCast2D.get_collider().name)
    -

    2. Edge detection

    Consider a platformer enemy that walks on platforms, but you don’t want it to fall off the edges. Add two downward-pointing raycasts to the mob like so:

    alt -alt

    In the mob’s script, check for when the ray stops colliding. That means you’ve found the edge and should turn around:

    func _physics_process(delta):
    +

    2. Edge detection

    Consider a platformer enemy that walks on platforms, but you don’t want it to fall off the edges. Add two downward-pointing raycasts to the mob like so:

    alt +alt

    In the mob’s script, check for when the ray stops colliding. That means you’ve found the edge and should turn around:

    func _physics_process(delta):
         velocity.y += gravity * delta
         if not $RayRight.is_colliding():
             dir = -1
    @@ -17,21 +17,21 @@
         velocity.x = dir * speed
         $AnimatedSprite.flip_h = velocity.x > 0
         velocity = move_and_slide(velocity, Vector2.UP)
    -

    Here’s what it looks like in action:

    alt -alt

    + + \ No newline at end of file diff --git a/docs/4.x/math/dot_cross_product/index.html b/docs/4.x/math/dot_cross_product/index.html index 4982f875..bac0b3e2 100644 --- a/docs/4.x/math/dot_cross_product/index.html +++ b/docs/4.x/math/dot_cross_product/index.html @@ -1,26 +1,26 @@ -Vectors: Using Dot and Cross Product :: Godot 4 Recipes - +Vectors: Using Dot and Cross Product :: Godot 4 Recipes +

    Vectors: Using Dot and Cross Product

    Problem

    You’d like to understand what is meant by dot product and cross product.

    Solution

    In this recipe we’ll introduce the concept of vector dot product and cross product and how they might be used.

    Dot product

    Dot product is an operation on two vectors that returns a scalar. It is often visualized as the projection of vector A onto vector B:

    alt -alt

    This is the formula for calculating the dot product:

    alt -alt

    Where θ is the angle between the two vectors and ||A|| is the magnitude of A.

    This is very useful when both vectors are normalized (i.e. their magnitudes are 1), then the formula simplifies to:

    alt -alt

    This shows that the dot product is directly related to the angle between the two vectors. Since cos(0) == 1 and cos(180) == -1, the result of the dot product can tell you how closely aligned two vectors are:

    alt -alt

    See below for how we can apply this fact in a practical example.

    Cross product

    The cross product of two vectors is a third vector that is perpendicular to both of them. Its magnitude is related to their magnitudes and the angle between them.

    alt -alt

    Once again, if we’re using normalized vectors, the result is simplified: it will be directly related to the angle and its magnitude will range from -1 to 1.

    Note

    Since the cross product is perpendicular to both vectors, we would need to be working in 3D. In most 2D frameworks, including Godot, the 2D Vector2.cross() method returns a scalar value representing the result’s magnitude.

    Practical applications

    Consider this animation, showing how the results of Vector2.dot() and Vector2.cross() change in relation to the changing angle:

    alt -alt

    This demonstrates two common applications of these methods. If the red vector is our object’s forward direction, and the green shows the direction towards another object:

    • Dot product: Using the result, we can tell if the object is in front of (> 0) or behind (< 0) us.
    • Cross product: Using the result, we can tell if the object is to the left (> 0) or right (< 0).
    + + \ No newline at end of file diff --git a/docs/4.x/math/index.html b/docs/4.x/math/index.html index b2d59cd2..1523a57d 100644 --- a/docs/4.x/math/index.html +++ b/docs/4.x/math/index.html @@ -1,22 +1,22 @@ -Gamedev Math :: Godot 4 Recipes - +Gamedev Math :: Godot 4 Recipes +

     Gamedev Math

    Math is a big part of game development. Some of it you may remember from school, or it may be something you’ve never encountered before. Here you’ll find guides to help you get up to speed and examples of how these concepts are applied to making games.

    In this section:

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/math/interpolation/index.html b/docs/4.x/math/interpolation/index.html index dd26ceab..e1e11291 100644 --- a/docs/4.x/math/interpolation/index.html +++ b/docs/4.x/math/interpolation/index.html @@ -1,5 +1,5 @@ -Interpolation :: Godot 4 Recipes - +Interpolation :: Godot 4 Recipes +

    Interpolation

    Linear Interpolation, or its commonly-used abbreviation lerp, is a term that comes up often in game development. If you’ve never come across it before it can seem mysterious and highly-technical, but as you’ll see in this tutorial, it’s actually a straightforward concept with a wide variety of applications in game programming.

    Numeric Interpolation

    The core formula for linear interpolation is this:

    func lerp(a, b, t):
         return (1 - t) * a + t * b
    @@ -34,17 +34,17 @@
     

    For more advanced applications of interpolation, see Tween.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/math/transforms/index.html b/docs/4.x/math/transforms/index.html index 7c5ab6e7..4c60c32c 100644 --- a/docs/4.x/math/transforms/index.html +++ b/docs/4.x/math/transforms/index.html @@ -1,40 +1,40 @@ -Transforms :: Godot 4 Recipes - +Transforms :: Godot 4 Recipes +

    Transforms

    Before reading this, make sure you have an understanding of vectors and how they’re used in game development. If you don’t, I recommend you read this introduction I wrote for the Godot documentation: -Vector Math.

    2D Transforms

    In 2D space, we use the familiar X-Y coordinate plane. Remember that in Godot, as in most computer graphics applications, the Y axis points downward:

    alt -alt

    To begin, let’s consider this spaceship floating in space:

    alt -alt

    The ship is pointing in the same direction as the X axis. If we wanted it to move forward, we could add to its X coordinate and it would move to the right:

    position += Vector2(10, 0)
    -

    But what happens when the ship rotates?

    alt -alt

    How do we move the ship forward now? If you remember Trigonometry from school, you might be starting to think about angles, sine and cosine and doing something like position += Vector2(10 * cos(angle), 10 * sin(angle)). While this would work, there’s a much more convenient way: the Transform.

    Let’s look at the rotated ship again, but this time, let’s also imagine that the ship has its own X and Y axes that it carries with it, independent of the global axes:

    alt -alt

    These “local” axes are contained in the object’s transform.

    Knowing this, we can move the ship forward by moving it along its own X axis and we won’t have to worry about angles and trig functions. To do this in Godot, we can use the transform property, which is available to all Node2D derived nodes.

        position += transform.x * 10
    -

    This code says “Add the transform’s x vector multiplied by 10.” Let’s break down what that means. The transform contains x and y properties that represent those local axes. They are unit vectors, which means their length is 1. Another term for unit vector is direction vector. They tell us the direction the ship’s x axis is pointing. We then multiply by 10 to scale it to a longer distance.

    Tip

    The transform property of a node is relative to its parent node. If you need to get the global value, it’s available in global_transform.

    In addition to the local axes, the transform also contains a component called the origin. The origin represents the translation, or change in position.

    In this picture, the blue vector is the transform.origin. It is equal to the object’s position vector.

    alt -alt

    Converting Between Local and Global Space

    You can convert coordinates from local to global by applying the transform. For convenience, Node2D and Spatial include helper functions for this: to_local() and to_global():

        var global_position = to_global(local_position)
    +Vector Math.

    2D Transforms

    In 2D space, we use the familiar X-Y coordinate plane. Remember that in Godot, as in most computer graphics applications, the Y axis points downward:

    alt +alt

    To begin, let’s consider this spaceship floating in space:

    alt +alt

    The ship is pointing in the same direction as the X axis. If we wanted it to move forward, we could add to its X coordinate and it would move to the right:

    position += Vector2(10, 0)
    +

    But what happens when the ship rotates?

    alt +alt

    How do we move the ship forward now? If you remember Trigonometry from school, you might be starting to think about angles, sine and cosine and doing something like position += Vector2(10 * cos(angle), 10 * sin(angle)). While this would work, there’s a much more convenient way: the Transform.

    Let’s look at the rotated ship again, but this time, let’s also imagine that the ship has its own X and Y axes that it carries with it, independent of the global axes:

    alt +alt

    These “local” axes are contained in the object’s transform.

    Knowing this, we can move the ship forward by moving it along its own X axis and we won’t have to worry about angles and trig functions. To do this in Godot, we can use the transform property, which is available to all Node2D derived nodes.

        position += transform.x * 10
    +

    This code says “Add the transform’s x vector multiplied by 10.” Let’s break down what that means. The transform contains x and y properties that represent those local axes. They are unit vectors, which means their length is 1. Another term for unit vector is direction vector. They tell us the direction the ship’s x axis is pointing. We then multiply by 10 to scale it to a longer distance.

    Tip

    The transform property of a node is relative to its parent node. If you need to get the global value, it’s available in global_transform.

    In addition to the local axes, the transform also contains a component called the origin. The origin represents the translation, or change in position.

    In this picture, the blue vector is the transform.origin. It is equal to the object’s position vector.

    alt +alt

    Converting Between Local and Global Space

    You can convert coordinates from local to global by applying the transform. For convenience, Node2D and Spatial include helper functions for this: to_local() and to_global():

        var global_position = to_global(local_position)
     

    Let’s use the example of an object in the 2D plane and convert mouse clicks (global space) into coordinates relative to the object:

    extends Sprite
     
     func _unhandled_input(event):
         if event is InputEventMouseButton and event.pressed:
             if event.button_index == BUTTON_LEFT:
                 printt(event.position, to_local(event.position))
    -

    See the Transform2D docs for a list of the available properties and methods.

    3D Transforms

    In 3D space, the concept of transforms applies in the same way as in 2D. In fact, it becomes even more necessary, as using angles in 3D can lead to a variety of problems, as we’ll see in a bit.

    3D nodes inherit from the base node Node3D, which contains the transform information. The 3D transform requires more information than the 2D version. Position is still held in the origin property, but rotation is in a property called basis, which contains three unit vectors representing the body’s local X, Y, and Z axes.

    When you select a 3D node in the editor, the gizmo that appears allows you to manipulate the transform.

    alt -alt

    Local Space Mode

    In the editor, you can see and manipulate the body’s local orientation by clicking the “Local Space Mode” button. -alt -alt +

    See the Transform2D docs for a list of the available properties and methods.

    3D Transforms

    In 3D space, the concept of transforms applies in the same way as in 2D. In fact, it becomes even more necessary, as using angles in 3D can lead to a variety of problems, as we’ll see in a bit.

    3D nodes inherit from the base node Node3D, which contains the transform information. The 3D transform requires more information than the 2D version. Position is still held in the origin property, but rotation is in a property called basis, which contains three unit vectors representing the body’s local X, Y, and Z axes.

    When you select a 3D node in the editor, the gizmo that appears allows you to manipulate the transform.

    alt +alt

    Local Space Mode

    In the editor, you can see and manipulate the body’s local orientation by clicking the “Local Space Mode” button. +alt +alt When in this mode, the 3 colored axis lines represent the body’s local basis axes.

    As in 2D, we can use the local axes to move an object forward. In Godot’s 3D orientation (Y-up), this means that by default the body’s -Z axis is the forward direction. To move forward:

        position += -transform.basis.z * speed * delta
     
    Tip

    Godot has default vector values defined, for example: Vector3.FORWARD == Vector3(0, 0, -1). See Vector2 and Vector3 for details.

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/physics/asteroids_physics/index.html b/docs/4.x/physics/asteroids_physics/index.html index 58544846..d64c7ee7 100644 --- a/docs/4.x/physics/asteroids_physics/index.html +++ b/docs/4.x/physics/asteroids_physics/index.html @@ -1,5 +1,5 @@ -Asteroids-style Physics (using RigidBody2D) :: Godot 4 Recipes - +Asteroids-style Physics (using RigidBody2D) :: Godot 4 Recipes +

    Asteroids-style Physics (using RigidBody2D)

    Problem

    You want to use a RigidBody2D to create a semi-realistic spaceship, a la Asteroids.

    Solution

    Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc, and we’ll refer to it as we work through this example.

    For this example, we’ll use the following node setup:

     RigidBody2D (Ship)
           Sprite2D
    @@ -26,28 +26,28 @@
         xform.origin.x = wrapf(xform.origin.x, 0, screensize.x)
         xform.origin.y = wrapf(xform.origin.y, 0, screensize.y)
         state.transform = xform
    -

    As you can see, the _integrate_forces() function includes a parameter called state. This object is the PhysicsDirectBodyState2D of our body. It contains all of the current physics properties such as the forces, velocity, position, etc.

    From the state, we grab the current transform, modify it to wrap around the screen using wrapf(), and then set it back to the current state.

    Here’s how it looks:

    alt -alt

    Warping

    Let’s look at one more example of using _integrate_forces() to alter the body’s state without issues. Let’s add a “warp” mechanic - when the player presses the "warp" input, the ship will teleport to a random spot on the screen.

    First, we’ll add a new variable for this:

    var teleport_pos = null
    +

    As you can see, the _integrate_forces() function includes a parameter called state. This object is the PhysicsDirectBodyState2D of our body. It contains all of the current physics properties such as the forces, velocity, position, etc.

    From the state, we grab the current transform, modify it to wrap around the screen using wrapf(), and then set it back to the current state.

    Here’s how it looks:

    alt +alt

    Warping

    Let’s look at one more example of using _integrate_forces() to alter the body’s state without issues. Let’s add a “warp” mechanic - when the player presses the "warp" input, the ship will teleport to a random spot on the screen.

    First, we’ll add a new variable for this:

    var teleport_pos = null
     

    Then, in get_input(), we’ll set a random position:

        if Input.is_action_just_pressed("warp"):
             teleport_pos = Vector2(randf_range(0, screensize.x), randf_range(0, screensize.y))
     

    Finally, in _integrate_forces(), if there’s a teleport_position set, we’ll use it and then clear it:

        if teleport_pos:
             physics_state.transform.origin = teleport_pos
             teleport_pos = null
    -

    alt -alt

    Download This Project

    Download the project’s example code here: https://github.com/godotrecipes/asteroids_physics

    + + \ No newline at end of file diff --git a/docs/4.x/physics/character_vs_rigid/index.html b/docs/4.x/physics/character_vs_rigid/index.html index b95394c5..ac97438a 100644 --- a/docs/4.x/physics/character_vs_rigid/index.html +++ b/docs/4.x/physics/character_vs_rigid/index.html @@ -1,12 +1,12 @@ -Character to Rigid Body Interaction :: Godot 4 Recipes - +Character to Rigid Body Interaction :: Godot 4 Recipes +

    Character to Rigid Body Interaction

    Problem

    You want your character body to interact with rigid bodies.

    Solution

    Note

    This recipe applies equally well in both 2D and 3D nodes.

    By default, a CharacterBody2D moved with move_and_slide() or move_and_collide() will not push any RigidBody2D it collides with. The rigid body doesn’t react at all, and behaves just like a StaticBody2D.

    alt -alt

    In some cases, this might be all you need. However, if you want to be able to push the bodies, you’ll need to make some changes.

    For this example, we’ll use the 2D character described in the Platform character recipe. This example uses the most common movement method for character bodies: move_and_slide(). If you’re using move_and_collide(), you’ll need to adjust the examples below accordingly.

    You have two options when deciding how to interact with rigid bodies:

    1. You can just push them, ignoring physics. If you’re familiar with Godot 3.x, this is equivalent to the “infinite inertia” option.
    2. You can give them a push based on the character’s imagined “mass” and velocity. This will give you a “realistic” result - pushing heavy bodies a little, and lighter bodies a lot.

    We’ll try out both options below.

    Infinite Inertia

    This option has its pros and cons. The biggest pro is, you don’t need any extra code. You just need to correctly set the collision layers/masks of the objects. For this example, we’ve defined three physics layers:

    alt -alt

    For the rigid body, we’ve placed it on the “items” layer (layer 3), and left the mask at the default (masking all layers):

    alt -alt

    Then, we’ve placed the player on the “player” layer (layer 2), and configured the mask to ignore the “items”:

    alt -alt

    Running the game, we now see we can push the boxes around. Note that the mass of the box doesn’t matter - they’ll all be pushed the same.

    alt -alt

    Here, you can also see the downside of this option. Because the physics of the boxes is being ignored, they can clip through walls and you can’t jump on top of them.

    For some games, this will be fine. If you want to prevent the clipping, you’ll need to go with option 2.

    Applying impulses

    To give the colliding body a “push” we’ll need to apply an impulse. An impulse is an instantaneous “kick” - think of a bat hitting a ball. This is as opposed to a force, which is a continuous “push” on an object.

    # This represents the player's inertia.
    +

    Character to Rigid Body Interaction

    Problem

    You want your character body to interact with rigid bodies.

    Solution

    Note

    This recipe applies equally well in both 2D and 3D nodes.

    By default, a CharacterBody2D moved with move_and_slide() or move_and_collide() will not push any RigidBody2D it collides with. The rigid body doesn’t react at all, and behaves just like a StaticBody2D.

    alt +alt

    In some cases, this might be all you need. However, if you want to be able to push the bodies, you’ll need to make some changes.

    For this example, we’ll use the 2D character described in the Platform character recipe. This example uses the most common movement method for character bodies: move_and_slide(). If you’re using move_and_collide(), you’ll need to adjust the examples below accordingly.

    You have two options when deciding how to interact with rigid bodies:

    1. You can just push them, ignoring physics. If you’re familiar with Godot 3.x, this is equivalent to the “infinite inertia” option.
    2. You can give them a push based on the character’s imagined “mass” and velocity. This will give you a “realistic” result - pushing heavy bodies a little, and lighter bodies a lot.

    We’ll try out both options below.

    Infinite Inertia

    This option has its pros and cons. The biggest pro is, you don’t need any extra code. You just need to correctly set the collision layers/masks of the objects. For this example, we’ve defined three physics layers:

    alt +alt

    For the rigid body, we’ve placed it on the “items” layer (layer 3), and left the mask at the default (masking all layers):

    alt +alt

    Then, we’ve placed the player on the “player” layer (layer 2), and configured the mask to ignore the “items”:

    alt +alt

    Running the game, we now see we can push the boxes around. Note that the mass of the box doesn’t matter - they’ll all be pushed the same.

    alt +alt

    Here, you can also see the downside of this option. Because the physics of the boxes is being ignored, they can clip through walls and you can’t jump on top of them.

    For some games, this will be fine. If you want to prevent the clipping, you’ll need to go with option 2.

    Applying impulses

    To give the colliding body a “push” we’ll need to apply an impulse. An impulse is an instantaneous “kick” - think of a bat hitting a ball. This is as opposed to a force, which is a continuous “push” on an object.

    # This represents the player's inertia.
     var push_force = 80.0
     
     func _physics_process(delta):
    @@ -15,21 +15,21 @@
             var c = get_slide_collision(i)
             if c.get_collider() is RigidBody2D:
                 c.get_collider().apply_central_impulse(-c.get_normal() * push_force)
    -

    The collision normal points out of the rigid body, so we reverse it to point away from the character and apply the push_force factor. Now pushing works again, but it won’t force the rigid bodies through walls:

    alt -alt

    You’ll need to adjust the push_force in relation to the mass of your rigid bodies. Too high a force will still cause clipping, while too low will prevent pushing at all.

    Experiment to find the settings that work for your particular game.

    Download This Project

    Download the project’s example code here: https://github.com/godotrecipes/character_vs_rigid

    Watch Video

    + + \ No newline at end of file diff --git a/docs/4.x/physics/index.html b/docs/4.x/physics/index.html index d5cc7b49..bd2f2b79 100644 --- a/docs/4.x/physics/index.html +++ b/docs/4.x/physics/index.html @@ -1,19 +1,19 @@ -Physics :: Godot 4 Recipes - +Physics :: Godot 4 Recipes + - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/physics/rigidbody_drag_drop/index.html b/docs/4.x/physics/rigidbody_drag_drop/index.html index f849d2c7..ff3b8598 100644 --- a/docs/4.x/physics/rigidbody_drag_drop/index.html +++ b/docs/4.x/physics/rigidbody_drag_drop/index.html @@ -1,5 +1,5 @@ -RigidBody2D: Drag and Drop :: Godot 4 Recipes - +RigidBody2D: Drag and Drop :: Godot 4 Recipes +

    RigidBody2D: Drag and Drop

    Problem

    You want to pick up and move rigid bodies with the mouse.

    Solution

    Working with rigid bodies can be tricky. Godot’s physics engine controls their movements, and interfering with that can often lead to unexpected results. The key is to make use of the body’s mode property. This applies equally well in 2D or 3D.

    Body setup

    We’ll start with our rigid body object, adding a Sprite2D and CollisionShape2D. You can also add a PhysicsMaterial if you want to set Bounce and Friction properties.

    We’re going to use the rigid body’s freeze property to remove it from the control of the physics engine while we’re dragging it. Since we still want it to be movable, we need to set the Freeze Mode to “Kinematic”, rather than the default value of “Static”.

    Place the body in a group called “pickable”. We’ll use this to allow for multiple instances of the pickable object in the main scene. Attach a script to the body and connect the its _input_event signal.

    extends RigidBody2D
     
    @@ -45,17 +45,17 @@
     

    Note the use of get_last_mouse_velocity() to pass the impulse to the object - be careful with this! You may find yourself launching the rigid bodies at high speeds, especially if the bodies have low mass values. It’s probably a good idea to scale this to a reasonable value and clamp() it to some maximum. Experiment to find out what works for you.

    Download This Project

    Download the project code here: https://github.com/godotrecipes/rigidbody_drag_drop

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/physics/smooth_rigid_rotate/index.html b/docs/4.x/physics/smooth_rigid_rotate/index.html index 02f95be7..91633d87 100644 --- a/docs/4.x/physics/smooth_rigid_rotate/index.html +++ b/docs/4.x/physics/smooth_rigid_rotate/index.html @@ -1,5 +1,5 @@ -RigidBody2D: Look at Target :: Godot 4 Recipes - +RigidBody2D: Look at Target :: Godot 4 Recipes +

    RigidBody2D: Look at Target

    Problem

    You want a rigid body to rotate smoothly to look at a target.

    Solution

    Using RigidBody2D can be tricky. Because it’s controlled by Godot’s physics engine, you need to apply forces rather than moving it directly. Before doing anything with rigid bodies, I highly recommend looking at the RigidBody2D API doc.

    To rotate a body, we need to apply a rotational force - a torque. Once the body is rotating, we want the torque to get smaller as we get closer to the final rotation.

    This is the perfect situation to use the dot product. Its sign will tell us whether the target is to the left/right, and its magnitude will tell us how far away from the target direction we’re pointing.

    Tip

    See Vectors: Using Dot and Cross Product for a brief review of the dot product.

    extends RigidBody2D
     
    @@ -12,17 +12,17 @@
     

    You may be wondering why we’re using the transform.y here, when transform.x is the body’s forward vector. Using transform.x, the dot product would be at its maximum when the body is directly pointing at the target, but we want the torque to be zero at that point. Using transform.y means that our torque will be higher when we’re not aligned with the target.

    Skip the Rigid Body Entirely

    You can avoid all of this entirely by not rotating your rigid body at all! Instead, change the child sprite’s rotation to point at the target. You can use lerp() or a Tween to make the rotation as smooth as you wish.

    In many cases, this will be a great solution. Remember, the underlying body’s orientation doesn’t have to match the attached sprite!

    - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/recent/index.html b/docs/4.x/recent/index.html index 2b5ac77c..3d23acfb 100644 --- a/docs/4.x/recent/index.html +++ b/docs/4.x/recent/index.html @@ -1,19 +1,19 @@ -Fresh Recipes :: Godot 4 Recipes - +Fresh Recipes :: Godot 4 Recipes + - - \ No newline at end of file +
    + + \ No newline at end of file diff --git a/docs/4.x/tags/index.html b/docs/4.x/tags/index.html index 548f518a..3f4a3416 100644 --- a/docs/4.x/tags/index.html +++ b/docs/4.x/tags/index.html @@ -1,19 +1,19 @@ -Tags :: Godot 4 Recipes - +Tags :: Godot 4 Recipes +

    Tags

      - - \ No newline at end of file +
      + + \ No newline at end of file diff --git a/docs/4.x/ui/heart_containers_3/index.html b/docs/4.x/ui/heart_containers_3/index.html index 97f00c26..ca90d449 100644 --- a/docs/4.x/ui/heart_containers_3/index.html +++ b/docs/4.x/ui/heart_containers_3/index.html @@ -1,9 +1,9 @@ -Heart Containers: 3 Ways :: Godot 4 Recipes - +Heart Containers: 3 Ways :: Godot 4 Recipes +

      Heart Containers: 3 Ways

      Problem

      You need to display a heart container bar (or other icon-based bar).

      Solution

      A common way of displaying the player’s health is via a series of icons (typically hearts) that disappear as the player takes damage.

      In this recipe, we’re going to explore three ways of displaying this information, which I’m labeling “simple”, “empty”, and “partial”:

      alt -alt

      This image shows what the bar displays when the player has 3 health.

      • simple: Only the hearts are displayed.
      • empty: Empty heart containers are displayed.
      • partial: The player can have partially filled containers.

      Setting up the bar

      The heart images I’m using are 53x45. You can get them here:

      Kenney.nl: Platformer Art Deluxe

      Ideally, your heart bar will be easy to drop into your overall HUD/UI. It therefore makes sense to make it a separate scene. We’ll start with an HBoxContainer which will keep things aligned. Set the Theme Overrides/Constants/Separation to 5.

      Add a TextureRect child. Drag your heart texture into the Texture property and set the Stretch Mode to “Keep”. Name the node “1” and then press “Ctrl-D” to duplicate the node for as many hearts as you need (5 in this example). Your node setup should look like this:

      alt -alt

      Adding a script

      The script below will cover all three bar configurations for flexibility. You’ll probably only need one in your game, so you can remove the code relating to the other modes.

      To begin, we’re going to load the textures we need and define our three bar modes:

      extends HBoxContainer
      +

      Heart Containers: 3 Ways

      Problem

      You need to display a heart container bar (or other icon-based bar).

      Solution

      A common way of displaying the player’s health is via a series of icons (typically hearts) that disappear as the player takes damage.

      In this recipe, we’re going to explore three ways of displaying this information, which I’m labeling “simple”, “empty”, and “partial”:

      alt +alt

      This image shows what the bar displays when the player has 3 health.

      • simple: Only the hearts are displayed.
      • empty: Empty heart containers are displayed.
      • partial: The player can have partially filled containers.

      Setting up the bar

      The heart images I’m using are 53x45. You can get them here:

      Kenney.nl: Platformer Art Deluxe

      Ideally, your heart bar will be easy to drop into your overall HUD/UI. It therefore makes sense to make it a separate scene. We’ll start with an HBoxContainer which will keep things aligned. Set the Theme Overrides/Constants/Separation to 5.

      Add a TextureRect child. Drag your heart texture into the Texture property and set the Stretch Mode to “Keep”. Name the node “1” and then press “Ctrl-D” to duplicate the node for as many hearts as you need (5 in this example). Your node setup should look like this:

      alt +alt

      Adding a script

      The script below will cover all three bar configurations for flexibility. You’ll probably only need one in your game, so you can remove the code relating to the other modes.

      To begin, we’re going to load the textures we need and define our three bar modes:

      extends HBoxContainer
       
       enum modes {SIMPLE, EMPTY, PARTIAL}
       
      @@ -38,21 +38,21 @@
                   get_child(i).texture = heart_half
               else:
                   get_child(i).texture = heart_empty
      -

      Here’s an example using each of the bar modes:

      alt -alt

      Wrapping up

      Use this heart bar setup as a basis for your own HUD. This technique can be expanded to support a wide variety of information displays.

      Download This Project

      Download the project’s example code here: https://github.com/godotrecipes/heart_bars

      + + \ No newline at end of file diff --git a/docs/4.x/ui/index.html b/docs/4.x/ui/index.html index 63f6aef7..c26e274f 100644 --- a/docs/4.x/ui/index.html +++ b/docs/4.x/ui/index.html @@ -1,19 +1,19 @@ -UI :: Godot 4 Recipes - +UI :: Godot 4 Recipes +
      - - \ No newline at end of file +
      + + \ No newline at end of file diff --git a/docs/4.x/ui/level_select/index.html b/docs/4.x/ui/level_select/index.html index cd7daf73..581f5978 100644 --- a/docs/4.x/ui/level_select/index.html +++ b/docs/4.x/ui/level_select/index.html @@ -1,13 +1,13 @@ -Level Select Menu :: Godot 4 Recipes - +Level Select Menu :: Godot 4 Recipes +

      Level Select Menu

      Problem

      Your game needs a “level select” menu, where the user can choose from a grid of options.

      alt -alt

      Solution

      As shown in the example above, we’ll make a scrolling grid of level “boxes” that the player can choose from. Let’s start with the individual level boxes:

      1: Level box

      Here’s the node setup:

      LevelBox:  PanelContainer
      +

      Level Select Menu

      Problem

      Your game needs a “level select” menu, where the user can choose from a grid of options.

      alt +alt

      Solution

      As shown in the example above, we’ll make a scrolling grid of level “boxes” that the player can choose from. Let’s start with the individual level boxes:

      1: Level box

      Here’s the node setup:

      LevelBox:  PanelContainer
            Label
            MarginContainer
                TextureRect
      -

      The TextureRect is for displaying the lock icon, and the Label for displaying the level number. When one is showing, the other is hidden.

      You can style these as you like, here’s an example:

      alt -alt

      Make sure to set the LevelBox’s Custom Minimum Size in the Inspector. We’re using (110, 110) in the example, but it depends on what size layout you’re going for.

      Now add a script and connect the gui_input signal.

      @tool
      +

      The TextureRect is for displaying the lock icon, and the Label for displaying the level number. When one is showing, the other is hidden.

      You can style these as you like, here’s an example:

      alt +alt

      Make sure to set the LevelBox’s Custom Minimum Size in the Inspector. We’re using (110, 110) in the example, but it depends on what size layout you’re going for.

      Now add a script and connect the gui_input signal.

      @tool
       extends PanelContainer
       
       signal level_selected
      @@ -40,17 +40,17 @@
           if event is InputEventMouseButton and event.pressed:
               level_selected.emit(level_num)
               print("Clicked level ", level_num)
      -

      We’re using @tool here so that we can make changes to the properties in the inspector and see them right away, without running the scene. Go ahead and try clicking the Locked property and verify that you see the lock appear/disappear.

      Since we don’t have actual levels to load in this project, the print() statement can help test that the click is being detected.

      2: Grid

      Once you have the box scene completed, add a new scene with a GridContainer. Add any number of LevelBox instances under it, making sure to set the Columns value. Here’s one with 6 columns:

      alt -alt

      In this example Theme Overrides/Constants/H Separation and V Separation are set to 10.

      Save this scene as LevelGrid. In the menu, we’ll use multiple instances to display the desired number of levels.

      3: Menu screen

      Now we can put together the final menu.

      Here’s the basic layout we’re going for:

      alt -alt

      We’ll create it with these nodes:

      LevelMenu: MarginContainer
      +

      We’re using @tool here so that we can make changes to the properties in the inspector and see them right away, without running the scene. Go ahead and try clicking the Locked property and verify that you see the lock appear/disappear.

      Since we don’t have actual levels to load in this project, the print() statement can help test that the click is being detected.

      2: Grid

      Once you have the box scene completed, add a new scene with a GridContainer. Add any number of LevelBox instances under it, making sure to set the Columns value. Here’s one with 6 columns:

      alt +alt

      In this example Theme Overrides/Constants/H Separation and V Separation are set to 10.

      Save this scene as LevelGrid. In the menu, we’ll use multiple instances to display the desired number of levels.

      3: Menu screen

      Now we can put together the final menu.

      Here’s the basic layout we’re going for:

      alt +alt

      We’ll create it with these nodes:

      LevelMenu: MarginContainer
            VBoxContainer
               Title:  Label
                HBoxContainer
                   BackButton:  TextureButton
                   ClipControl:  Control
                   NextButton:  TextureButton
      -

      Adjust the node properties:

      • LevelMenu
        • Theme Overrides/Constants/Margins: 20
      • VBoxContainer
        • Theme Overrides/Constants/Separation: 50
      • Title
        • Style the font however you like
      • BackButton / NextButton
        • Ignore Texture Size: On
        • Stretch Mode: Keep Centered
        • Layout/Container Sizing/Horizontal/Expand: On
      • ClipControl
        • Layout/Clip Contents: On
        • Layout/Custom Minimum Size: (710, 350) (size of the LevelGrid)

      The ClipControl node is where the grid goes. Enabling Clip Contents means that if the contents are larger than the control, they’ll be cropped. That will allow us to make a horizontally scrolling set of grids. Add an HBoxContainer called GridBox to ClipControl, and instance 3 (or more) LevelGrids inside it.

      Make sure to set Theme Overrides/Constants/Separation to 0.

      Your layout should look something like this (we’ve disabled Clip Contents in order to show what’s happening):

      alt -alt

      With Clip Content, the three grids are all there, but the ClipControl only shows one at a time.

      Now, to scroll the menu, we need to shift the GridBox by 710 pixels to the left/right.

      110 (width of each LevelBox)
      +

      Adjust the node properties:

      • LevelMenu
        • Theme Overrides/Constants/Margins: 20
      • VBoxContainer
        • Theme Overrides/Constants/Separation: 50
      • Title
        • Style the font however you like
      • BackButton / NextButton
        • Ignore Texture Size: On
        • Stretch Mode: Keep Centered
        • Layout/Container Sizing/Horizontal/Expand: On
      • ClipControl
        • Layout/Clip Contents: On
        • Layout/Custom Minimum Size: (710, 350) (size of the LevelGrid)

      The ClipControl node is where the grid goes. Enabling Clip Contents means that if the contents are larger than the control, they’ll be cropped. That will allow us to make a horizontally scrolling set of grids. Add an HBoxContainer called GridBox to ClipControl, and instance 3 (or more) LevelGrids inside it.

      Make sure to set Theme Overrides/Constants/Separation to 0.

      Your layout should look something like this (we’ve disabled Clip Contents in order to show what’s happening):

      alt +alt

      With Clip Content, the three grids are all there, but the ClipControl only shows one at a time.

      Now, to scroll the menu, we need to shift the GridBox by 710 pixels to the left/right.

      110 (width of each LevelBox)
           * 6 (grid columns)
           + 10 (grid spacing) * 5
           == 710
      @@ -85,17 +85,17 @@
       

      When you run the scene, try clicking the “Next” and “Back” buttons and verify that it’s scrolling as expected. Clicking the individual level boxes should print to the console.

      Download the example project to see the whole thing in action, including some tweens for the scrolling action (because tweens make everything better).

      Download This Project

      Download the project code here: https://github.com/godotrecipes/ui_level_select

      - - \ No newline at end of file +
      + + \ No newline at end of file diff --git a/docs/4.x/ui/minimap/index.html b/docs/4.x/ui/minimap/index.html index 94b7e153..e2c84ef8 100644 --- a/docs/4.x/ui/minimap/index.html +++ b/docs/4.x/ui/minimap/index.html @@ -1,17 +1,17 @@ -Minimap/radar :: Godot 4 Recipes - +Minimap/radar :: Godot 4 Recipes +

      Minimap/radar

      Problem

      You want a minimap or radar-style UI item showing the locations of objects outside of the player’s view.

      Solution

      Here’s an example of what we are going for: -

      Project setup

      To illustrate this feature, we’ll start with a simplified top-down game using the Autotile recipe and a player based on the Top-down character recipe. See the linked recipes for details on how these parts work.

      Note

      The art in this project comes from kenney.nl, which you can download here: Minimap Assets.

      Our main scene setup looks like this:

      alt -alt

      The CanvasLayer node is there to hold our UI, including the minimap/radar we’re making in this recipe.

      UI Layout

      The first step will be to create the layout for the minimap. In order to work with whatever other UI elements exist in the game, it must resize smoothly, and integrate well with a container-based layout.

      Add a MarginContainer first. Set its Theme Overrides/Constants all to 5. This control will hold the rest of the nodes and ensure it doesn’t bleed over into any other elements. Name it “Minimap” and save the scene.

      Next, add a NinePatchRect node. This node is similar to a TextureRect but handles resizing differently by not stretching the corners/edges. Drop the panel_woodDetail_blank.png image from the asset folder into the Texture property. This is a 128x128 image and if we scale the root MarginContainer, the image becomes stretched and ugly:

      alt -alt

      Using the NinePatchRects’s properties, we can ensure that the frame remains the same size when stretched. You can define these properties graphically in the “TextureRegion” panel, but it’s sometimes easier to enter the values directly. Set all four properties in the Patch Margin section to 64 and change the node’s name to “Frame”.

      Now observe what happens when we change the size:

      alt -alt

      Next, we’d like to fill in the inner part of the frame with the grid pattern pattern_blueprintPaper.png:

      alt -alt

      However, we need it to tile automatically no matter what size we make the frame. Also, since this grid area is where our minimap markers will appear, we don’t want the grid extending past the edges of the frame.

      As a child of the MiniMap (and a sibling of the Frame), add another MarginContainer. Set all four margin properties in Theme Overrides/Constants to 20. As a child of this node, add a TextureRect and assign its Texture to the above image. Set its Stretch Mode to “Tile”. Name this node “Grid”.

      Try changing the size of your root node to see the effect:

      alt -alt

      For now, let’s leave the minimap’s size at (200, 200) - you can check the root node’s Size property in the Layout section to confirm.

      At this point, your scene tree should look like the following:

      alt -alt

      Map Markers

      As a child of Grid, add a Sprite2D node named “PlayerMarker” and give it the minimapIcon_arrowA.png texture. Note the sprite’s Transform/Position property: (0, 0), which places it exactly in the top-left corner of the Grid:

      alt -alt

      If our Grid size is currently (150, 150) (you can check this in its Size property), then its center will be (75, 75). Put the PlayerMarker’s Position there:

      alt -alt

      Don’t worry, we’ll automate this later.

      Add two more Sprite2D nodes: “MobMarker” and “AlertMarker”, using the minimapIcon_jewelRed.png and minimapIcon_exclamationYellow.png textures.

      alt -alt

      These will represent two different types of objects in the game world. Click the “Toggle Visibility” button next to each so that they won’t appear by default.

      Scripting the map markers

      At this point, we have some decisions to make. How we approach populating the minimap with the objects in the world has a lot to do with how the game is set up. Since this is a very minimal demonstration project, we’re going keep the process simple. In a larger game, you may need to use a more robust approach.

      For this demo, we have two game objects: a Mob, which wanders around the map randomly, and a Crate, which the player can pick up. Many of these are scattered around the main scene. Each will need to be represented by one of the map markers we made.

      Add each item that you want to appear on the minimap to a group named “minimap_objects”. In each object’s script, assign it a minimap_icon property:

      # In the mob's script:
      +

      Project setup

      To illustrate this feature, we’ll start with a simplified top-down game using the Autotile recipe and a player based on the Top-down character recipe. See the linked recipes for details on how these parts work.

      Note

      The art in this project comes from kenney.nl, which you can download here: Minimap Assets.

      Our main scene setup looks like this:

      alt +alt

      The CanvasLayer node is there to hold our UI, including the minimap/radar we’re making in this recipe.

      UI Layout

      The first step will be to create the layout for the minimap. In order to work with whatever other UI elements exist in the game, it must resize smoothly, and integrate well with a container-based layout.

      Add a MarginContainer first. Set its Theme Overrides/Constants all to 5. This control will hold the rest of the nodes and ensure it doesn’t bleed over into any other elements. Name it “Minimap” and save the scene.

      Next, add a NinePatchRect node. This node is similar to a TextureRect but handles resizing differently by not stretching the corners/edges. Drop the panel_woodDetail_blank.png image from the asset folder into the Texture property. This is a 128x128 image and if we scale the root MarginContainer, the image becomes stretched and ugly:

      alt +alt

      Using the NinePatchRects’s properties, we can ensure that the frame remains the same size when stretched. You can define these properties graphically in the “TextureRegion” panel, but it’s sometimes easier to enter the values directly. Set all four properties in the Patch Margin section to 64 and change the node’s name to “Frame”.

      Now observe what happens when we change the size:

      alt +alt

      Next, we’d like to fill in the inner part of the frame with the grid pattern pattern_blueprintPaper.png:

      alt +alt

      However, we need it to tile automatically no matter what size we make the frame. Also, since this grid area is where our minimap markers will appear, we don’t want the grid extending past the edges of the frame.

      As a child of the MiniMap (and a sibling of the Frame), add another MarginContainer. Set all four margin properties in Theme Overrides/Constants to 20. As a child of this node, add a TextureRect and assign its Texture to the above image. Set its Stretch Mode to “Tile”. Name this node “Grid”.

      Try changing the size of your root node to see the effect:

      alt +alt

      For now, let’s leave the minimap’s size at (200, 200) - you can check the root node’s Size property in the Layout section to confirm.

      At this point, your scene tree should look like the following:

      alt +alt

      Map Markers

      As a child of Grid, add a Sprite2D node named “PlayerMarker” and give it the minimapIcon_arrowA.png texture. Note the sprite’s Transform/Position property: (0, 0), which places it exactly in the top-left corner of the Grid:

      alt +alt

      If our Grid size is currently (150, 150) (you can check this in its Size property), then its center will be (75, 75). Put the PlayerMarker’s Position there:

      alt +alt

      Don’t worry, we’ll automate this later.

      Add two more Sprite2D nodes: “MobMarker” and “AlertMarker”, using the minimapIcon_jewelRed.png and minimapIcon_exclamationYellow.png textures.

      alt +alt

      These will represent two different types of objects in the game world. Click the “Toggle Visibility” button next to each so that they won’t appear by default.

      Scripting the map markers

      At this point, we have some decisions to make. How we approach populating the minimap with the objects in the world has a lot to do with how the game is set up. Since this is a very minimal demonstration project, we’re going keep the process simple. In a larger game, you may need to use a more robust approach.

      For this demo, we have two game objects: a Mob, which wanders around the map randomly, and a Crate, which the player can pick up. Many of these are scattered around the main scene. Each will need to be represented by one of the map markers we made.

      Add each item that you want to appear on the minimap to a group named “minimap_objects”. In each object’s script, assign it a minimap_icon property:

      # In the mob's script:
       var minimap_icon = "mob"
       
       # In the crate's script:
      @@ -49,10 +49,10 @@
       

      Next, we’ll find each object’s position relative to the player and use that to find the marker’s position (remembering to offset by grid.size / 2 because the control’s origin is in the top left corner).

      for item in markers:
           var obj_pos = (item.position - player.position) * grid_scale + grid.size / 2
           markers[item].position = obj_pos
      -

      The problem with this is that markers can be placed outside the grid:

      alt -alt

      To fix this, after calculating obj_pos, but before setting the marker’s position, clamp it to the grid’s rectangle:

      obj_pos = obj_pos.clamp(Vector2.ZERO, grid.size)
      -

      alt -alt

      We can also decide what to do about markers that are “off-screen” - when they would be outside the grid’s rectangle. Choose one of the following options (do this also before using clamp()). The first option is to hide them:

      if grid.get_rect().has_point(obj_pos + grid.position):
      +

      The problem with this is that markers can be placed outside the grid:

      alt +alt

      To fix this, after calculating obj_pos, but before setting the marker’s position, clamp it to the grid’s rectangle:

      obj_pos = obj_pos.clamp(Vector2.ZERO, grid.size)
      +

      alt +alt

      We can also decide what to do about markers that are “off-screen” - when they would be outside the grid’s rectangle. Choose one of the following options (do this also before using clamp()). The first option is to hide them:

      if grid.get_rect().has_point(obj_pos + grid.position):
           markers[item].show()
       else:
           markers[item].hide()
      @@ -60,8 +60,8 @@
           markers[item].scale = Vector2(1, 1)
       else:
           markers[item].scale = Vector2(0.75, 0.75)
      -

      alt -alt

      Removing objects

      If a mob gets killed or a crate picked up, the game will crash because the marker reference is no longer valid. We need a way to ensure markers are removed when the object is. Here’s a quick way to do this in our rudimentary demo setup:

      Add signal removed to any object that you’ve put in the “minimap_objects” group. Emit this signal when the object is destroyed (or collected), along with a reference to itself so the map can identify it:

      removed.emit(self)
      +

      alt +alt

      Removing objects

      If a mob gets killed or a crate picked up, the game will crash because the marker reference is no longer valid. We need a way to ensure markers are removed when the object is. Here’s a quick way to do this in our rudimentary demo setup:

      Add signal removed to any object that you’ve put in the “minimap_objects” group. Emit this signal when the object is destroyed (or collected), along with a reference to itself so the map can identify it:

      removed.emit(self)
       

      In the _ready() of the main script, connect these signals to the minimap:

      func _ready():
           for object in get_tree().get_nodes_in_group("minimap_objects"):
               object.removed.connect(minimap._on_object_removed)
      @@ -81,21 +81,21 @@
                   zoom += 0.1
               if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
                   zoom -= 0.1
      -

      That’s it - observe the effect of scrolling in and out:

      alt -alt

      Wrapping up

      While this is a pretty big recipe, I’ve tried to make it flexible enough for you to incorporate into whatever project you’re working on.

      Some other things you might want to add:

      • More marker types for different game objects.
      • Adding new units when they’re spawned (hint: use a signal just like we did for removing units).
      • Clicking on a marker to get info about it.
      • Use a picture of your map as the minimap background instead of the grid.

      Download This Project

      Download the project’s example code here: https://github.com/godotrecipes/minimap

      + + \ No newline at end of file diff --git a/src-4/content/3D/assets/level_design.md b/src-4/content/3D/assets/level_design.md index 71488696..69d41cfc 100644 --- a/src-4/content/3D/assets/level_design.md +++ b/src-4/content/3D/assets/level_design.md @@ -10,20 +10,72 @@ draft: true We have several options to consider for designing our level: -* **GridMap** +### Options - Using the built-in {{< gd-icon GridMap >}}`GridMap` node allows you to layout meshes in a grid in the editor. It's similar in concept to the 2D {{< gd-icon TileMap >}}`TileMap` node, though with less functionality. +#### GridMap - This option has a few drawbacks: +Using the built-in {{< gd-icon GridMap >}}`GridMap` node allows you to layout meshes in a grid in the editor. It's similar in concept to the 2D {{< gd-icon TileMap >}}`TileMap` node, though with less functionality. - 1. The GridMap functionality in Godot is fairly rudimentary and hasn't been updated in some time. - 1. Placement is limited to a fixed grid layout, so you don't have as much control over how your meshes are placed. +This option has a few drawbacks: +1. The GridMap functionality in Godot is fairly rudimentary (especially compared to its 2D equivalent) and hasn't been updated in some time. +1. Placement is limited to a fixed grid layout, so you don't have as much control over how your meshes are placed. -* **Directly placing models** +#### Directly placing models -pros/cons +Alternatively, you can turn on grid snapping in the editor and just drag scenes directly from the **FileSystem** tab to place them. This has the advantage of being more flexible than `GridMap`, although a bit more manual in how you go about placing objects. -* **External tool** +#### External tool -pros/cons +A third option is to use a separate tool to design your levels and then import them to Godot. [Blender](https://blender.org/) is a very popular choice for this. Odds are, if you're making your own 3D assets, you're probably already using Blender to do your modeling. + +Using Blender, you can use your familiar modeling tools to create your level and then export that as a `GLTF` for Godot. You can even use Godot [Import Hints](https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/importing_scenes.html#import-hints) to have Godot automatically create collision shapes, lights, etc in your imported level. + +You can even use Godot's built-in [Blender support](https://docs.godotengine.org/en/stable/tutorials/assets_pipeline/importing_scenes.html#importing-blend-files-directly-within-godot) to make this even easier. Changes to your `.blend` file will instantly appear in your Godot project. + +### Interactable objects + +#### Door + +Find the `wall_doorway_scaffold.glb` file in the **FileSystem** and double-click to check the import settings and see that you've created a static collision for both meshes (the door frame and the door). Right-click to create a "New Inherited Scene". + +Add an {{< gd-icon AnimationPlayer >}}`AnimationPlayer` node, which we'll use to animate the door opening. Your node tree should look like this: + +**SS** + +The "wall_doorway_scaffold_door" is the mesh that we want to rotate. +We want to be able to open the door in either direction, so we're going to create two animations. Both of them rotate the door's **Y** rotation by `90°`, but "open+" opens in the **+Z** direction and "open-" does the opposite. This way, when the player interacts with the door, we can open it away from them, no matter which side they're on. + +Add the {{< gd-icon StaticBody3D >}}`StaticBody3D` child of the door to a group called "interactable". This is the object the player is going to detect. If it's in that group, the player will call `interact()` on it. + +Add a script to the door scene: + +```gdscript +extends Node3D + +var open = false + +func interact(dir): + if open: + return + if dir.dot(global_transform.basis.z) < 0: + $AnimationPlayer.play("open+") + else: + $AnimationPlayer.play("open-") + open = true +``` + +#### Chest + +Find the `chest.glb` file in the **FileSystem** and double-click to check the import settings and see that you've created a static collision for both meshes (the chest body and lid). Right-click to create a "New Inherited Scene". + +Add an {{< gd-icon AnimationPlayer >}}`AnimationPlayer` and create an animation of the chest lid opening. + +Similar to the door, add the static body to the "interactable" group and an `interact()` function in its script: + +```gdscript +extends Node3D + +func interact(_dir): + $AnimationPlayer.play("open") +``` diff --git a/src-4/content/_index.md b/src-4/content/_index.md index 8eecb223..72968856 100644 --- a/src-4/content/_index.md +++ b/src-4/content/_index.md @@ -30,7 +30,7 @@ If you're new to Godot, start here: [What is Godot?](/godot_recipes/4.x/g101/sta #### Beginners -If you're new to game development, start with the ["Godot 101: Basics"](/godot_recipes/3.x/basics/) section. There you'll find an introduction to the Godot application, and a step-by-step guide to creating your first project. There is a lot of material to absorb here. Don't feel discouraged if you feel you don't get it at first. Repetition is the key to learning complex topics; the more you work with Godot's features, the more familiar and _easy_ they will start to feel. +If you're new to game development, start with the ["Godot 101: Basics"](/godot_recipes/4.x/basics/) section. There you'll find an introduction to the Godot application, and a step-by-step guide to creating your first project. There is a lot of material to absorb here. Don't feel discouraged if you feel you don't get it at first. Repetition is the key to learning complex topics; the more you work with Godot's features, the more familiar and _easy_ they will start to feel. {{% notice info %}} It's assumed that you have at least some general programming experience. If you're *completely* new to programming, click [here](https://docs.godotengine.org/en/stable/getting_started/step_by_step/index.html) for tips on how to get started. diff --git a/src-4/content/input/multi_unit_select.md b/src-4/content/input/multi_unit_select.md index 4531a653..a877855e 100644 --- a/src-4/content/input/multi_unit_select.md +++ b/src-4/content/input/multi_unit_select.md @@ -79,9 +79,9 @@ We start by recording the location when we released the button, and use that to ```gdscript var space = get_world_2d().direct_space_state var query = PhysicsShapeQueryParameters2D.new() - q.shape = select_rect - q.collision_mask = 2 # Units are on collision layer 2 - q.transform = Transform2D(0, (drag_end + drag_start) / 2) + query.shape = select_rect + query.collision_mask = 2 # Units are on collision layer 2 + query.transform = Transform2D(0, (drag_end + drag_start) / 2) selected = space.intersect_shape(query) ``` diff --git a/src-4/content/input/processing_inputs.md b/src-4/content/input/processing_inputs.md new file mode 100644 index 00000000..45c84d78 --- /dev/null +++ b/src-4/content/input/processing_inputs.md @@ -0,0 +1,7 @@ + + +Examples w/the flowchart + +If any function consumes the event, it can call Viewport.set_input_as_handled(), and the event will not spread any more. + +If the control wants to "consume" the event, it will call Control.accept_event() and the event will not spread any more