[{"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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’re looking to make a 3D driving or racing game and don’t know where to start.\nSolution Note Even in 3D, cars tend to remain on the ground. For this reason, movement can (mostly) be treated as if it were 2D. Much of the car’s movement code will be very much like the 2D: Car Steering recipe. It’s recommended that you review that recipe before proceeding with this one.\nGodot does provide a VehicleBody node, which is based on RigidBody and includes a complex simulation of engine, braking, suspension, etc. However, this introduces a lot of complexity and tends to be overkill for most casual racing/driving games. For that reason, we’re going with a CharacterBody3D based solution here.\nInfo If you’re interested in how to work with VehicleBody, I highly recommend this series by Bastiaan Olij.\nSetting up the car Before we start coding, we need to find a 3D model of a car and import it to Godot.\nImporting the Model Here’s the car model we’ll use for this demonstration:\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 some of the other cars later.\nTo import the car, find the model in the \"Models/GLTF format\" folder. In our case, we want the sedanSports.glb. Drop this file in your new Godot project, preferably in a separate folder such as res://assets/cars/.\nSelect the file in Godot and go to the “Import” tab. Change the Root Type to “CharacterBody3D” and click “Reimport”. Now we’re ready to use this car.\nSetting up the CharacterBody3D Double-click on the sedanSports.glb file and choose “New Inherited”. You’ll have a new scene that looks like this:\nNote the individual meshes for each of the car’s parts. There’s also a stray “tmpParent” Node3D node, but we can ignore that.\nThe CharacterBody3D has a warning about missing collision shapes, so we’ll need to fix that first. We’re going to add 3 CollisionShapes: a BoxShape for the car’s body, and a CylinderShape for each of the front and rear axles.\nOnce the shapes are set up they should look something like this:\nTip To ensure the front and rear shapes match, just create and size one of them, then duplicate it. It is also a good idea to name the CollisionShape nodes to help keep track of them - CollisionBody, CollisionWheelsFront, and CollisionWheelsRear would be a good example.\nBase script We want to be able to make cars that can be driven by human or AI control. In either case, most of the movement code will be the same - it’s really just the input that will be different. For this reason, we can use a base car script that can be shared between them.\nMake a new script called car_base.gd. We’ll start with our variables: some exports to allow for adjusting the car’s behavior, and some others to track its state.\nextends CharacterBody3D # Car behavior parameters, adjust as needed @export var gravity = -20.0 @export var wheel_base = 0.6 # distance between front/rear axles @export var steering_limit = 10.0 # front wheel max turning angle (deg) @export var engine_power = 6.0 @export var braking = -9.0 @export var friction = -2.0 @export var drag = -2.0 @export var max_speed_reverse = 3.0 # Car state properties var acceleration = Vector3.ZERO # current acceleration var velocity = Vector3.ZERO # current velocity var steer_angle = 0.0 # current wheel angle Note that rather than using a gravity variable you can set the global value in “Project Settings”. Having it separate does allow for different behavior for different game objects. It’s up to you, use whichever works best for your game.\nengine_power and braking will apply for accelerating and decelerating the car.\ndrag and friction are explained here.\nThe rest of the script will be very similar to the 2D version, which a few changes to work correctly with Node3Ds and Transforms.\nWe’ll start with _physics_process().\nHere we check if the car is on the ground before applying controls - you can’t steer in mid-air! Then we apply the standard movement equations.\nNote that we’re using move_and_slide_with_snap(), which will keep the car from coming off slopes (if your track has them). We’re also using the car’s local down vector as the snap - again, to handle slopes correctly.\nfunc _physics_process(delta): if is_on_floor(): get_input() apply_friction(delta) calculate_steering(delta) acceleration.y = gravity velocity += acceleration * delta velocity = move_and_slide_with_snap(velocity, -transform.basis.y, Vector3.UP, true) This function applies friction (proportional to the car’s velocity) and drag (proportional to the velocity squared). This will not only slow the car when not applying power, but it will also determine the car’s maximum speed.\nfunc apply_friction(delta): if velocity.length() \u003c 0.2 and acceleration.length() == 0: velocity.x = 0 velocity.z = 0 var friction_force = velocity * friction * delta var drag_force = velocity * velocity.length() * drag * delta acceleration += drag_force + friction_force Finally, we need to calculate turning, using the same simplified “bicycle” model we used in the 2D car. Once the new velocity is found, look_at() rotates the body to point in the correct direction. We’re not including drifting/traction here - that will come later.\nWe can also handle reverse by checking the dot product of the new heading (the direction the car is facing) with the velocity.\nfunc calculate_steering(delta): var rear_wheel = transform.origin + transform.basis.z * wheel_base / 2.0 var front_wheel = transform.origin - transform.basis.z * wheel_base / 2.0 rear_wheel += velocity * delta front_wheel += velocity.rotated(transform.basis.y, steer_angle) * delta var new_heading = rear_wheel.direction_to(front_wheel) 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) look_at(transform.origin + new_heading, transform.basis.y) Finally, we’ll have a function to “decide” how the car is controlled. We’ll override this in the individual cars - with key/gamepad input for player-controlled cars, and with AI decision-making in computer-controlled ones.\nfunc get_input(): # Override this in inherited scripts for controls pass Player controls Now we’re ready to add some player controls. Here’s the InputMap setup:\nIf you have a gamepad with an analog stick, it’s highly recommended you use it. With keyboard controls, which can only be pressed or not, you can only turn the “steering wheel” to the maximum value. An analog stick allows for a much better experience. We’ll make sure the code works with both.\nHere’s the script to attach to the car CharacterBody3D:\nextends \"res://cars/car_base.gd\" func get_input(): var turn = Input.get_action_strength(\"steer_left\") turn -= Input.get_action_strength(\"steer_right\") steer_angle = turn * deg2rad(steering_limit) $tmpParent/sedanSports/wheel_frontRight.rotation.y = steer_angle*2 $tmpParent/sedanSports/wheel_frontLeft.rotation.y = steer_angle*2 acceleration = Vector3.ZERO if Input.is_action_pressed(\"accelerate\"): acceleration = -transform.basis.z * engine_power if Input.is_action_pressed(\"brake\"): acceleration = -transform.basis.z * braking First, we get the input action for steering, which results in a value between -1 and 1. Then we convert that to an angle in radians based on the maximum allowed angle.\nThe next step rotates the wheel meshes to give some visual feedback of the steering. Note that we’re multiplying it by 2 to make it more exaggerated, since you’ll typically be looking at the car from some distance.\nAfter steering, we check the accelerate/brake inputs to set the car’s acceleration.\nWrapping up That’s the bare-bones car controller. Feel free to use this as a starter for your game. If you’re looking to add more, here are some of the topics we’ll address in follow-up recipes:\nTraction and drifting Chase camera and camera control AI/NPC control (steering, obstacle avoidance, track following) Slopes and ramps Note Download the project file here: https://github.com/kidscancode/3d_car_tutorial/releases\nRelated recipes 2D: Car Steering recipe Input Actions 3D: CharacterBody3D Movement Like video? ","description":"","tags":null,"title":"3D Kinematic Car: Base","uri":"/godot_recipes/4.x/3d/kinematic_car/car_base/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 player = AudioStreamPlayer.new() add_child(player) available.append(player) player.finished.connect(_on_stream_finished.bind(player)) player.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 “AudioManager”.\nAnywhere in your project that you want to play a sound, use:\nAudioManager.play(\"res://path/to/sound\") Remember, you can drag sound files directly into the text editor to paste the file path.\nNote 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 lerp() methods for this.\nFor example, to find a vector that’s halfway between a Node3D node’s forward and left direction vectors:\nvar forward = -transform.basis.z var left = transform.basis.x var forward_left = forward.lerp(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.lerp(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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to display some text on the screen.\nSolution Sooner or later you’re going to need to display some text on your screen. Examples include a title, countdown timer, score counter, and many others. For the majority of these, Godot’s Label node is the answer.\nWorking with fonts Before you can start, you’re going to need a font. We’ll go into the full details of Godot’s font support in a separate recipe, but for our purposes, let’s assume you have a TTF or OTF font file. For using bitmap fonts, see the associated recipe.\nNote For this example, we’ll use “Roboto” - a popular free font, which you can find on Google Fonts. You can also download here: Roboto_font.zip\nAdding a Label Add a new Label node to your scene. In the Inspector, you’ll see the node’s properties, most of which are self-explanatory (hover them with the mouse to see a description):\nGo ahead and add something in the Text field and experiment with how it looks. You’ll notice there is a default font, but it’s very plain (and small).\nAdding a DynamicFont To add your font in the Inspector, scroll down to and expand the Custom Fonts section. In the empty Font property, choose “New DynamicFont” and then click the new DynamicFont to expand it.\nDrag your font file (in this example we’re using Roboto-Medium.ttf) into the Font Data property (or choose “Load” and navigate to the file). There are several properties to adjust but for now let’s make Size a bit bigger.\nFeel free to tinker with how the others affect the text appearance. For example, in the picture below, the second label has the Filter property enabled:\nAdjusting color You can adjust the label’s font color in the Custom Colors section. Here you can change Font Color as well as add a shadow color. Shadow properties are set in the Custom Constants section.\nDynamically changing text If all you need in your scene is static text, then you’re done. However, if you need to update the label dynamically, you can do so in code by using the text property.\nFor example, if we had a Timer node in our scene, we could do the following:\nextends Control var counter = 0 func _ready(): $Label.text = str(counter) func _on_Timer_timeout(): counter += 1 $Label.text = str(counter) See the “related recipes” section for more examples of using labels and working with UI nodes.\nRelated recipes Like video? ","description":"","tags":null,"title":"Labels","uri":"/godot_recipes/4.x/ui/labels/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nWhere to start? Depending on the game, and how fleshed-out your idea is, the answer might be very different. In our case, I’ve cheated a little bit by making a prototype of the game already and working out a few of the ideas ahead of time. Still, it diverged a bit from my initial idea, and so might this series - time will tell.\nIn a bigger project, you might start with design document, which could be as simple as a page of notes or as complex as a 500-page treatise laying out every detail of your game’s world, plot, and mechanics. We’ve no need of anything so involved here, so let’s just go over the gameplan.\nGameplan In this game, the player controls a “character” that jumps from circle to circle. Jumping is initiated by a click or touch, and if you don’t hit another circle, you lose. The score is related to how long you survive, and the difficulty will increase over time with circles that move, shrink, and/or expire. The idea is fast-paced, short games with a “top that” feel. As much as possible, the art will remain simple and clean, with visual and audio effects to add appeal.\nNote We’ll be using GLES 3 to start. It’s not yet clear what if any impact this will have. Once we get to the mobile testing phase, we’ll see if a switch to GLES 2 is warranted.\nYou can also follow this project on Github.\nGetting started Let’s start with the project settings. We need to define our screen size/ behavior. We want this to be a mobile game so it’s going to need to be portrait mode and able to adjust to variable screen sizes, since there are so many phone resolutions available.\nOpen Project Settings and find the Display/Window section. Set the screen size to (480, 854), the Handheld/Orientation to “Portrait”, the Stretch/Mode to “2d”, and the Stretch/Aspect to “Keep”.\nNext, in Input Devices/Pointing enable “Emulate Touch From Mouse”. This will let us write the code only using screen touch events, but still play by using the mouse on PC platforms.\nProject organization To keep things organized, we’re going to make a folder to hold the game objects (objects) and one for UI (gui). The game assets (images, audio, etc.) will go in an assets folder. You can download the starting assets here:\nNote Download the project file here: circle_jump_assets.zip\nOnce we have the folders and the assets set up, we’re ready to start coding!\nGame Objects We have two game objects to make: the player (“jumper”) and the circle.\nJumper For movement and collision, we’re going to use a Area2D. To be fair, we could use CharacterBody2D here too, and it would work just as well. However, we don’t really need collision in this game, we just need to know when the jumper contacts a circle. Let’s add the following nodes:\nArea2D (“Jumper”) Sprite CollisionPolygon2D VisibilityNotifier2D Save the scene in res://objects/ and drag the circle image (res://assets/images/jumper.png) into the Sprite’s Texture. Note that all the game images are flat white. This will make it easier for us to dynamically color them later.\nSince the art is drawn pointing upwards, set the Sprite’s Rotation property to 90.\nSelect the CollisionPolygon2D and add three points to cover the jumper’s triangular shape.\nNow let’s add a script to the body and start coding its behavior:\nFirst, the signals and variables:\nextends Area2D var velocity = Vector2(100, 0) # start value for testing var jump_speed = 1000 var target = null # if we're on a circle Next we’ll detect the screen touch and, if we’re on a circle, call our jump method:\nfunc _unhandled_input(event): if target and event is InputEventScreenTouch and event.pressed: jump() Jumping means leaving a circle and traveling forward at our jump speed:\nfunc jump(): target = null velocity = transform.x * jump_speed We’ll detect hitting a circle with the area_entered signal, so connect it. If we hit a circle, we’ll stop moving forward.\nfunc _on_Jumper_area_entered(area): target = area velocity = Vector2() If we are captured by a circle, we want to rotate around it. We’ll add a pivot on the circle, and match its transform so our orientation will always be facing outwards. Otherwise we move forward in a straight line.\nfunc _physics_process(delta): if target: transform = target.orbit_position.global_transform else: position += velocity * delta Color Shader Tip See the Shaders section for help getting started using shaders.\nWe’re going to use a small shader to the Sprite so that we can customize its color. Select the Sprite and then in the Material property add a new ShaderMaterial. Click on that, and in Shader select “New Shader”, then click on that. The shader editor panel will open at the bottom.\nHere is the code for our color shader. It uses a uniform variable for the color, which allows us to choose a value from the Inspector or from our game script. Then it changes all the visible pixels of the texture into that color, preserving the alpha (transparency) value.\nshader_type canvas_item; uniform vec4 color : hint_color; void fragment() { COLOR.rgb = color.rgb; COLOR.a = texture(TEXTURE, UV).a; } You’ll now see a Shader Params section in the Inspector where you can set a color value:\nWe’ll want to use this same shader elsewhere, so in the Shader property, choose “Save” and save this as res://objects/color.shader.\nCircle The second game object is the circle, which will be instanced many times as the game progresses. Eventually, we’ll add a variety of behaviors such as moving, shrinking, etc., but for this first iteration, we just want it to capture the player.\nHere’s the starting node setup:\nArea2D (“Circle”) Sprite CollisionShape2D Node2D (“Pivot”) Marker2D (“OrbitPosition”) The “Pivot” node is how we’ll make the player orbit the circle. The “OrbitPosition” will be offset by whatever the size of the circle is, and the player will follow it.\nUse res://assets/images/circle1_n.png as the Sprite’s texture. While we’re here, add a ShaderMaterial and choose “Load” to use the saved color.shader we made earlier.\nAdd a circle shape to the CollisionShape2D and attach a script to the root node.\nextends Area2D @onready var orbit_position = $Pivot/OrbitPosition var radius = 100 var rotation_speed = PI func _ready(): init() func init(_radius=radius): radius = _radius $CollisionShape2D.shape = $CollisionShape2D.shape.duplicate() $CollisionShape2D.shape.radius = radius var img_size = $Sprite.texture.get_size().x / 2 $Sprite.scale = Vector2(1, 1) * radius / img_size orbit_position.position.x = radius + 25 func _process(delta): $Pivot.rotation += rotation_speed * delta In the init() function, we’re setting up the size of the circle, based on the given radius. We need to size the collision shape as well as scaling the texture to match.\nTry running the scene with different values of radius to test. (Later we’ll stop calling init() in _ready()).\nMain Scene Now we can test out the interaction.\nCreate a “Main” scene using a Node2D and instance both the Jumper and the Circle in it. Arrange them so the jumper will hit the Circle (Jumper’s default velocity is (100, 0)).\nTry running. You should see the jumper get captured by the circle and start orbiting it. Clicking the mouse should then send the jumper flying off in whatever direction it’s pointing.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nLike video? ","description":"","tags":null,"title":"Project setup","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_01/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to get started coding shaders.\nSolution A shader is a special program that runs on the computer’s GPU (graphics card). The GPU is optimized to perform certain types of math very efficiently. Shader code can be attached to objects to affect how they’re rendered on the screen.\nThe output of a shader program is the color of the set of pixels of the object. Shaders can be used in 2d (canvas_item shaders) and 3D (spatial shaders).\nThe most difficult part for newcomers to understand about shaders is that they run in parallel. A shader runs simultaneously on all pixels. This allows for great speed, but also limits what information you have access to in the shader.\nTo add a shader to an object, find its Material property and select “New ShaderMaterial”. Click the new material to open it, and select “New Shader”. Click that, and you’ll see a shader editor open at the bottom of the screen.\nThe first line of the shader must specify its type. If the node it’s attached to is a 2D node:\nshader_type canvas_item; Or for a 3D node:\nshader_type spatial; For these first examples, let’s stick to 2D. Add a Sprite node and add shader following the steps above. You can use the Godot icon for its texture.\nThere are two basic types of shader we’ll discuss here: vertex and fragment.\nFragment shader Fragment shaders calculate the color of the pixel. Let’s look at an example:\nvoid fragment() { COLOR = vec4(1.0, 0.0, 0.0, 1.0); } Every pixel is red. COLOR is the output of the fragment shader and is applied to every pixel simultaneously. But what if we want some variation?\nUV coordinates In shaders, the pixel coordinates are specified in UV notation. These are normalized values ranging from (0, 0) (top-left) to (1, 1) (bottom-right).\nNote Shaders use vectors (vec4) to represent RGBA colors. Individual compenents can be accessed using e.g. color.r. Treating colors as vectors allows for a variety of interesting effects based on vector math.\nvoid fragment() { COLOR = vec4(UV.x, 0.0, 0.0, 1.0); } Now the red channel ranges from 0 on the left to 1.0 on the right, varying along with the UV.\nAnother example:\nvoid fragment() { COLOR = vec4(UV.x, 1.0 - UV.y, 0.5, 1.0); Textures Notice that since we’re setting the pixel color directly, we’ve thrown away the Godot icon’s data. You can access that texture data using the TEXTURE input and texture() function:\nvoid fragment() { COLOR = texture(TEXTURE, UV); } Now we’re back to the original image. Each pixel’s color is being set to the color value of the texture at the same UV position.\nIt’s also possible to change only one channel of the COLOR output:\nvoid fragment() { COLOR = texture(TEXTURE, UV); COLOR.a = 1.0 - UV.x; } This ramps the alpha channel down, resulting in a fade-out effect.\nVarying with time Another useful built-in shader property is TIME, which gives an ever-increasing value representing the current elapsed time. If we also use the sin() function, which returns a value between -1 and 1, we can produce this effect:\nvoid fragment() { COLOR = texture(TEXTURE, UV); COLOR.a = abs(sin(TIME * 0.5)); } Or this one:\nvoid fragment() { COLOR = texture(TEXTURE, UV); COLOR.a = max(0.0, UV.x - abs(sin(TIME))); } Vertex shader Vertex shaders alter the vertices of the object, allowing for deformations and scaling. Just as fragment shaders run on every pixel, vertex shaders run on every vertex of an object. In a canvas_item shader, this typically means the four corners of the texture. In a spatial shader, it’s each vertex of the mesh.\nFor example, observe what happens with the following:\nvoid vertex() { VERTEX.x += UV.x * 10.0; } In this shader, the two left vertices (0, 0) and (0, 1) are unchanged, but the right vertices become (10, 0) and (10, 1).\nVarying the vertex positions over time can produce a variety of interesting effects:\nvoid vertex() { VERTEX.y += sin(UV.x * TIME) * 10.0; } Uniforms To pass a value to the shader, you need a variable declared with the uniform keyword. Once you do this, the variable appears in the Inspector in much the same way an export variable. However, a uniform’s value can not be changed in the shader!\nUniform values are global to the shader and can be accessed from any function.\nHints You can also use optional hints to assist in setting the value in the Inspector.\nuniform float radius : hint_range(0, 1); Hints are available for a variety of data types. See the Shader Language Reference for a full list.\nWrapping up This is just a tiny introduction to what’s possible with shaders. See the rest of the recipes in this section for more examples you can use in your projects.\nRelated Recipes ","description":"","tags":null,"title":"Shaders: intro","uri":"/godot_recipes/4.x/shaders/intro/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nIntroduction In this demo, we’ll consider a local multiplayer game - a topdown-style maze game with two players (one using arrow keys and the other using WASD controls). This is not a problem if our game world all fits on one screen, but if the map is large, we’ll want to have a “split screen” view tracking the two players separately.\nWe’ll also look at a quick way to set up a minimap display.\nGame setup We won’t spend a lot of time on the setup of the game world. The two players are CharacterBody2D objects using no-frills 8-way movement.\nNote If you need help setting up this part, see the following section in the official Godot docs: 2D Movement Overview.\nEach player has its input actions set up in the Project Settings -\u003e Input Map section: “right_1” to Right Arrow, “right_2” to D, etc. Note that by naming them this way, we can save time in the code by using:\n@export var id = 0 func get_input(): velocity = Vector2() if Input.is_action_pressed('right_%s' % id): velocity.x += 1 # etc. This way both characters can use the same script for movement. Just assign the appropriate value to id for each player.\nThe two players are added to a “World” scene containing a TileMap:\nIf you like, you can download the starting project, with the world already set up, here:\nsplitscreen_start.zip\nNote that the map is much larger than the game screen, but aside from that everything works as intended. Setting up your game “world” separately like this will make setting up the viewports much easier and more flexible.\nViewports, Cameras, and Worlds We’re going to start with a new scene that’s going to contain our two viewports. Create a node to serve as the root. I like to use Node since it has no properties of its own - it’s just there to contain the rest of the scene.\nBy themselves, Viewport nodes don’t have position information (they don’t inherit from Node3D or Node2D). We’re going to use ViewportContainer, a Control node, to hold each viewport. To keep them arranged side-by-side, we’ll use an HBoxContainer.\nSet the HBoxContainer’s Alignment to “Center” and to have a small gap between the two viewports, set Custom Constants/Separation to 5. In the “Layout” menu, choose “Full Rect”.\nNow add two ViewportContainers as children, naming them with a 2 and 1 (to match the player they’ll display). Set the Size Flags on both to “Fill, Expand” so that they will each expand to fill half of the screen. Also, check the Stretch property so that the Viewport will automatically be set to the size of the container.\nInside each of these containers add a Viewport. Note that if you set the viewport’s Size property, it will be reset by the container.\nIn order for a Viewport to display anything, we’ll need a Camera2D which will render onto the Viewport. Add one to each viewport. Don’t forget to check the Current property to activate the camera. We can also set each camera’s Zoom to (0.75, 0.75) to get a better view of the area around the player.\nYour node setup should look like this:\n┖╴Main (Node) ┖╴Viewports (HBoxContainer) ┠╴ViewportContainer2 ┃ ┖╴Viewport2 ┃ ┖╴Camera2D ┖╴ViewportContainer1 ┖╴Viewport1 ┖╴Camera2D Note Note that we’ve put ViewportContainer1 second in the HBoxContainer. This will place it on the right side since Player 1 uses the arrow keys.\nAdding the World When we run the scene we won’t see anything because the viewports don’t have any “world” to render. A viewport’s world (for 3D) or world_2d property represent the source for the viewport’s environment and determine what will be rendered by its camera. The world can be set in code, but for 2D it will also display any child 2D nodes we add to it.\nLet’s instance the “World” scene as a child of Viewport1. Now when we play the scene we see the world inside the left viewport.\nWe also need to add a world to Viewport2, but we want it to use the same one. We can handle this in code. Attach a script to Main and add the following:\nextends Node @onready var viewport1 = $Viewports/ViewportContainer1/Viewport1 @onready var viewport2 = $Viewports/ViewportContainer2/Viewport2 @onready var camera1 = $Viewports/ViewportContainer1/Viewport1/Camera2D @onready var camera2 = $Viewports/ViewportContainer2/Viewport2/Camera2D @onready var world = $Viewports/ViewportContainer1/Viewport1/World func _ready(): viewport2.world_2d = viewport1.world_2d The onready node references are for convenience - we’ll be using them as we move forward. Remember that when you type “$” Godot will autosuggest node paths so you don’t have to type them. You can also drag a node from the scene tree into the script editor and you’ll get the node’s path.\nWhen we run the scene now, we see the world rendered in both viewports. However, neither camera is moving so we only see a small part of the world.\nSetting up the cameras Attach the following script to each camera:\nextends Camera2D var target = null func _physics_process(delta): if target: position = target.position Now we can assign a target to each camera and it will follow that node’s position. We’ll do that in the Main script:\nfunc _ready(): viewport2.world_2d = viewport1.world_2d camera1.target = world.get_node(\"Player_1\") camera2.target = world.get_node(\"Player_2\") When we run the scene now, each player is centered in its viewport and our splitscreen setup works!\nTip I find it looks best if you disable the Drag Margin properties of the cameras.\nCamera limits Next, let’s add some limits to the player cameras so that they don’t scroll outside the bounds of the map. Add this function to the main script and call it in _ready():\nfunc set_camera_limits(): var map_limits = world.get_used_rect() var map_cellsize = world.cell_size for cam in [camera1, camera2]: cam.limit_left = map_limits.position.x * map_cellsize.x cam.limit_right = map_limits.end.x * map_cellsize.x cam.limit_top = map_limits.position.y * map_cellsize.y cam.limit_bottom = map_limits.end.y * map_cellsize.y Minimap Let’s add one more fun feature: a minimap showing a zoomed-out view of the entire map so the players can orient themselves.\nWe’ll need another ViewportContainer, this one a child of Main. This time, we don’t want to use Stretch. Add a Viewport and set its Size to (340, 200) then add a Camera2D. We’ll set the Camera2D’s Position to (512, 300) to center it on the screen. We’ll zoom out by setting Zoom to (9, 9). Don’t forget to click Current on this camera as well.\nIn the _ready(), set the minimap to use the same world as the other two viewports:\n$Minimap/Viewport.world_2d = viewport1.world_2d Use the “Layout” menu to align the Minimap container at “Center Bottom”. Let’s see what it looks like:\nWe need to get rid of that grey area around the edges. We could find the precise zoom level that matches our desired minimap size, but instead, we’ll check the Transparent Bg on the Viewport. Now our non-map areas aren’t visible and the minimap appears floating directly on top of the main viewports.\nConclusion Viewports can be very powerful, but also confusing. One way of managing them is to try to keep them separate from the game logic and only use them as displays.\n","description":"","tags":null,"title":"Splitscreen multiplayer","uri":"/godot_recipes/4.x/2d/splitscreen_demo/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 Node2D, 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 have a CharacterBody2D character colliding with a TileMap, and you want to know which tile it collided with.\nSolution When a CharacterBody2D collides, the collision data is returned in a KinematicCollision2D object. The TileMap acts as a single collider, so if you reference the collider property, it will be the TileMap node.\nYou then need to find out which tile in the TileMap is at the collision location.\nAssume you’ve obtained a KinematicCollision2D object stored in the variable collision:\n# Confirm the colliding body is a TileMap if collision.collider is TileMap: # Find the character's position in tile coordinates var tile_pos = collision.collider.world_to_map(position) # Find the colliding tile position tile_pos -= collision.normal # Get the tile id var tile_id = collision.collider.get_cellv(tile_pos) Once you have the tile_id, you can get the tile properties from the TileSet resource, found in the TileMap’s tile_set property. For example, to get the name of the tile:\nvar tile_name = collision.collider.tile_set.tile_get_name(tile_id) You can also change the tile by setting it to a new id:\ncollision.collider.set_cellv(tile_pos, new_id) Related recipes TileMap: using autotile TileMap: animated tiles Like video? ","description":"","tags":null,"title":"TileMap: detecting tiles","uri":"/godot_recipes/4.x/2d/tilemap_collision/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’ve got a kinematic car, but you don’t like the “on rails” feeling, especially at high speeds. You’d like to have some “slip” so that you can have drifting and loss of traction.\nSolution When the car is drifting, the heading of the car (the direction it’s pointing) may not be the same as its velocity (the direction it’s moving). Turning the wheel will make the car turn, but the velocity will not instantly “catch up” - instead, we’ll use lerp() (linear interpolation) to gradually move the velocity to the desired direction.\nAdd the following new variables to car_base.gd:\n@export var slip_speed = 9.0 @export var traction_slow = 0.75 @export var traction_fast = 0.02 var drifting = false slip_speed is how fast the car needs to be going before losing traction. You’ll need to adjust this based on the car’s other parameters.\ntraction_slow and traction_fast represent the traction when below or above the slip_speed, ranging from 0 - 1. Smaller numbers mean the car will feel more “slippery”. Setting them to 1 will be “on rails” with no sliding at all.\ndrifting is a boolean variable to keep track of the drifting state.\nNext, add this code to the calculate_steering() function in car_base.gd, right after calculating the new_heading:\n# traction if not drifting and velocity.length() \u003e slip_speed: drifting = true if drifting and velocity.length() \u003c slip_speed and steer_angle == 0: drifting = false var traction = traction_fast if drifting else traction_slow This code sets the drifting state as appropriate, and then selects which traction value to use.\nThe last piece of the puzzle is to interpolate the velocity to the new heading. Change this line:\nvelocity = new_heading * velocity.length() to this:\nvelocity = lerp(velocity, new_heading * velocity.length(), traction) Wrapping up At this point, we have a large number of parameters to adjust, giving us a very wide range of behavior for the car. Depending on the style of driving you’re going for, your number might be very different from the ones used here.\nIf you’re looking to add more, here are some of the topics we’ll address in follow-up recipes:\nChase camera and camera control AI/NPC control (steering, obstacle avoidance, track following) Slopes and ramps Related recipes Kinematic Car: Base 2D: Car Steering recipe Input Actions 3D: CharacterBody3D Movement Like video? ","description":"","tags":null,"title":"3D Kinematic Car: Traction/Drifting","uri":"/godot_recipes/4.x/3d/kinematic_car/car_traction/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 Circular movement Using Custom Resources ","description":"","tags":null,"title":"Basics","uri":"/godot_recipes/4.x/basics/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem Your UI has problem(s): it’s become overcomplicated, it doesn’t resize well, and/or you can’t keep track of how everything fits together.\nSolution For many developers, building a UI is their least favorite part. It’s very easy for a complex UI to spiral out of control and become impossibly painful to fix or modify. Godot provides some great tools for building UI - and if you take the time to learn to use them, you’ll find that they take away a lot of that pain.\nThe solution is the Container. Containers provide a lot of power in building your UI’s layout.\nWhen a Control node is added to a Container, the container takes over all the control’s positioning information. You can no longer set the size, position, or other layout properties of the container’s children.\nThis is the key thing to remember about containers:\nWarning A Container node automatically arranges its children. You cannot directly control the position of a child UI node.\nLet’s look at some of the most commonly used containers:\nCenterContainer\nThis container places keeps its children centered.\nMarginContainer\nThis container maintains a margin, preventing children from getting too close to the edges of the container. Margin values can be set in the “Custom Constants” section of the properties.\nVBoxContainer/ HboxContainer\nThese containers keep their contents aligned vertically or horizontally, respectively. In the “Custom Constants” section you can also set a Separation property to increase spacing between elements.\nGridContainer\nThis container arranges its children in a grid pattern.\nSize flags The way a container handles its children is mainly controlled by their “Size Flags” properties.\nFill\nWhen this option is checked, the control fills its assigned location in the container. This option is enabled by default.\nExpand\nIf this option is checked, the control tries to use as much space as it can. Nodes without Expand selected are pushed by those that do.\nShrink Center\nWhen Fill is disabled and Expand is enabled, the control remains at the center of its area, rather than the beginning.\nShrink End\nSame as above, except the control stays to the end rather than the beginning.\nStretch Ratio\nThis ratio sets the amount that expanding controls take up relative to each other.\nA good way to experiment with these settings is to set up a test scene like the following:\nTry adjusting the “Size Flags” properties of the different buttons and see how it affects their positioning in the HBoxContainer.\nNesting Containers For more complex UI setups, you’ll need to use containers holding other containers. Each item in a GridContainer, for example, may itself be a VBoxContainer, with all of it inside a MarginContainer.\nAll these containers inside containers can cause your scene tree to become quite large and hard to manage, especially if you have a lot of repeated elements, such as buttons and labels. It’s recommended that you break your UI into pieces and save each part as a separate scene that you can instance in the larger scene.\nRelated recipes Labels ","description":"","tags":null,"title":"Containers","uri":"/godot_recipes/4.x/ui/containers/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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.\n@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.\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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to interact with a Godot shader from GDScript.\nSolution To access the uniform’s value from GDScript, you can use set_shader_param() on the object’s material property. If the attached material is a ShaderMaterial, then you can access it like so:\nnode.material.set_shader_param(\"param_name\", value) You can also get the value with get_shader_param().\nFor an example of this, see the Blur Shader recipe.\nRelated Recipes Shaders: Intro ","description":"","tags":null,"title":"Interacting with Shaders","uri":"/godot_recipes/4.x/shaders/interacting/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: Label Path2D \u0026 PathFollow2D 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.\nA better way The downsides of this approach are that you have to specify the node path, and if that changes later, you’ll have to edit the code as well. Instead, you can use the @export feature to directly select a node.\nextends CharacterBody2D @export var animation : AnimatedSprite2D func _process(delta): if speed \u003e 0: animation.play(\"run\") else: animation.play(\"idle\") With this method, you can assign the value of the variable directly in the Inspector by choosing the node.\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:\n@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:\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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want a character to follow a pre-defined path, such as a guard patrolling or a car following the road.\nSolution There are many ways to approach this problem. In this solution, we’ll use Godot’s Path2D node (or Path for 3D) as a convenient way to draw paths in the editor.\nYou can add the Path2D as a child of your main scene, your map, or another location that makes sense. Don’t make it a child of the patrolling entity, though - or the path will move along with the player!\nDrawing the path After adding the Path2D node, you’ll see some new buttons appear above the viewport:\nSelect the “Add points” button and click to start adding. If you want a closed curve, the “Close curve” button will connect the last point to the first one.\nUse the “Control points” mode to adjust the “curviness” of the line.\nMoving along the path You can use PathFollow2D to automatically move along a path. However, if you’re using a kinematic body, this will cause problems with collisions, because you’re not using the body’s movement methods. For this reason, we’ll instead use the path’s points as “targets” for the body to move towards.\nextends CharacterBody2D var move_speed = 100 @export var patrol_path: NodePath var patrol_points var patrol_index = 0 var velocity = Vector2.ZERO func _ready(): if patrol_path: patrol_points = get_node(patrol_path).curve.get_baked_points() Exporting the patrol_path lets us assign the path node directly in the Inspector. Then, if it’s assigned, we can get the points that make up the line in _ready().\nNext, we can use the currently selected point in the path as our target for movement. If we get close enough to it, we advance to the next point in the curve, using wrapi() to loop around to the first point when we reach the end.\nfunc _physics_process(): if !patrol_path: return var target = patrol_points[patrol_index] if position.distance_to(target) \u003c 1: patrol_index = wrapi(patrol_index + 1, 0, patrol_points.size()) target = patrol_points[patrol_index] velocity = (target - position).normalized() * move_speed velocity = move_and_slide(velocity) Related recipes ","description":"","tags":null,"title":"Path following","uri":"/godot_recipes/4.x/ai/path_follow/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 RigidBody2D: Move to Target ","description":"","tags":null,"title":"RigidBody2D: Look at Target","uri":"/godot_recipes/4.x/physics/smooth_rigid_rotate/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nIn the previous part, we created the Jumper and Circle object that make up the bulk of the game. Now we need to add the progression: a continuous series of spawned circles as long as the player doesn’t miss.\nExpanding the Main scene Let’s add some more nodes to Main:\nMarker2D (“StartPosition”)\nThis will mark the starting position for the game. Place it near the bottom-center of the screen.\nCamera2D\nThe camera will follow the player as it moves.\nLet’s also configure the camera. Set its Offset to (0, -200) - this will ensure we can see more of the world ahead of us. Also set Current to “On”.\nScripting the Main scene Remove the jumper and circle instances we manually created. We’ll add them in code moving forward.\nAdd the following to Jumper.gd:\nsignal captured We’ll emit this signal when the jumper hits a circle:\nfunc _on_Jumper_area_entered(area): target = area velocity = Vector2.ZERO emit_signal(\"captured\", area) And let’s change the init() function on the circle to also accept a position:\nfunc init(_position, _radius=radius): position = _position Now let’s add a script to the Main scene:\nextends Node var Circle = preload(\"res://objects/Circle.tscn\") var Jumper = preload(\"res://objects/Jumper.tscn\") var player We need references to both objects so that we can instance them when needed.\nfunc _ready(): randomize() new_game() This is temporary - later we’ll have a UI with a start button to call the new game function.\nfunc new_game(): $Camera2D.position = $StartPosition.position player = Jumper.instantiate() player.position = $StartPosition.position add_child(player) player.connect(\"captured\", self, \"_on_Jumper_captured\") spawn_circle($StartPosition.position) The new_game() function initializes the game - spawning a player and a circle at the start position, and setting the camera.\nfunc spawn_circle(_position=null): var c = Circle.instantiate() if !_position: var x = rand_range(-150, 150) var y = rand_range(-500, -400) c.position = player.target.position + Vector2(x, y) add_child(c) c.init(_position) Here’s our spawn_circle() function. If it’s passed a position, it’ll use it, otherwise we pick a random one some distance away from the current target. These are temporary numbers - once we’ve got more of the gameplay up and running, we’ll see how much they need to be adjusted.\nfunc _on_Jumper_captured(object): $Camera2D.position = object.position call_deferred(\"spawn_circle\") Finally, we need the function that processes the jumper’s captured signal. We’re going to move the camera to the new circle and spawn another. Note that because this function is called during physics processing, we’ll get an error if we try and add to the scene tree. Using call_deferred() tells the engine to execute that function as soon as it’s safe to do so.\nTry it out. You should be able to jump from circle to circle - how many did you get?\nOne jarring thing is that the camera “teleports” when it moves to the next circle. We can improve this by enabling Smoothing on the camera. The Smoothing/Speed controls how quickly the camera interpolates to the new position. Try something between 5 and 10.\nAdjustments It’s also jarring that when we hit a circle we don’t start rotating at the place we hit. Add this to the jumper’s _on_Jumper_area_entered() function:\ntarget.get_node(\"Pivot\").rotation = (position - target.position).angle() Let’s also add this to the circle’s init():\nrotation_speed *= pow(-1, randi() % 2) This randomly flips the rotation speed to positive or negative, so we won’t always orbit in the same direction.\nTrail Add these nodes to the jumper:\nNode (“Trail”) Line2D (“Points”) We’re going to use this to make a trail that streams out behind the player. Later we’ll make it more visually appealing, but for now, let’s stick with a simple gradient. In the Fill add a new Gradient, and go from transparent to a color of your choosing:\nNow in the jumper’s script, let’s add the following:\n@onready var trail = $Trail/Points var trail_length = 25 And then in the _physics_process():\nif trail.points.size() \u003e trail_length: trail.remove_point(0) trail.add_point(position) IMAGE/GIF\nCircle animations Finally, we’ll add some visuals to the circles. First, we’ll add an effect when the player jumps off and the circle disappears. Then, we’ll add a capture effect for when we hit a circle.\nAdd an AnimationPlayer node to the Circle.\n“Implode” animation Add a new animation called “implode”. Set the length to 0.4 and keyframe two properties of the root Area2D node: Scale at (1, 1) and Modulate at its default ((1, 1, 1, 1)). Then move the scrubber all the way to the end and key the values (0.1, 0.1) and (1, 1, 1, 0) (that’s the “alpha” value of the color).\nCapture animation The capture animation is a little more complex. Duplicate the Sprite and call it SpriteEffect. Set its Visible property off. We’re going to animate this second ring zooming in on the main circle.\nHere are the functions to add to the circle script:\nfunc capture(): $AnimationPlayer.play(\"capture\") func implode(): if !$AnimationPlayer.is_playing(): $AnimationPlayer.play(\"implode\") await $AnimationPlayer.animation_finished queue_free() And then in Jumper.gd, our jump function becomes:\nfunc jump(): target.implode() target = null velocity = transform.x * jump_speed And in Main, our capture method calls the capture:\nfunc _on_Jumper_captured(object): $Camera2D.position = object.position object.capture() call_deferred(\"spawn_circle\") GIF\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Spawning Circles","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_02/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 Node3D 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 Splitscreen multiplayer TileMap: detecting tiles Top-down movement Grid-based movement Shooting projectiles Car steering 8-Directional Movement/Animation TileMap: using autotile Using Y-Sort Coyote Time Moving Platforms Pathfinding on a 2D Grid TileMap: animated tiles Multitarget Camera Ballistic bullet Line2D Collision Touchscreen Camera Draw trajectory ","description":"","tags":null,"title":"2D","uri":"/godot_recipes/4.x/2d/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want a “chase camera” that can follow your car (or any other object).\nSolution Note Godot has a built-in InterpolatedCamera node that does most of what’s described here. However, we’re not going to use it for two reasons: first, it has a tendency to stutter when following kinematic bodies, and second, it’s getting removed in Godot 4.0. Setting up our own is really easy though, so don’t worry. Setting up the camera Add a new scene with a Camera. Name it ChaseCamera, save it, and add a script.\nThe ChaseCamera will have a target - the thing it’s following. We’re also going to include the ability to change that target.\nextends Camera @export var lerp_speed = 10.0 var target = null func _physics_process(delta): if !target: return global_transform = global_transform.interpolate_with(target.global_transform, lerp_speed * delta) func _on_change_camera(t): target = t The only parameter to set here is the lerp_speed, which controls how quickly the camera updates its position. Set it low, and the camera will “lag” behind the car. Set it high, and it will remain locked on.\nSetting up the target(s) We want to be able to have a few different chase camera positions. One close and one far, for example, or perhaps one looking straight down. Add a Node3D to the car and name it CameraPositions. Add a few Marker3Ds to this - as many as you would like.\nMove and orient each Marker3D in a different location of your choosing. The position’s -Z axis should point at the car.\nTip You may find it helpful to temporarily attach a Camera to the position and use its “Preview” mode to help aim the Marker3D so that it’s pointing directly where you want (you can remove the camera once you’re done). To communicate to the camera, we’ll emit a signal whenever we want it to change position. Add the following code to the car’s script:\nextends \"res://cars/car_base.gd\" signal change_camera var current_camera = 0 @onready var num_cameras = $CameraPositions.get_child_count() func _ready(): emit_signal(\"change_camera\", $CameraPositions.get_child(current_camera)) func _input(event): if event.is_action_pressed(\"change_camera\"): current_camera = wrapi(current_camera + 1, 0, num_cameras) emit_signal(\"change_camera\", $CameraPositions.get_child(current_camera)) Add an action in the InputMap for changing the camera. Here, we’re using Tab and the right shoulder button:\nConnecting it together Add a ChaseCamera instance to your main scene and set it Current. Then connect the car’s change_camera signal to the camera’s _on_change_camera() function.\nRun the game and press the camera change button to try it out:\nRelated recipes Kinematic Car: Base 2D: Car Steering recipe Input Actions 3D: CharacterBody3D Movement Like video? ","description":"","tags":null,"title":"3D Kinematic Car: Chase Camera","uri":"/godot_recipes/4.x/3d/kinematic_car/car_camera/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem Your CharacterBody3D slides down slopes.\nSolution We’ve started with a no-frills CharacterBody3D, using move_and_slide(), using the script below:\nextends CharacterBody3D @export var gravity = -10.0 @export var speed = 5.0 @export var rot_speed = 4.0 @export var jump_speed = 5.0 var velocity = Vector3.ZERO var jumping = false func get_input(delta): var input = Vector3.ZERO if Input.is_action_pressed(\"forward\"): input += -transform.basis.z * speed if Input.is_action_pressed(\"back\"): input += transform.basis.z * speed if Input.is_action_pressed(\"right\"): rotate_y(-rot_speed * delta) if Input.is_action_pressed(\"left\"): rotate_y(rot_speed * delta) velocity.x = input.x velocity.z = input.z func _physics_process(delta): get_input(delta) velocity.y += gravity * delta move_and_slide() if jumping and is_on_floor(): jumping = false if Input.is_action_just_pressed(\"jump\"): if is_on_floor(): jumping = true velocity.y = jump_speed We see the problem if we stop moving on a slope:\nThis is move_and_slide() doing what it’s supposed to do.\nThe downward velocity caused by gravity is being slid along the surface.\nChecking the move_and_slide() documentation, we see there’s a parameter called stop_on_slope, which defaults to false:\nIf stop_on_slope is true, body will not slide on slopes when you include gravity in linear_velocity and the body is standing still.\nSo we can change our movement to this instead:\nmove_and_slide() Now we stop sliding down slopes!\nBut there is still a problem, which is easier to see if you use a low value for gravity:\nWhen we come to a stop, we have a little bit of upward momentum, which causes the small “hop”. We can solve this by switching to the move_and_slide_with_snap() method.\nIn order to ensure we can still jump, we also need to disable snapping during a jump, or we’ll remain “snapped” to the ground:\nvar snap = Vector3.DOWN if not jumping else Vector3.ZERO move_and_slide() Now the “hop” is gone, and everything works as expected.\nFinally, you may notice that on very steep slopes, you still have a problem:\nThis is because the default value of the floor_max_angle parameter is 45°, and the slope shown is greater. Any angle above this value does not count as a floor. Increasing the value makes this slope behave like the others:\nmove_and_slide() Related recipes Godot 101: Intro do 3D CharacterBody3D: Movement Like video? ","description":"","tags":[],"title":"CharacterBody3D: Stopping on Slopes","uri":"/godot_recipes/4.x/physics/kinematicbody_slopes/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":"Introduction Collision layers and masks are essential for controlling which objects interact with each other in Godot 4.\nThe System Collision Layer: Which layer(s) the object lives on. Collision Mask: Which layer(s) the object scans for collisions. Example Configuration Node Layer Mask Interaction Player 1 2, 3 Scans for Enemies and Coins Enemy 2 1 Scans for the Player Coin 3 (None) Doesn’t need to scan anything Setting Names In Godot 4, you can name your layers in Project Settings \u003e Layer Names \u003e 2D Physics. This makes it much easier to manage in the Inspector.\nAccessing via Code In Godot 4, you can use get_collision_layer_value(layer_number) and set_collision_layer_value(layer_number, value) for easier bit manipulation.\n# Enable layer 2 set_collision_layer_value(2, true) # Check if masking layer 3 if get_collision_mask_value(3): print(\"Scanning layer 3\") [!NOTE] Godot 3 to 4 Migration Summarized:\nThe inspector UI for layers has been improved. New helper methods like set_collision_layer_value() replace the need for complex bitwise math (1 \u003c\u003c (layer - 1)). ","description":"","tags":null,"title":"Collision Layers and Masks","uri":"/godot_recipes/4.x/physics/collision_layers/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want a shader to convert an image to greyscale.\nSolution Let’s start with a canvas_item (2D) shader. To convert to greyscale but also preserve pixel contrast, we need to average the pixel’s color value. Add the color channels together and divide by 3:\nshader_type canvas_item; void fragment() { COLOR = texture(TEXTURE, UV); float avg = (COLOR.r + COLOR.g + COLOR.b) / 3.0; COLOR.rgb = vec3(avg); } You can apply this to the whole screen by adding a ColorRect (placed in a CanvasLayer to ignore camera movement) and scaling it to cover the screen.\nChange the texture() function to sample the screen instead of the object’s pixels:\nCOLOR = texture(SCREEN_TEXTURE, SCREEN_UV); Related Recipes Shaders: Intro ","description":"","tags":null,"title":"Greyscale (monochrome) shader","uri":"/godot_recipes/4.x/shaders/greyscale/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to add friction and acceleration to your kinematic character, giving it a smoother feel.\nSolution For most games, we’re not necessarily interested in a perfect physics simulation. We want action, responsiveness, and arcade feel. This is why you choose a kinematic body over a rigid one: so that you can control its behavior directly. However, some amount of physics is good - it means an object doesn’t instantly change direction or come to a stop.\nBelow is the code for a no-frills kinematic platformer character:\nextends CharacterBody2D var speed = 1200 var jump_speed = -1800 var gravity = 4000 var velocity = Vector2.ZERO func get_input(): velocity.x = 0 if Input.is_action_pressed(\"ui_right\"): velocity.x += speed if Input.is_action_pressed(\"ui_left\"): velocity.x -= speed func _physics_process(delta): get_input() velocity.y += gravity * delta move_and_slide() if Input.is_action_just_pressed(\"ui_select\"): if is_on_floor(): velocity.y = jump_speed If you run this code, you’ll see that the character’s x velocity changes instantaneously. To fix this, we’ll use lerp() to gradually increase/decrease the velocity.\nUsing lerp lerp(start_value, end_value, amount) lerp(), aka linear interpolate, finds a “blended” value between two given numbers. See Interpolation for details.\nIn the code below, friction represents how quickly the character comes to a stop, while acceleration determines how quickly it gets up to full speed. Both are values between 0.0 and 1.0.\nReplace the get_input() code with the following:\nvar friction = 0.1 var acceleration = 0.5 func get_input(): var input_dir = 0 if Input.is_action_pressed(\"ui_right\"): input_dir += 1 if Input.is_action_pressed(\"ui_left\"): input_dir -= 1 if dir != 0: # accelerate when there's input velocity.x = lerp(velocity.x, dir * speed, acceleration) else: # slow down when there's no input velocity.x = lerp(velocity.x, 0, friction) Explanation We’re using friction and acceleration as the amount to blend. For acceleration, we want to find a value between the current speed and the maximum, speed. When decelerating, we’re ramping the current speed down to 0.\nTip Using values of 1.0 would recreate the “instant” movement we started with.\nRelated Recipes Platform Character ","description":"","tags":null,"title":"Kinematic Friction","uri":"/godot_recipes/4.x/physics/kinematic_friction/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nIn the first two parts, we got the basic gameplay working. Now we’re going to start adding some different modes to the circles.\nCircle modes Eventually, we’ll have many different modes, but we’re going to start with the “limited” mode: the circle only allows a given number of orbits before disappearing. First, let’s add a Label node to show the number of remaining orbits. Type a number (1) in the text field so we can see how it looks.\nIn the Custom Fonts section, add a new DynamicFont, load the Font Data from the assets folder, and set the Size to 64. To align the label, in the “Layout” menu, choose “Center”.\nAdd the following new variables at the top of the Circle.gd:\nenum MODES {STATIC, LIMITED} var mode = MODES.STATIC var num_orbits = 3 # Number of orbits until the circle disappears var current_orbits = 0 # Number of orbits the jumper has completed var orbit_start = null # Where the orbits started Next we need a way to set the mode:\nfunc set_mode(_mode): mode = _mode match mode: MODES.STATIC: $Label.hide() MODES.LIMITED: current_orbits = num_orbits $Label.text = str(orbits_left) $Label.show() Right now we have these two modes defined, but later we’ll be adding more.\nLet’s also add to the init() method a way to pass a mode. The default should be STATIC, but we’re going to use LIMITED now so we can test:\nfunc init(_position, _radius=radius, _mode=MODES.LIMITED): set_mode(_mode) The jumper is setting the rotation position when it’s captured. Remove the line from Jumper.gd and put it in the circle’s capture() method:\nfunc capture(target): jumper = target $AnimationPlayer.play(\"capture\") $Pivot.rotation = (jumper.position - position).angle() orbit_start = $Pivot.rotation Note that we’re now sending a reference to the jumper, so add var jumper = null at the top, and in the Main.gd script update the call to read object.capture(player).\nNow we can check to see if the jumper has gone full circle, and if so, decrement current_orbits:\nfunc _process(delta): $Pivot.rotation += rotation_speed * delta if mode == MODES.LIMITED and jumper: check_orbits() func check_orbits(): # Check if the jumper completed a full circle if abs($Pivot.rotation - orbit_start) \u003e 2 * PI: current_orbits -= 1 $Label.text = str(current_orbits) if orbits_left \u003c= 0: jumper.die() jumper = null implode() orbit_start = $Pivot.rotation In order for this to work, we need to add a die() method to the jumper:\nfunc die(): target = null queue_free() func _on_VisibilityNotifier2D_screen_exited(): if !target: die() We’ve also connected the jumper’s VisibilityNotifier2D signal so that we can remove the player when it exits the screen.\nIf we try it out, everything looks good so far:\nCircle effect The last thing we’ll do for this part is add a “fill” effect to the circle to show that the orbits are running out. To begin, we’ll use some drawing code from the official docs:\nfunc draw_circle_arc_poly(center, radius, angle_from, angle_to, color): var nb_points = 32 var points_arc = PoolVector2Array() points_arc.push_back(center) var colors = PoolColorArray([color]) for i in range(nb_points + 1): var angle_point = angle_from + i * (angle_to - angle_from) / nb_points - PI/2 points_arc.push_back(center + Vector2(cos(angle_point), sin(angle_point)) * radius) draw_polygon(points_arc, colors) We’ll call this function in _draw():\nfunc _draw(): if jumper: var r = ((radius - 50) / num_orbits) * (1 + num_orbits - current_orbits) draw_circle_arc_poly(Vector2.ZERO, r, orbit_start + PI/2, $Pivot.rotation + PI/2, Color(1, 0, 0)) Lastly, add update() to the _physics_process so that it will be called after every call to check_orbits().\nIn the next part we’ll start adding some UI.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Limited circles","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_03/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to implement a melee attack, such as a sword or punch.\nSolution For this example, we’ll assume we have already set up a character with one or more attack animations. To illustrate, we’ll use these two attacks:\nWe can detect the sword hitting the target using an Area2D, but we only want that area to be active during the swing. In order for this activation to be in sync with the animation, we’ll use the AnimationPlayer to control it.\nAdd an Area2D and CollisionShape2D to the scene. We’ll use a rectangle shape for the hitbox and size it so that it covers the sword during the swing frame.\nMove the animation to the first frame and check the Disabled property of the area. Click the keyframe icon to add a track to the animation. Then advance the animation to the frame where the sword is extended, and add another keyframe with Disabled unchecked. Finally, advance to the end of the swing and keyframe Disabled on once more.\nNow connect this new area’s area_entered signal (or, depending on how your game is set up, body_entered). For the purposes of this demo, let’s assume that any body that can take damage has an Area2D defined and placed in a group called “hurtbox”.\nfunc _on_SwordHit_area_entered(area): if area.is_in_group(\"hurtbox\"): area.take_damage() Now you should be able to try it out and see the attack doing damage if the target is inside the sword’s hitbox.\nChanging the hitbox size When you have more than one attack animation, the size of the affected area may not be the same. In the above attack animations, the first one is an upward sweeping attack that covers more area. To handle this, we also need to add an animation track for the collision shape’s Extents property. Set this and keyframe it at the start of each animation.\nRelated recipes Top-down character Controlling animation states Like video? ","description":"","tags":null,"title":"Melee attacks","uri":"/godot_recipes/4.x/animation/melee_attacks/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 want a rigid body to move to a target position.\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 move a body, we need to apply a push in a given direction - a force. Once the body is moving, we want the force to get smaller as we get closer to the final position.\nThis is the perfect situation to use the Vector2.distance_to() function. It will tell us how far away the target is, and we can use that to set the force.\n# Smoothly move to target extends RigidBody2D var linear_force = 5 var target = position func _physics_process(delta): var dist = position.distance_to(target) constant_force = dir * linear_force * dist Use linear damp If you try this using the default RigidBody2D settings, you will notice that the body shoots right past the target. This is due to the body’s Linear/Damp property, which has a default setting (found in the Project Settings of 1). This value represents “friction” and controls how quickly a moving rigid body will come to a stop when no force is applied. Increasing this value will ensure that your body coasts to a stop at the target. Experiment with how this value and the linear_force interact to get the exactly the movement you’re looking for.\nRelated recipes RigidBody2D: Look at Target ","description":"","tags":null,"title":"RigidBody2D: Move to Target","uri":"/godot_recipes/4.x/physics/smooth_rigid_move/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 Shooting projectiles Rolling Cube Align Movement with Camera Arcade-style Spaceship Drawing Vectors in 3D Arcade-style Airplane Arcade-style Car Click to move Smooth rotation CharacterBody3D: Align with Surface 3D Kinematic Car ","description":"","tags":null,"title":"3D","uri":"/godot_recipes/4.x/3d/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem Your Kinematic Car climbs slopes, but it doesn’t look quite right:\nSolution Kinematic bodies don’t automatically rotate on collision. When the wheels aren’t both touching the ground, as in the image above, we’ll need to align the car manually.\nTo begin, we need to detect when the wheel isn’t on the ground. Add two RayCast nodes to the car and align them with the front and rear wheels like so:\nFor both, set the Cast To to (0, -0.25, 0) and don’t forget to check the “Enabled” box.\nAligning a 3D object We’re going to reuse the code from the CharacterBody3D: Align with Surface recipe. Add this to car_base.gd:\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 Now, in the _physics_process() function, right after calling move_and_slide_with_snap(), we’ll check to see if we need to align the car:\n# If either wheel is in the air, align to slope. if $FrontRay.is_colliding() or $RearRay.is_colliding(): # If one wheel is in air, move it down var nf = $FrontRay.get_collision_normal() if $FrontRay.is_colliding() else Vector3.UP var nr = $RearRay.get_collision_normal() if $RearRay.is_colliding() else Vector3.UP var n = ((nr + nf) / 2.0).normalized() var xform = align_with_y(global_transform, n) global_transform = global_transform.interpolate_with(xform, 0.1) How it works When neither wheel is on the ground, we don’t rotate the car at all.\nOtherwise, we’re going to use an average of the front and rear rays’ results. When the ray is colliding, the collider’s surface normal is used. This way, if the two wheels are touching different slopes (like on a curved hill, for example), the result will be to try and get both wheels on the surface, like so:\nIn this image, you can see the car isn’t aligned with either surface, but is halfway between.\nIf the ray is not hitting anything, then we’ll assume a horizontal surface. That will bring the front or rear down when the other wheel is touching.\nRelated recipes Kinematic Car: Base CharacterBody3D: Align with Surface Like video? ","description":"","tags":null,"title":"3D Kinematic Car: Slopes \u0026 Ramps","uri":"/godot_recipes/4.x/3d/kinematic_car/car_slopes/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want a shader to blur an object or the screen.\nSolution shader_type canvas_item; uniform float blur_amount : hint_range(0, 5); void fragment() { COLOR = textureLod(SCREEN_TEXTURE, SCREEN_UV, blur_amount); } For example, to gradually blur the entire screen, such as for a scene transition effect:\nYou can also animate the blurring:\nextends Node # Add a ColorRect or other Control set to fill the screen # Place it lower in the tree and/or place in CanvasLayer # so it's on top of the rest of the scene. @onready var blur = $Blur var blur_amount = 0 func _process(delta): blur_amount = wrapf(blur_amount + 0.05, 0.0, 5.0) blur.material.set_shader_param(\"blur_amount\", blur_amount) Related Recipes Shaders: Intro Interacting with Shaders ","description":"","tags":null,"title":"Blur shader","uri":"/godot_recipes/4.x/shaders/blur/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 Marker3D 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:\n@export 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":" Tip This article is being updated from Godot 3 to Godot 4.\nNow that we’ve got the basic gameplay, it’s time to start working on the UI. We’re going to need menu screens for the title, settings, and game over.\nMenu screens The three screens will share a common layout and some functionality, so we’ll start with a base scene they can all inherit from. In the new scene, start with a CanvasLayer and name it BaseScreen. Save this scene in the “UI” folder.\nCanvasLayer (“BaseScreen”) MarginContainer VBoxContainer Label HBoxContainer (“Buttons”) Tween The MarginContainer will ensure that none of our UI elements get too close to the edge of the screen. Set all four of its Custom Constants properties to 20.\nNext is a VBoxContainer to organize the main elements. Set its Custom Constants/Separation to 150.\nThe Label node displays the screen’s title. Put “Title” in its Text field and load the same font resource we used for the circles.\nFinally, add an HBoxContainer named “Buttons” which will hold the buttons we add to the screens. Set its Separation to 75. Then duplicate the node so that we have another row of buttons.\nThe screen should start offscreen, so set the Offset on the root node to (500, 0). Then add a script to the scene:\nextends CanvasLayer @onready var tween = $Tween func appear(): tween.interpolate_property(self, \"offset:x\", 500, 0, 0.5, Tween.TRANS_BACK, Tween.EASE_IN_OUT) tween.start() func disappear(): tween.interpolate_property(self, \"offset:x\", 0, 500, 0.4, Tween.TRANS_BACK, Tween.EASE_IN_OUT) tween.start() This script sets up the animations we can call to make the screen appear and disappear.\nNow we can make our three inherited scenes. For each, name the root node, change the Label text, and add TextureButtons to the “Buttons” containers. Use the images from the assets folder for each button’s Normal texture. Name each button for its function (“Play”, “Settings”, etc.) and add it to the group “buttons”.\nHere is what the three scenes should look like, using the indicated button names:\nMake one more scene with a Node root named “Screens” and instance the three screens in it. Add the following script, which will handle scene transitions and state.\nextends Node signal start_game var current_screen = null func _ready(): register_buttons() change_screen($TitleScreen) func register_buttons(): var buttons = get_tree().get_nodes_in_group(\"buttons\") for button in buttons: button.connect(\"pressed\", self, \"_on_button_pressed\", [button.name]) func _on_button_pressed(name): match name: \"Home\": change_screen($TitleScreen) \"Play\": change_screen(null) await get_tree().create_timer(0.5).timeout emit_signal(\"start_game\") \"Settings\": change_screen($SettingsScreen) func change_screen(new_screen): if current_screen: current_screen.disappear() await current_screen.tween.tween_completed current_screen = new_screen if new_screen: current_screen.appear() await current_screen.tween.tween_completed func game_over(): change_screen($GameOverScreen) This script connects up all our buttons by linking the pressed signal and passing along the button’s name as a parameter. This lets our _on_button_pressed() method decide what each button should do.\nThe change_screen() method handles transition to the selected screen, including the null option for when we don’t want to display a screen at all.\nRun it to test out the screen transitions:\nInstance this scene in Main, then connect its start_game signal to the new_game() function in main. Don’t forget to remove new_game() from the _ready(). Try running the game and you should be able to start. The last part will be to connect up the game over condition.\nIn the Jumper, add a signal called died and emit that signal in the visibility notifier’s method.\nAdd this to the new_game() function:\nplayer.connect(\"died\", self, \"_on_Jumper_died\") Then add this new function, which will ensure all the circles are removed when the player dies.\nfunc _on_Jumper_died(): get_tree().call_group(\"circles\", \"implode\") $Screens.game_over() Our menu screens are basic and no-frills, but they’re functional. In the next part, we’ll continue the UI work with our score counter and other in-game displays.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Menus","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_04/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You are using a TileMap, and want to use autotiling to more quickly draw your levels.\nSolution For this demo, we’ll be using the following tileset:\nNote These tiles are from Kenney’s “Topdown Shooter” art pack, which you can find here:https://kenney.nl/assets/topdown-shooter\nCreating a map from these tiles, if you were adding them one-by-one, would be a tedious process. You would be constantly changing between tiles to line up corners, intersections, and endpoints.\nUsing autotiling, you to draw the walls freely, and the autotiling algorithm selects the correct tiles to make everything line up.\nHere’s an example:\nHow autotiling works The tiles we’re using are designed for a 3x3 (minimal) tiling. Consider a single tile divided into a 3x3 grid:\nWe can mark the “active” portions of the tile (i.e. the parts that are not the wall):\nIf we were to do this with each tile, the computer can then make sure that whatever tile is placed adjacent to this one will match up.\nIn a 3x3 grid there are 512 possible combinations (2^9). We can discard most of these, as they don’t make sense for making continuous walls. It turns out, to properly cover the wall combinations, you need 48 tiles, which we have in our tileset. We’ll be ignoring the 7 tiles in the bottom-right (the ones with the white background).\nMaking the TileSet In your TileMap’s Tile Set property, select “New TileSet” and click on it to open. You’ll see the TileSet editor panel open:\nClick the ⊞ button to add a texture, choosing the tile set from above. Then click “New Autotile” and drag to select the whole image. You will probably need to enable snap and adjust the options. The tiles in this tilest are 64x64 and have a 10 pixel separation. If you’re using your own art, you’ll need to enter your own values.\nNow that you have selected the set of tiles to make up the autotile group, it’s time to set the bitmasks. Click the “Bitmask” button at the top and start clicking in the tiles. The masked area will appear red. When you’re done it should look like this:\nRemember, we’re not using the tiles in the lower-right corner.\nLastly, click the “Icon” button and select a tile you’d like to use as the icon for the autotile group. This is the tile that will show under the cursor as you’re drawing.\nSwitch back to the TileMap, and you should be able to start drawing. If something is wrong, check your bitmasks and make sure you didn’t miss a square on any of the tiles. Compare with the picture above.\nFull TileSet You can also add collision, navigation, or occlusion to your autotile set. If you download the example project below, you’ll find a complete tileset with polygons defined on all the tiles.\n","description":"","tags":null,"title":"TileMap: using autotile","uri":"/godot_recipes/4.x/2d/autotile_intro/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":"In the last part, we learned how to use Area3D nodes to detect contact between objects, making coin, bullet, and spike objects for our character to interact with. In this part, we’ll look at a few small improvements: capturing the mouse, animating the coins, and detecting edges so our character doesn’t fall.\nCapturing the Mouse One issue with our mouse-based controls is that as you move the mouse from side to side, it eventually moves out of the game window and hits the edge of your screen. To solve this, we need to “capture” the mouse. However, if we do that, we won’t be able to close the window or anything else - our mouse will be gone! We’ll need a way to release the mouse again.\nFirst, to capture the mouse, add the following to the main scene:\nfunc _ready(): Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) This takes care of the first part: the mouse will now be captured by our game window. Now we need it to be released when we press the “Escape” key. Let’s put this in the main script as well:\nfunc _input(event): if event.is_action_pressed(\"ui_cancel\"): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) Run the game and try it out.\nLet’s also ignore mouse motion when it’s not captured. In the character script, change this line in _unhandled_input():\nif event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: Now we have another issue: once you’ve pressed “Escape”, we don’t have a way to go back to being captured. Let’s do that if we click on the window:\nfunc _input(event): if event.is_action_pressed(\"ui_cancel\"): Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE) if event.is_action_pressed(\"shoot\"): if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) This works OK, but when we click to recapture the mouse, we also fire a bullet, since the mouse click does that as well. We can solve this by marking the input as “handled”, so that Godot won’t send it on to any other nodes:\nif event.is_action_pressed(\"shoot\"): if Input.get_mouse_mode() == Input.MOUSE_MODE_VISIBLE: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) get_tree().set_input_as_handled() Now that first click capturing the mouse won’t also fire a bullet.\nAnimated Coins Now we’re going to make the coins from the last part a bit more dynamic and appealing. Open Coin.tscn and add an AnimationPlayer to the scene.\nClick the “Animation” button and select “New” to create a new animation called “bounce”. A duration of 1 second is fine, but make sure to enable looping.\nWe’re going to animate two properties of the coin: position (on the Y axis, up and down) and rotation. Ensure the scrubber is at time 0 and add a keyframe for both Translation and Rotation Degrees.\nMove the scrubber to the 0.5 second mark, change the Y component of the translation to 0.3, and click the keyframe button. Then move the scrubber all the way to 1.0 and keyframe the rotation at 180 degrees in Y.\nPress “Play” to see how your animation looks. Try clicking on the individual translation keyframes and adjusting the Easing value.\nFinally, click the “Autoplay” button to ensure the animation will automatically start when the game is run.\nEdge Detection Finally, let’s see if we can keep our character from running off a cliff and falling to its death.\nStart by adding a RayCast node to the player. It appears as a thin blue line. By default, its Cast To property is set to (0, -1, 0), which is pointing down. This is good, but we also need to move it forward so that it’s pointing down at the front of the character:\nAlso, make sure to check the Enabled property, or the RayCast won’t work.\nNow, in our character script, we need to check that when moving forward, if the RayCast is colliding, it’s safe to move.\nRight now, we have the following:\nif Input.is_action_pressed(\"move_forward\"): velocity += -transform.basis.z * speed Let’s try only adding to the velocity if the ray is colliding:\nif Input.is_action_pressed(\"move_forward\") and $RayCast.is_colliding(): velocity += -transform.basis.z * speed Try it out. When you run up to an edge, you’ll stop. But wait - have you tried jumping forward? Our forward movement is now canceled when we’re in the air! Back to the drawing board.\nNow we need to also check if we’re on the ground, so that if we walk forward and the ray stops colliding, we do nothing. Otherwise, we move as normal:\nif Input.is_action_pressed(\"move_forward\"): if is_on_floor() and !$RayCast.is_colliding(): pass else: velocity += -transform.basis.z * speed Info You may be wondering why I wrote it this way. Keep reading, there’s a reason!\nThis works, but something feels off about the code. We have a conditional statement that does nothing. Surely we can simplify this. We can, with a little bit of Boolean Algebra.\nOur conditional statement is essentially this:\nif A: do_nothing else: do_something Which is equivalent to:\nif not A: do_something So what we really need to do is convert our conditional statement to:\nif !(is_on_floor() and !$RayCast.is_colliding()) This works, but it’s hard to read. Can it be simplified? It can, using a Boolean Algebra method called “De Morgan’s Law”. De Morgan’s Law states that\nnot (A and B) = not A or not B So we can apply that here and we get the following:\nif Input.is_action_pressed(\"move_forward\"): if !is_on_floor() or $RayCast.is_colliding(): velocity += -transform.basis.z * speed In English:\n“If we’re not on the floor or there is floor in front of us, move forward.”\nThis is a very simplistic implementation - you can still walk sideways or backwards off the edge, for example. Feel free to take this idea and run with it to make improvements. Some games let you fall if you move off the edge slowly, but stop you if you’re moving fast.\nWrapping Up In this tutorial, we added a few small improvements to the game. Capturing the mouse is useful in many types of 3D games (first-person, for example), and RayCasts have a wide range of uses - we only touched on one here. The animation we added was very small, but a good start - we’ll be using them for many things as we move forward.\nIn the next part: Using Constructed Solid Geometry (CSG).\nYou can also find a video version of this lesson here: ","description":"","tags":null,"title":"Edge Detection \u0026 Mouse Capture","uri":"/godot_recipes/4.x/g101/3d/101_3d_05/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 Edge Detection \u0026 Mouse Capture Using CSG First-person Character ","description":"","tags":null,"title":"Intro to 3D","uri":"/godot_recipes/4.x/g101/3d/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 Melee attacks 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to make RPG-style ability buttons, including a cooldown effect.\nSolution If you need art for your buttons, you can find a wide variety of well-designed buttons at Game-icons.net. We’ll be using a few from there for this recipe.\nNode setup The scene for our ability button will need the following nodes:\nAbilityButton: TextureButton Sweep: TextureProgress Timer Counter: MarginContainer Value: Label Drop your chosen icon into the Textures/Normal property of the AbilityButton.\nOn the Sweep node, choose “Full Rect” from the Presets menu. Set the Fill Mode to “Counter Clockwise”.\nWe also want our cooldown “radial wipe” to darken the button, so set the Modulate property to a dark gray with some transparency:\nThe Timer node should be set to “One Shot”.\nCounter is a container to hold and align the text. Set its layout to “Bottom Wide”, and in its Theme Overrides/Constants, both Margin Right and Margin Left to 5.\nFinally, on the Value label, set Horizontal Alignment to “Right” and Clip Text to “On”. Add a font to the Theme Overrides/Font. Put a value like 0.0 in the Text field to check how it works. Since our icon is black and white, it also helps to add a Theme Overrides/Constants/Outline Size_ of 1.\nScript Add a script to the AbilityButton. Connect the Timer’s timeout signal and the AbilityButton’s pressed signal.\nextends TextureButton class_name AbilityButton @onready var time_label = $Counter/Value @export var cooldown = 1.0 func _ready(): time_label.hide() $Sweep.value = 0 $Sweep.texture_progress = texture_normal $Timer.wait_time = cooldown set_process(false) We start by exporting a cooldown variable for the length of our ability’s cooldown. Then, in the _ready() method, we can set the Timer to use that value. Then we hide the label, because we only want to display it during the countdown.\nNext, we need a texture to assign to the TextureProgress display. In this case, we’ll copy the texture from the button - you could also use a different texture if you like.\nFinally, we make sure the sweep’s value is at 0, and set the node’s processing to false. We’ll do the animation in _process() so we don’t need it running when we’re not in cooldown mode.\nfunc _process(delta): time_label.text = \"%3.1f\" % $Timer.time_left $Sweep.value = int(($Timer.time_left / cooldown) * 100) In _process() we use the time_left on the timer to set the label’s text and the sweep’s value.\nfunc _on_AbilityButton_pressed(): disabled = true set_process(true) $Timer.start() time_label.show() When the button is clicked, everything gets started.\nfunc _on_Timer_timeout(): print(\"ability ready\") $Sweep.value = 0 disabled = false time_label.hide() set_process(false) And everything is reset when the timer runs out. Put several buttons in an HBoxContainer and you’ve got an action bar:\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ui_cooldown_button\n","description":"","tags":null,"title":"Cooldown Button","uri":"/godot_recipes/4.x/ui/cooldown_button/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to use a custom mouse cursor.\nSolution Setting the mouse cursor is done with Input.set_custom_mouse_cursor(). All you need is a texture to use. The texture must be no larger than 256x256 pixels in size.\nFor example, to use the following image:\nAnd set its hotspot to the center:\nextends Node2D func _ready(): Input.set_custom_mouse_cursor(cursor_image, Input.CURSOR_ARROW, Vector2(64, 64)) The second parameter sets which system cursor to replace. See the Input docs for the full list.\n","description":"","tags":null,"title":"Customizing the Mouse Cursor","uri":"/godot_recipes/4.x/input/custom_mouse_cursor/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 Customizing the Mouse Cursor Mouse: Drag-select multiple units ","description":"","tags":null,"title":"Input","uri":"/godot_recipes/4.x/input/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":" Circle Jump An end-to-end game development series. In this series, we build a one-touch mobile game called “Circle Jump”. Here’s what the game looks like:\nIn each part of the series, we’ll add features and fix bugs, explaining the process along the way.\nThe game is be available on the following platforms:\nAndroid: Google Play Store iOS: coming soon Web: Game of the Month You can also download it for desktop platforms from Itch.io:\nCircle Jump by kidscancode All source code for the game is available on GitHub.\n","description":"","tags":null,"title":"Mobile Game: Circle Jump","uri":"/godot_recipes/4.x/games/circle_jump/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":" Tip This article is being updated from Godot 3 to Godot 4.\nIn the last part, we added UI in the form of menus to start and configure the game. We also need a UI to display in-game information such as score.\nHUD scene Add a new scene with a CanvasLayer root to be our HUD. Give it two children: a MarginContainer named “ScoreBox” and a `Label\" named “Message”.\nYour scene tree should look like this:\nSet the layout of the ScoreBox to “Bottom Wide” and the Custom Constants all to 20. Add an HBoxContainer child and under that two Label nodes. Name the second label “Score” and put 100 in its Text property. Set the HBoxContainer’s Alignment to “End”.\nAdd the same DynamicFont resource to both labels, but choose “Make Unique” on the first label and set its size to 32. Set its Text property to “Score”. In its _Size Flags/Vertical, set “Fill”. Your layout should look like this:\nNow for the Message node load the font and set Text to “Message” so we’ll have something to see. Also choose “Make Unique” on the font resource (you’ll see why in the next section). Set Align and Valign to “Center” and Clip Text to “On”. For layout, choose “Center Wide”. Also, set Grow Direction/Vertical to “Both”.\nMessage animation This message will show information during gameplay (level up, bonuses, etc). We want it to be animated - to appear and then fade out. Add an AnimationPlayer to the scene.\nWe’ll make two animations: one to set the initial values, and one to animate the message display. Add the first animation, “init” and click the “Autoplay on Load” button. Set the length to 0.1.\nAdd a keyframe at time 0 for the Font/Size (64), and one for the Visible set to “Off”.\nAdd the second animation, “show_message”. Set its length to 0.75 and keyframe Visibility to “On”.\nNext, we’ll keyframe the Font/Size from 64 at time 0 and 200 at the end. Set the track’s Update Mode to “Continuous”.\nWe also want it to fade out as it grows, so keyframe the Modulate alpha value from 255 to 0.\nHeres’ what the animation settings should look like:\nAnd the animation when it plays:\nHUD Script Now let’s add a script to the scene, with methods to update the displays:\nextends CanvasLayer func show_message(text): $Message.text = text $AnimationPlayer.play(\"show_message\") func hide_score(): $ScoreBox.hide() func show_score(): $ScoreBox.show() func update_score(value): $ScoreBox/HBoxContainer/Score.text = str(value) Instance the HUD in the main scene, and add $HUD.hide_score() to the _ready() and _on_Jumper_died() functions. In new_game() we need to show the hud and display a message:\n$HUD.show_score() $HUD.show_message(\"Go!\") To add the score, create a score variable and set it to 0 in new_game(). In _on_Jumper_captured() increment it by one. Make sure to call $HUD.update_score(score) after each of these.\nIn the next part, we’ll add sound and color to the game!\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Score and HUD","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_05/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to shoot projectiles from your player/mob/etc..\nSolution For this example, we’ll use the “Mini Tank” that we set up in CharacterBody3D: Movement.\nSetting up the bullet First, we’ll set up a “bullet” object that we can instance. Here are the nodes we’ll use:\nArea3D: Bullet MeshInstance CollisionShape For your mesh, you can use one of Godot’s built-in primitive shapes, or something like this:\nNote If you’d like to use the bullet model pictured here, you can grab it from Kenney’s “Weapon Pack”.\nAdd your mesh to the MeshInstance and a scale a collision shape to match.\nWarning Remember to align your MeshInstance with the forward direction (-Z) of the Area3D node, or your bullet won’t look like it’s flying the right way!\nAdd a script and connect the Area3D’s body_entered signal.\nextends Area3D signal exploded @export var muzzle_velocity = 25 @export var g = Vector3.DOWN * 20 var velocity = Vector3.ZERO func _physics_process(delta): velocity += g * delta look_at(transform.origin + velocity.normalized(), Vector3.UP) transform.origin += velocity * delta func _on_Shell_body_entered(body): emit_signal(\"exploded\", transform.origin) queue_free() We’re using a custom gravity vector, g so that we can control how the shell flies from the tank’s cannon, giving it a nice arc effect. If you’d rather your projectiles move in a straight line, you can remove the line that applies it in _physics_process().\nUsing look_at() each frame turns the bullet to point in its direction of travel.\nWe’ll also emit an exploded signal, which you can connect up to implement explosion and/or damage effects (but that’s for another recipe).\nShooting Now in the tank (or whatever object you have doing the shooting), add a Marker3D child at the point where you want the bullets to appear. In the case of our tank, we’re placing it at the end of the cannon barrel:\nNow we can add the code to the tank’s script. First a way to add the bullet scene we’re going to instance:\n@export var Bullet: PackedScene And in _process() or _unhandled_input() (wherever you’re capturing input), add the code to instance the bullet:\nif Input.is_action_just_pressed(\"shoot\"): var b = Bullet.instantiate() owner.add_child(b) b.transform = $Cannon/Muzzle.global_transform b.velocity = -b.transform.basis.z * b.muzzle_velocity That’s it - run your scene and try it out:\nRelated recipes CharacterBody3D: Movement Godot 101: Intro to 3D ","description":"","tags":null,"title":"Shooting projectiles","uri":"/godot_recipes/4.x/3d/3d_shooting/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’d like to use animated tiles in your TileMap.\nSolution The most straightforward way to approach this problem is to use the AnimatedTexture resource.\nCreating an AnimatedTexture For this example, we’ll use the following water tiles:\nDownload these images: water.zip\nUnzip the images into your project folder. In the Inspector, click the “Create a new resource” button:\nChoose AnimatedTexture and set the Frames property to 5. For each frame, drag the corresponding image to its Texture property.\nYou can adjust the overall animation’s speed with the Fps property, as well as each individual frame’s Delay Sec.\nClick the “Save” button to save the resource. Give it a name such as water_anim.tres.\nUsing AnimatedTexture in a TileMap Now that the AnimatedTexture is saved, it can be used in a TileSet. Open a new or existing TileMap and select its Tile Set property. Click the button to add a new texture to the TileSet:\nSelect the newly added texture and click “New Single Tile”. Draw a box around the texture (use “Enable Snap” to make this easier).\nNow you can select the tile in your TileMap and draw with it just like any other tile.\nRelated Recipes TileMap: using autotile ","description":"","tags":null,"title":"TileMap: animated tiles","uri":"/godot_recipes/4.x/2d/tilemap_animation/index.html"},{"content":" UI Building user interfaces.\nIn this section: Labels Containers Cooldown Button Heart Containers: 3 Ways Floating combat text Level Select Menu Minimap/radar Radial Popup Menu ","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 Path following Homing missile Context-based steering Pet Following ","description":"","tags":null,"title":"AI/Behavior","uri":"/godot_recipes/4.x/ai/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want an object to “orbit” (move in a circle) around another object.\nSolution This is a common beginner question, and often comes after a bunch of messy experimenting with trig functions. The answer is much simpler:\nPlace the orbiting sprite in a child node of the main sprite (we’re calling it “Pivot”). Give it an offset and rotate the Pivot.\nextends Node2D @export var rotation_speed = PI func _process(delta): $Sprite/Pivot.rotation += rotation_speed * delta This works just as well in 3D, too:\nextends Node3D @export var rotation_speed = PI func _process(delta): $MeshInstance/Pivot.rotate_y(rotation_speed * delta) ","description":"","tags":null,"title":"Circular movement","uri":"/godot_recipes/4.x/basics/rotation/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 CharacterBody3D: Stopping on Slopes Collision Layers and Masks Kinematic Friction RigidBody2D: Move to Target RigidBody2D: Drag and Drop Character to Rigid Body Interaction Using 2D Joints Conveyor Belt 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 Node3D(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":" Tip This article is being updated from Godot 3 to Godot 4.\nSettings singleton First, we’ll add a new script by choosing File -\u003e New Script in the script tab. Name the script settings.gd.\nIn this script we’ll place the configuration settings for the game.\nvar enable_sound = true var enable_music = true var circles_per_level = 5 Add the script as an autoload by opening “Project Settings” and selecting the “Autoloads” tab. Click the folder to load the script and then click “Add”.\nAdding sound To play sounds, we’ll be adding several AudioStreamPlayer nodes to different scenes.\nFirst, add one to the Main scene and name it “Music”. For its Stream property use res://assets/audio/Music_Light-Puzzles.ogg.\nTo the Screens scene, add another called “Click”, which will play when we tap buttons. Use menu_click.wav from the assets folder.\nIn the Circle scene, add an audio player named “Beep” and use the 89.ogg sound file.\nFinally, on the Jumper, we need two sound effects: “Jump” and “Capture”. Use 70.ogg and 88.ogg, respectively.\nNow to play the sounds, we can call their play() methods. Add this to Main.new_game():\nif settings.enable_music: $Music.play() and Main._on_Jumper_died():\nif settings.enable_music: $Music.stop() In Screens.gd add this to _on_button_pressed():\nif settings.enable_sound: $Click.play() On the circle, we want to play the Beep sound when a limited circle completes a full orbit. This is in check_orbits():\ncurrent_orbits -= 1 if settings.enable_sound: $Beep.play() And in Jumper.gd, we add the sounds like so:\nfunc jump(): target.implode() target = null velocity = transform.x * jump_speed if settings.enable_sound: $Jump.play() func _on_Jumper_area_entered(area): target = area velocity = Vector2.ZERO emit_signal(\"captured\", area) if settings.enable_sound: $Capture.play() Run the game and test that you hear all the sounds as expected.\nSound settings Now that we have sound working, we can connect the buttons on the “Settings” screen that can toggle sound and music.\nThe button appearance needs to be changed to match the current on/off state of the property. We’ll load the textures first so that we can assign them as needed:\nvar sound_buttons = {true: preload(\"res://assets/images/buttons/audioOn.png\"), false: preload(\"res://assets/images/buttons/audioOff.png\")} var music_buttons = {true: preload(\"res://assets/images/buttons/musicOn.png\"), false: preload(\"res://assets/images/buttons/musicOff.png\")} Right now, we’re not handling the buttons when they’re pressed. The issue is that we’re currently passing the button’s name, which won’t let us change its texture. Instead, we’re going to refactor register_buttons() to pass a reference to the button itself:\nbutton.connect(\"pressed\", self, \"_on_button_pressed\", [button]) Then we can update _on_button_pressed() like so:\nfunc _on_button_pressed(button): if settings.enable_sound: $Click.play() match button.name: \"Home\": change_screen($TitleScreen) \"Play\": change_screen(null) await get_tree().create_timer(0.5).timeout emit_signal(\"start_game\") \"Settings\": change_screen($SettingsScreen) \"Sound\": settings.enable_sound = !settings.enable_sound button.texture_normal = sound_buttons[settings.enable_sound] \"Music\": settings.enable_music = !settings.enable_music button.texture_normal = music_buttons[settings.enable_music] Color themes We’re also goign to add a way to have different color schemes. These can change in different ways: perhaps as a settings option, or they change as the player gets to higher levels.\nWe’ll store the color scheme data in a dictionary, with the keys being the “name” of the scheme. Each color scheme will also be a dictionary, with the keys denoting the game component that will use that color.\nAdd this to settings.gd:\nvar color_schemes = { \"NEON1\": { 'background': Color8(0, 0, 0), 'player_body': Color8(203, 255, 0), 'player_trail': Color8(204, 0, 255), 'circle_fill': Color8(255, 0, 110), 'circle_static': Color8(0, 255, 102), 'circle_limited': Color8(204, 0, 255) }, \"NEON2\": { 'background': Color8(0, 0, 0), 'player_body': Color8(246, 255, 0), 'player_trail': Color8(255, 255, 255), 'circle_fill': Color8(255, 0, 110), 'circle_static': Color8(151, 255, 48), 'circle_limited': Color8(127, 0, 255) }, \"NEON3\": { 'background': Color8(0, 0, 0), 'player_body': Color8(255, 0, 187), 'player_trail': Color8(255, 148, 0), 'circle_fill': Color8(255, 148, 0), 'circle_static': Color8(170, 255, 0), 'circle_limited': Color8(204, 0, 255) } } var theme = color_schemes[\"NEON1\"] Now on each object, we need to set the colors based on the settings property.\nFor the circle, the color is set using the shader material resource. Because resources are shared, that means that changing one circle’s color would change them all. Let’s make each circle’s material unique to avoid this:\n$Sprite.material = $Sprite.material.duplicate() $SpriteEffect.material = $Sprite.material The color of the circle is determined by what mode it’s using, so set_mode() is where we’ll choose the color:\nfunc set_mode(_mode): mode = _mode var color match mode: MODES.STATIC: $Label.hide() color = settings.theme[\"circle_static\"] MODES.LIMITED: current_orbits = num_orbits $Label.text = str(current_orbits) $Label.show() color = settings.theme[\"circle_limited\"] $Sprite.material.set_shader_param(\"color\", color) Then in the _draw() function where we’re filling in the limited circle, replace the red color with settings.theme[\"circle_fill\"].\nFor the player, set the color in its _ready():\nfunc _ready(): $Sprite.material.set_shader_param(\"color\", settings.theme[\"player_body\"]) $Trail/Points.default_color = settings.theme[\"player_trail\"] In the next part, we’ll add a movement to the circles.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Sound and Colors","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_06/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nEarlier, we saw how to design a 3D environment using imported models. But what if you want to make something like a room, with walls, doors, ramps, and other features, but you don’t have any models handy? CSG to the rescue!\nWhat is CSG? CSG stands for Constructive Solid Geometry. It allows you to combine primitive shapes to build complex geometry. Shapes can be combined with boolean operations such as Union, Intersection, and Subtraction.\nCSG is a great tool for prototyping environments and game objects. Later in this tutorial, we’ll use it to make a small FPS-style level with some ramps, walls and platforms.\nBefore we do that, let’s get introduced to how the CSG nodes work.\nCSG Basics Create a new scene with a Node3D root, then add a child node and type “CSG” in the search box.\nThese are the available CSG shapes. Choose a CSGBox to start. You’ll see a plain cube mesh with the following properties:\nThe Operation property is the one that determines how CSG shapes will be combined. The options are:\nUnion - The shapes will be merged, removing any “inside” geometry. Intersection - Only the intersecting (overlapping) geometry will be kept. Subtraction - The second shape is “cut out” of the first. CSG operations are performed on a shape by adding children. Add a child CSGCylinder to the CSGBox. Drag the top size handle (orange dot) to make it a bit taller. You can also increase the Sides property to make it look more circular (here it’s set to 20):\nBy default, the shape’s operation is set to “Union”. The cylinder shape is being “added” to the cube. Try changing it to “Intersection”:\nAnd “Subtraction”:\nHopefully you’re already seeing the possibilities of creating complex shapes through these 3 operations.\nCSGCombiner This node is an “empty” shape. It’s used to organize your shapes. Children of a CSGCombiner will be combined following the same rules as above.\nBuilding a Room Now we’re going to make something useful: a large room with some obstacles and features that our character can interact with, and that we can use in the upcoming tutorials. Make a new scene with a Node3D root that we can start working with.\nStart with a CSGBox, and set its Width and Depth to 20 and its Height to 5. We need this to be a box that we go inside, so click the Invert Faces property as well. This reverses the shape so that the solid walls are on the inside rather than the outside. Also check the Use Collision property, so that the physics engine will treat this shape as a static body object.\nAdd an instance of the player character and test that you can walk around in your new room.\nTip You may remember that in the last part we added code to capture/release the mouse. You’ll need to copy that code over to this scene as well.\nAdding features Now let’s add some features - some internal walls, a ledge running around the edge with a ramp, and so on. Feel free to get creative and add your own ideas. Here are a few to get started:\nTip If you use a CSGCombiner for each of these objects it will be easier to organize and duplicate them. Make sure to enable Use Collision on it.\nWall with door Add a CSGBox and set its Width to 0.5 and its Height to 5 (the same height as the original room). Make the depth about half the size of the room. You can enable snapping here to make it easier to align.\nAdd another CSGBox as a child and set it to “Subtract”. Size it to resemble a door. You can also use a cylinder shape to get an arched portal.\nRamp For the ramp, we’ll use a CSGPolygon. This CSG shape lets you extrude a given polygon to a desired depth. The default shape is a square, but you can add or remove points. For a ramp, we want 3 points.\nAfter adding the CSGPolygon, you can click the Polygon property to adjust its number of points. After that, you can drag the three points to whatever location you like. To ensure everything lines up, you can type the coordinates into the Inspector:\nIn this picture, we’ve created a ramp and added a couple of CSGBox shapes to make the ledge.\nPutting it together Make sure to add a Material to your shapes, choosing an Albedo color that seems pleasant to you. In the following examples, we’ve picked a tan color.\nHere’s an example of a possible room setup:\nHit play and you should be able to walk around the rooms:\nThe area is featureless right now, but to make things more visually interesting, you can add individual lights in each room (more about lighting in a later tutorial). Here’s an example of adding some OmniLight and SpotLight nodes to the scene:\nWrapping Up CSG is a powerful tool for building objects directly in Godot without having to move to another modeling application such as Blender. It can be helpful if you need to mock up a test level for your game, or for the final environment. Keep in mind that as the CSG tree becomes more complex, it can incur a performance penalty. Try to use CSGCombiner to separate your scene into separate CSG trees to minimize this.\nIn the next part, we’ll look at a popular style of 3D game: first person.\nYou can also find a video version of this lesson here: ","description":"","tags":null,"title":"Using CSG","uri":"/godot_recipes/4.x/g101/3d/101_3d_06/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem When moving with WASD-style controls in 3D, it’s easy to get disoriented if the camera rotates. Whose forward counts - the player’s (ie the camera’s) or the object in the game world?\nSolution While this situation can apply to many possible scenarios, we’ll use the Rolling Cube recipe as our example.\nIn the script for the cube, we have the following code for movement:\nfunc _physics_process(_delta): var forward = Vector3.FORWARD if Input.is_action_pressed(\"up\"): roll(forward) if Input.is_action_pressed(\"down\"): roll(-forward) if Input.is_action_pressed(\"right\"): roll(forward.cross(Vector3.UP)) if Input.is_action_pressed(\"left\"): roll(-forward.cross(Vector3.UP)) As you can see, this uses global direction vectors, so if the camera rotates, “up” will no longer appear to be moving forward in the camera view. If we rotate the camera 180°, everything will be reversed!\nWe could just change to use the camera’s forward vector:\nvar forward = -camera.transform.basis.z.normalized() For some setups this might be fine. However, it really doesn’t work for the cube:\nThe cube needs to only move in the 4 cardinal directions. This means we need to take the camera’s forward vector and find which of the axes (+X, -X, +Z, or -Z) it’s closest to.\nWe can find this using the Vector3.max_axis() function. This returns which of the vector’s components is the largest. Since they can be positive or negative, we’ll use abs() first.\nOnce we have the axis with the largest magnitude, we can set our forward vector to match:\nfunc _physics_process(_delta): var forward = Vector3.FORWARD if camera: forward = Vector3.ZERO var cam_forward = -camera.transform.basis.z.normalized() var cam_axis = cam_forward.abs().max_axis() forward[cam_axis] = sign(cam_forward[cam_axis]) if Input.is_action_pressed(\"up\"): roll(forward) if Input.is_action_pressed(\"down\"): roll(-forward) if Input.is_action_pressed(\"right\"): roll(forward.cross(Vector3.UP)) if Input.is_action_pressed(\"left\"): roll(-forward.cross(Vector3.UP)) In this clip, I’m only pressing “w” to move:\nRelated recipes Rolling Cube Camera Gimbal Like video? ","description":"","tags":null,"title":"Align Movement with Camera","uri":"/godot_recipes/4.x/3d/move_with_camera/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":" Tip This article is being updated from Godot 3 to Godot 4.\nIn this installment, we’ll look at how to make a first-person character. We’ll use the CSG-based level we designed in the previous part as a place to walk around and test our movement.\nCharacter Scene In an FPS or similar game, we want to give the player the illusion that they’re looking out of the character’s eyes. One nice aspect of this is that we don’t really need a model, at least to get started.\nStart with a CharacterBody3D. To this we’ll add two CollisionShape nodes (“Body” and “Feet”). We also want to have a Camera, but we need to be careful about how we handle rotation. The character should rotate in Y, but only the camera should rotate in X (for looking up and down). To make this work, add a Node3D node, which we’ll call “Pivot”, and add the Camera to that.\nThe “Body” collision shape is going to represent the player’s body. We can use a CapsuleShape (rotated 90 degrees around X). Set its Radius to 0.5 and Height to 1.\nOne issue with using a CapsuleShape is that the bottom is rounded. This is good for moving over small bumps in a natural way, but it also means that when standing on the edge of a surface, the player will “roll” off in a strange way. We can prevent this by using a BoxShape for the “Feet” collision. Make its extents (.4, .1, .4) and place it so that its bottom is just above the bottom of the capsule. We’ll still have the round bottom to move over things, but the box will keep us from sliding off ledges.\nMove the Pivot up a bit, so that it’s not pointing the camera out of the “middle” of the body.\nMoving around Much of the code for movement is the same as we used for the third-person character earlier in this series. We’ll start with declaring our variables:\nextends CharacterBody3D @onready var camera = $Pivot/Camera var gravity = -30 var max_speed = 8 var mouse_sensitivity = 0.002 # radians/pixel var velocity = Vector3() Note The value of mouse_sensitivity maps the movement of the mouse, which is in pixels, to rotation, in degrees. So for each pixel the mouse moves, we’ll rotate by 0.002 radians (or about 0.1 degrees).\nfunc get_input(): var input_dir = Vector3() # desired move in camera direction if Input.is_action_pressed(\"move_forward\"): input_dir += -global_transform.basis.z if Input.is_action_pressed(\"move_back\"): input_dir += global_transform.basis.z if Input.is_action_pressed(\"strafe_left\"): input_dir += -global_transform.basis.x if Input.is_action_pressed(\"strafe_right\"): input_dir += global_transform.basis.x input_dir = input_dir.normalized() return input_dir When detecting input, we want to move in the direction the body is facing.\nNext, we add up the inputs and return the resulting direction vector.\nfunc _unhandled_input(event): if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: rotate_y(-event.relative.x * mouse_sensitivity) $Pivot.rotate_x(-event.relative.y * mouse_sensitivity) $Pivot.rotation.x = clamp($Pivot.rotation.x, -1.2, 1.2) We also need to capture mouse movement for camera rotation. As discussed above, horizontal mouse movement rotates the entire body in Y, while vertical motion rotates the helper node in X.\nWe also need to limit that vertical rotation to prevent the camera from flipping upside-down.\nfunc _physics_process(delta): velocity.y += gravity * delta var desired_velocity = get_input() * max_speed velocity.x = desired_velocity.x velocity.z = desired_velocity.z velocity = move_and_slide(velocity, Vector3.UP, true) In _physics_process() we get the desired_velocity, the direction vector returned by get_input(), and multiply it by max_speed to set its length. We don’t want to alter our velocity.y because that’s set by gravity, so we only set the x and z components based on the input.\nWe’re also setting true for the stop_on_slope parameter of move_and_slide(). This keeps us from sliding down the ramp if we stand on it.\nTest your movement and ensure everything is working as expected.\nAdding a weapon First person characters typically have some sort of item, or at least empty hands, visible in front of them. We’re going to use the shotgun model from the following art pack:\nKenney Weapon Pack\nAddd a MeshInstance to the Pivot node and use the shotgun.obj model from the art pack. You’ll notice that the model is too small for our player’s scale, so set Scale to (8, 8, 8).\nWe need to position the model so that it’s projecting out “through” the camera. Aligning it can be difficult, so click the “View” menu and choose “2 Viewports”. In the bottom one, select the Camera and click “Preview”, and in the top you can move the gun until it looks right.\nWrapping up We now have a basic first-person character controller. This could make a good foundation for a wide variety of game types by adding features and behaviors, as we’ll see in later lessons.\nYou can also find a video version of this lesson here: ","description":"","tags":null,"title":"First-person Character","uri":"/godot_recipes/4.x/g101/3d/101_3d_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":"Fixing a bug Our first task is to fix a bug with our menu system. Pressing the “Start” button launches a new game, but as the screen is moving off, it can be pressed again. Try “spamming” the start button - disaster ensues!\nWe can fix this by disabling the buttons while the screen transition is happening. Since we put all the buttons in a “buttons” group, we can easily do this with call_group().\nHere’s the updated BaseScreen.gd:\nextends CanvasLayer @onready var tween = $Tween func appear(): get_tree().call_group(\"buttons\", \"set_disabled\", false) tween.interpolate_property(self, \"offset:x\", 500, 0, 0.5, Tween.TRANS_BACK, Tween.EASE_IN_OUT) tween.start() func disappear(): get_tree().call_group(\"buttons\", \"set_disabled\", true) tween.interpolate_property(self, \"offset:x\", 0, 500, 0.5, Tween.TRANS_BACK, Tween.EASE_IN_OUT) tween.start() Score and level As our score increases, we’ll want the game’s difficulty to increase as well. This means that when we get points, we’ll need to check if we’ve passed a certain threshold (circles_per_level). We may also have other things that give us points besides jumping on a circle. To make this easier to handle, we’ll give our score variable a setget method in the main script:\nvar score = 0 setget set_score var level = 0 And update the new_game() to use that method:\nfunc new_game(): self.score = 0 level = 1 Do the same with the score change in _on_Jumper_captured(), and we’ll move the HUD update into our new set_score() method:\nfunc _on_Jumper_captured(object): $Camera2D.position = object.position object.capture(player) call_deferred(\"spawn_circle\") self.score += 1 func set_score(value): score = value $HUD.update_score(score) if score \u003e 0 and score % settings.circles_per_level == 0: level += 1 $HUD.show_message(\"Level %s\" % str(level)) Try the game and you should see a “Level 2” message on the screen when you reach five points.\nMoving circles Part of the level progression is going to be increased difficulty. One way we’ll do that is by making some circles move. We already have multiple circle types (static and limited), but either of those should be capable of moving, so this won’t be a new circle type. Instead, it will be a property that any circle can have.\nOpen up the Circle scene and add a Tween node called “MoveTween”. Add this to the top of the circle script:\n@onready var move_tween = $MoveTween var move_range = 100 # Distance the circle moves. var move_speed = 1.0 # The circle's movement speed. If move_range is 0, we’ll have a non-moving circle. We’ll make the default 100 here so that we can test it out.\nTo handle the movement, we’ll start the MoveTween. When it ends, we’ll start it again in the opposite direction, using the tween_completed signal.\nThis is the code to start the movement. Connect the tween_completed signal to this function:\nfunc set_tween(object=null, key=null): if move_range == 0: return move_range *= -1 move_tween.interpolate_property(self, \"position:x\", position.x, position.x + move_range, move_speed, Tween.TRANS_QUAD, Tween.EASE_IN_OUT) move_tween.start() Finally, we’ll add set_tween() to the end of the init() function and we can try it out.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Moving circles","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_07/index.html"},{"content":" Shaders Deep voodoo. Cool effects.\nIn this section: Shaders: intro Interacting with Shaders Greyscale (monochrome) shader Blur shader ","description":"","tags":null,"title":"Shaders","uri":"/godot_recipes/4.x/shaders/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’d like to understand Godot’s Joint2D nodes.\nSolution Joint are used to constrain the movement of attached physics objects. For any joint node, you need to attach two bodies, which must extend from PhysicsObject2D.\nProperties These properties are common to all joint nodes:\nNode A and Node B: The assigned physics bodies. Bias: The rate at which the joint pulls the two bodies back together if they move apart. Defaults to 0. Disable Collisions: Allows the connected bodies to ignore collisions between them. Defaults to true. There are three types of Joint2D. In all of the following examples, there is one RigidBody2D connected via a joint to a StaticBody2D. “Visible Collision Shapes” is enabled in the screen images below so you can see a representation of the joint.\nPinJoint2D The “pin” joint attaches the two bodies at a single point, allowing them to freely rotate.\nThe pin joint’s Softness property gives some “springiness” to the connection. The value can range from 0 (the default) which allows no movement, to 16.\nDampedSpringJoint2D This joint connects the two bodies with a spring-like force.\nThe spring’s behavior can be adjusted with these properties:\nLength: The joint’s maximum length. Rest Length:The joint’s length when no forces or movement are applied. Stiffness: The spring’s “stretchiness”, i.e. how much it resists forces pulling against it. Damping: How quickly the spring stops “bouncing”. GrooveJoint2D This joint constrains the attached bodies to move linearly.\nBy default, the groove runs vertically, but you can change this by rotating the groove node.\nThese properties control the groove’s behavior:\nLength: The groove’s length. The attached bodies can’t move past this maximum distance. Initial Offset: Starting “position” along the groove. Related Recipes ","description":"","tags":null,"title":"Using 2D Joints","uri":"/godot_recipes/4.x/physics/joints_2d/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to make a conveyor belt object that will move bodies (kinematic or rigid).\nSolution You can make a conveyor belt object using nothing but a StaticBody2D by using its constant_linear_velocity property.\nNote See below for how to address this in 3D.\nHere’s an example, using a StaticBody2D and a RigidBody2D. No code was added. The static body’s Constant Linear Velocity is set to (200, 0).\nAnimating the belt There are many ways to present the appearance of your conveyor belt, depending on your art assets. For this demo project, I have only a TileMap which is using this single 88x88 tile:\nAdd a Sprite to your static body, and in its Texture choose “New AtlasTexture”:\nDrop the tile texture in its Texture property and set the Region to (0, 0, 880, 88):\nChoosing 880 gives us a conveyor belt that’s exactly 10 tiles wide. You can use any width you need.\nTip If your image doesn’t repeat or looks wrong, reimport it with the Repeat flag set to “Enabled”.\nTry adjusting the x of the Region property. You’ll see the tiles shift. This is what we need to animate the belt. You can do this with an AnimationPlayer or in code. We’ll do the latter for this example:\nextends StaticBody2D @export var speed = 100 func _ready(): constant_linear_velocity.x = speed func _process(delta): $Sprite.texture.region.position.x -= speed * delta This code ensures that our belt moves at the desired speed, and that the animation matches the physics effect. Note that the directions are opposite: increasing the x of the region shifts the image to the left.\nThis works perfectly well with kinematic bodies, too. Here’s the same conveyor belt object added to our Platform character recipe:\n3D At the time of this writing, constant_linear_velocity does not work in 3D using StaticBody.\nHowever, you can use this technique if you change from “Bullet” to the “GodotPhysics” engine in your Project Settings:\nRelated recipes Platform character Using CharacterBody2D Moving Platforms ","description":"","tags":null,"title":"Conveyor Belt","uri":"/godot_recipes/4.x/physics/conveyor_belt/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You need an AI-controlled object in your game that can follow a path, avoid obstacles, and make other decisions about how to move around the world.\nSolution “Steering behavior” is the blanket term for a variety of algorithms that you can use to solve this problem. Which one you choose will depend on your game, the type of world the object lives in, and what type of “intelligence” you want it to have.\nIn this example, we’re going to use a method called “Context Behavior”, which aims to give the object enough information about the world to make a choice of how to move. For additional reading on this subject, see the following links:\nAndrew Fray: Context Behaviours Know How to Share\nJames Keats: AI Context Behaviors\nFor this demo, we’ll use a generic “Agent” object. In your game, this might be a car driving around a track, a monster patrolling a dungeon, or some other kind of game entity. Our agent will use a CharacterBody2D, but remember, you can use this technique with any kind of object - the algorithm is about the entity choosing a direction to move, how it moves is entirely separate.\nThe Algorithm To begin, let’s imagine our agent has a number of rays extending in all directions (we’ll talk about how many to use later - for now let’s use 8).\nIn our agent’s script, we’ll store an array called interest, tracking in which directions the agent wants to go.\nOf course, if they’re all the same, then it can’t move - it wants to go in all directions equally! So lets consider that it has a preference - it mostly wants to go forward:\nIn this case, the interest array would look like this:\nThe strongest desire is to go forward, but forward-left and forward-right are acceptible as well. But what if an obstacle appears?\nNow we’ll introduce a second array, danger, that indicates directions that are not preferred.\nCombining these two arrays, we can eliminate any interest directions that are also contained in danger. By summing up the remaining interest directions, we’re left with a new direction pointing away from the obstacle.\nTo summarize:\nFind the object’s interest directions. Find the directions that contain danger. Eliminate any interest directions that are dangerous. Sum the remaining interest directions to find the new heading. Finding Interest This will vary depending on what your agent’s goal is. If it’s to chase the player, then the interest values should be high in the direction of the player. You can even have multiple targets: closer goals have higher interest, but if an obstacle cancels them out, the lower scoring goals will win.\nFor this demo, we’re going to imagine we’re making a racing game of some kind. The AI-controlled cars need to make it around the track: their interest array should be pointing forward along the track, so they don’t start going backwards.\nThere are a few ways to do this, and in order to keep our agents from needing to know the implementation details, we’ll have the track tell them which way to go based on their position. At any time if you ask the track which way is correct, it will tell you.\nThe Code Here’s the code for our agent. We start with the exported values: movement parameters and other values we want to be able to adjust easily. look_ahead, for example, is how far ahead the danger rays will detect obstacles.\nNote that we’ve made the num_rays adjustable, so that you can find the number that works best for your situation. We’ll talk below about the tradeoffs and benefits of larger numbers of rays.\nextends CharacterBody2D @export var max_speed = 350 @export var steer_force = 0.1 @export var look_ahead = 100 @export var num_rays = 8 # context array var ray_directions = [] var interest = [] var danger = [] var chosen_dir = Vector2.ZERO var velocity = Vector2.ZERO var acceleration = Vector2.ZERO Next, we have _ready() where we size the arrays properly and populate the ray_directions array with the actual ray vectors, distributing them evenly around the circle based on num_rays. We begin with no rotation, so Vector2.RIGHT is forward.\nfunc _ready(): interest.resize(num_rays) danger.resize(num_rays) ray_directions.resize(num_rays) for i in num_rays: var angle = i * 2 * PI / num_rays ray_directions[i] = Vector2.RIGHT.rotated(angle) In _physics_process() we’ll populate the context arrays and execute the movement. Note we’ve broken the steps of the algorithm in to separate functions. Once we’ve found our chosen direction, we turn towards it as much as possible (based on steer_force) and move.\nfunc _physics_process(delta): set_interest() set_danger() choose_direction() var desired_velocity = chosen_dir.rotated(rotation) * max_speed velocity = velocity.linear_interpolate(desired_velocity, steer_force) rotation = velocity.angle() move_and_collide(velocity * delta) Now we’ll go over the 3 functions that make up the algorithm. first, setting the interest array. As mentioned above, we’re going to ask the world (our owner in this case) to tell us which direction we should be trying to go.\nUsing each ray direction, we take the dot product with the given path direction. Recall that the dot product of two aligned vectors is 1 and for two perpendicular vectors it’s 0. We ignore negative values - 0 means we don’t want to go that way.\nFor example, with 32 rays, the interest would look like this:\nAs a safety measure, if there’s no owner to tell us a direction, we’ll default to trying to go forward.\nfunc set_interest(): # Set interest in each slot based on world direction if owner and owner.has_method(\"get_path_direction\"): var path_direction = owner.get_path_direction(position) for i in num_rays: var d = ray_directions[i].rotated(rotation).dot(path_direction) interest[i] = max(0, d) # If no world path, use default interest else: set_default_interest() func set_default_interest(): # Default to moving forward for i in num_rays: var d = ray_directions[i].rotated(rotation).dot(transform.x) interest[i] = max(0, d) Now we can populate the danger array. Using the Physics2DDirectSpaceState, we cast a ray in each direction. If there’s a hit, we add a 1 in that spot.\nfunc set_danger(): # Cast rays to find danger directions var space_state = get_world_2d().direct_space_state for i in num_rays: var result = space_state.intersect_ray(position, position + ray_directions[i].rotated(rotation) * look_ahead, [self]) danger[i] = 1.0 if result else 0.0 Finally, we can use the context arrays to choose our direction. Looping through the danger array, zero the interest wherever there’s danger. Then, sum up and normalize the remaining interest vectors.\nfunc choose_direction(): # Eliminate interest in slots with danger for i in num_rays: if danger[i] \u003e 0.0: interest[i] = 0.0 # Choose direction based on remaining interest chosen_dir = Vector2.ZERO for i in num_rays: chosen_dir += ray_directions[i] * interest[i] chosen_dir = chosen_dir.normalized() Example in Practice Let’s try it out in action! Here, we’ve created a track using a Path2D and some collision polygons.\nIn the script for this scene, we have a get_path_direction() function. Given a position, this function finds the closest point on the path and puts the PathFollow2D there in order to find the forward direction.\nfunc get_path_direction(pos): var offset = path.curve.get_closest_offset(pos) path_follow.offset = offset return path_follow.transform.x We’ve randomized the speeds of the agents do get some variety. Notice how the fast one finds ways to dodge around the slow ones.\nWrapping up This method is very flexible and can be extended to produce a wide variety of complex-looking behaviors. It\nHere are some additional suggestions for adaptations/improvements:\nLevels of danger When populating the danger array, don’t just use 0 or 1, but instead calculate a danger “score” based on the distance of the object. Then subtract that amount from the interest rather than removing it. Far away objects will have a small impact while close ones will have more.\nAvoidance Rather than a danger item canceling the interest, it could add to the interest in the opposite direction.\nRelated recipes Vectors: Using Dot and Cross Product Like video? ","description":"","tags":null,"title":"Context-based steering","uri":"/godot_recipes/4.x/ai/context_map/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’d like visual debug information in your 3D game: a way to see vectors representing velocity, position, etc.\nSolution Debug drawing in 2D is quite convenient. CanvasItem provides a range of primitive drawing methods to use in the _draw() callback. In 3D, things are not quite so simple. One solution is to use ImmediateGeometry to manually create meshes, but this is very cumbersome and inconvenient for quick debugging.\nA better solution is to stick with the CanvasItem draw methods. To do so, we need to project the positions in 3D space onto the 2D viewport. Fortunately, Camera can do this for us using its unproject_position() method.\nSetting up For the display layer, add a CanvasLayer containing a Control to your 3D scene and add a script to the Control.\nAs an example, let’s assume this drawing control has a reference to the player node, and we want to draw the node’s velocity vector. We also have a reference to the Camera node. More about how we’ll add those references later.\nvar player var camera func _draw(): var color = Color(0, 1, 0) var start = camera.unproject_position(player.global_transform.origin) var end = camera.unproject_position(player.global_transform.origin + player.velocity) node.draw_line(start, end, color, width) node.draw_triangle(end, start.direction_to(end), width*2, color) func draw_triangle(pos, dir, size, color): var a = pos + dir * size var b = pos + dir.rotated(2*PI/3) * size var c = pos + dir.rotated(4*PI/3) * size var points = PoolVector2Array([a, b, c]) draw_polygon(points, PoolColorArray([color])) We use unproject_position() to find the start and end points of the vector we want to draw. draw_triangle() is there to give us a nice pointed arrow appearance.\nEasy access from game objects Now let’s make this more functional. Your game might have many objects you want to draw debug vectors for. An enemy’s facing direction, an acceleration vector, a destination, etc. We need an easy way to register any object to the debug drawing layer.\nAdd the DebugOverlay as an autoload and set it as a singleton. This way we can access it from any node. Add this script to it:\nextends CanvasLayer @onready var draw = $DebugDraw3D func _ready(): if not InputMap.has_action(\"toggle_debug\"): InputMap.add_action(\"toggle_debug\") var ev = InputEventKey.new() ev.scancode = KEY_BACKSLASH InputMap.action_add_event(\"toggle_debug\", ev) func _input(event): if event.is_action_pressed(\"toggle_debug\"): for n in get_children(): n.visible = not n.visible I’ve included the code to add an input action to toggle visibility. This makes it convenient to drop this into any project without needing to edit the Input Map. We can now reference the drawing layer with DebugOverlay.draw.\nNote You can add other debug layers here too. For example, one that displays properties as text.\nWe’ll start by defining a custom object to hold all the information for the debug value we want to display.\nextends Control class Vector: var object # The node to follow var property # The property to draw var scale # Scale factor var width # Line width var color # Draw color func _init(_object, _property, _scale, _width, _color): object = _object value = _property scale = _scale width = _width color = _color func draw(node, camera): var start = camera.unproject_position(object.global_transform.origin) var end = camera.unproject_position(object.global_transform.origin + object.get(property) * scale) node.draw_line(start, end, color, width) node.draw_triangle(end, start.direction_to(end), width*2, color) var vectors = [] # Array to hold all registered values. This object encapsulates all the functionality for each vector we want to display, including the drawing code we saw earlier. In _process(), we can then draw them, making sure to get the current active camera:\nfunc _process(delta): if not visible: return update() func _draw(): var camera = get_viewport().get_camera() for vector in vectors: vector.draw(self, camera) And finally, we can add a function to register a new vector to follow:\nfunc add_vector(object, property, scale, width, color): vectors.append(Vector.new(object, property, scale, width, color)) Now any object in the game can add a debug vector with the following:\nDebugOverlay.draw.add_vector(self, \"velocity\", 1, 4, Color(0,1,0, 0.5)) Here’s an example of an AI car displaying its raycasts and steering direction:\nRelated recipes UI: Displaying debug data ","description":"","tags":null,"title":"Drawing Vectors in 3D","uri":"/godot_recipes/4.x/3d/debug_overlay/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You’re looking for a way to handle data and/or create flexible data objects in your game.\nSolution Godot’s Resource class is a powerful tool for storing and working with data. Many of the most common objects you work with in Godot extend the Resource type: animations, collision shapes, images, etc. Resources not only contain data, but can also manipulate that data (if you’re familiar with the concept of scriptable objects in Unity, the concept is similar).\nIn addition to all of Godot’s built-in Resource types, you can create your own custom resources to handle your own game data. This has the benefit of abstracting and encapsulating data - creating something that can be used by any other object in your game.\nExample: Player health For this example, we’ll take the concept of player health in a platformer game. A lot of game systems interact with the player’s health. For example:\nThe player may take damage when running into obstacles Enemies can damage the player when touching or shooting them The player can heal when picking up objects or standing in certain places The game’s UI needs to display the health and any changes that happen In addition, there may be other interactions: maybe the game’s soundtrack changes as the player’s health gets low, or enemy behavior changes based on the player’s status.\nNote This is an intentionally simplified example. In practice, you’ll probably need more functionality than we use here, or you’ll want to modify the example to fit with your game’s architecture.\nFirst, we need to define our new custom resource, which we’ll call PlayerHealth. This resource needs to keep track of properties related to health. It also provides some functionality and signals to handle the changing of the health amount (such as healing and taking damage).\nIn the Script tab, choose File\u003eNew Script. Make sure it inherits Resource and name it PlayerHealth.gd.\nLet’s break it down piece-by-piece:\nAt the top we have our extends line and the class_name we’re assigning to the resource. This name will appear in various places in the editor.\nextends Resource class_name PlayerHealth Next we have a signal that game objects can subscribe to if they need to know when the player’s health changes. You could also add additional signals for the health reaching zero, etc.\nsignal health_changed These are the properties we’ll be using.\n@export var max_value: int var current_value = 0 This function lets us initialize the health to the max value. You might do this at game restart or when starting a new level.\nfunc reset(): current_value = max_value This function should be called whenever damage is dealt to the player.\nfunc take_damage(amount): current_value = max(0, current_value - amount) emit_signal(\"health_changed\", current_value) This function should be called whenever the player needs to be healed.\nfunc heal(amount): current_value = min(max_value, current_value + amount) emit_signal(\"health_changed\", current_value) Here’s the full script:\nextends Resource class_name PlayerHealth signal health_empty signal health_changed @export var max_value: int var current_value = 0 func reset(): current_value = max_value func take_damage(amount): current_value = max(0, current_value - amount) emit_signal(\"health_changed\", current_value) func heal(amount): current_value = min(max_value, current_value + amount) emit_signal(\"health_changed\", current_value) Creating a new resource Once the PlayerHealth class is defined, we can make a new instance of it. Click the “New Resource” button at the top of the Inspector:\nIn the “Create New Resource” dialog you’ll see the long list of resource types. Searching will locate our PlayerHealth type.\nNow you can set the desired max_value and save the new resource as a .tres file.\nUsing the resource Once the resource has been created and saved, we’re ready to use it. Once again, in this scenario we have the following objects:\nPlayer - a CharacterBody2D UI - contains a ProgressTexture to display health Heal zone - an Area2D that heals anything that stands in it Spikes - TileMap tiles that cause damage if touched We won’t include all of the code for the game, just the parts that pertain to the health resource.\nOn the player, we export a variable to attach the resource via the Inspector. As part of the player’s movement code, it calls hurt() when the player runs into spikes.\n@export var health: Resource func _ready(): health.reset() func hurt(amount): # Called when running into obstacles health.take_damage(amount) The heal zone (an Area2D), affects anything inside it that has a health property:\nfunc _physics_process(delta): for body in get_overlapping_bodies(): if \"health\" in body: body.health.heal(heal_rate * delta) Finally, for the UI to display the health, we attach the same health resource and connect to its health_changed signal:\n@export var player_health: Resource func _ready(): if player_health: player_health.health_changed.connect(_on_player_health_changed) func _on_player_health_changed(value): healthbar.value = float(value) / player_health.max_value * 100 Here’s an example of it in action:\nNote Download the project file here: custom_resources.zip\nRelated recipes Platform character Object healthbars ","description":"","tags":null,"title":"Using Custom Resources","uri":"/godot_recipes/4.x/basics/custom_resources/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nAbout ads When building a free-to-play mobile game, you have two choices when it comes to monetization: in-app purchases and advertisement. In this part, we’ll look at how to integrate a mobile ad platform (Admob) into your game.\nAds can be unpopular and whether to use them is a decision for the individual game developer to make. We’re not making a decision on the pros and cons in this tutorial - we’re here to show you how to put ads in your game if you want them.\nSet up Admob Head over to Admob and create an account.\nIn the AdMob manager, create a new app - ours is titled “Circle Jump” - and specify the “Android” platform (we’ll discuss iOS later).\nIn the “Circle Jump” app, you’ll need to create three “Ad Units”. These are the types of ads that you can show in your game. For this tutorial, we’ll need a “Banner” and an “Interstitial”. Each ad unit will have an “Ad Unit ID”, a long string of characters - we’ll need that later in the game.\nUsing Godot modules Godot doesn’t include ad services by default, so it’s necessary to use an engine module, or plugin, to add that functionality. You can find the module we’ll be using here: godot-admob. On that page, you’ll see a list of the methods provided by the plugin.\nTo use a custom engine module, the engine has to be recompiled. In the case of mobile platforms, that means recompiling the export templates because the default ones we downloaded from Godot weren’t compiled with this module.\nCompiling export templates is not difficult, but it does require setting up a build environment on your computer - downloading the required programs and libraries needed to build Godot. If you’re new to this concept and interested in learning about it, see the Compiling section of the official docs.\nFortunately, we won’t need to compile custom export templates, because it’s already been done for us. Head over to the godot-custom-mobile-templates Github repo. Click on “Releases” and download the version of the export templates that matches your version of Godot.\nWarning The export template version must match the Godot editor version. If you’re using a custom-built editor, you will also have to build the templates from the same code branch.\nUnzip the templates somewhere on your computer (don’t put them in the Circle Jump project folder).\nConfiguring export Back in the Godot editor, we need to make some changes to the export configuration. First, open Project -\u003e Project Settings and find the “Android” section. In the Modules property is where you list the module(s) you want to use in your code. The module name is listed on the godot-admob page: “org/godotengine/godot/GodotAdMob”. If you have more than one module, separate them with commas.\nIn the _Project -\u003e Export_menu, we need to tell Godot to use the custom templates we downloaded. These are set in the “Custom Package” section. Click the folder icon and navigate to where you unzipped the templates. Make sure to add both the “Debug” and “Release” templates.\nCode Now when we run the game (on Android), it will load that module. It’s accessed via an engine singleton. Open settings.gd and add the following:\nvar admob = null var real_ads = false var banner_top = false # Fill these from your AdMob account: var ad_banner_id = \"\" var ad_interstitial_id = \"\" var enable_ads = true These are our settings variables for the module. real_ads set to false puts us in “Test Ad” mode. You shouldn’t change this to true until you’re ready to release your game. banner_top toggles whether the banner ad should be shown at the top or bottom of the screen.\nad_banner_id and ad_interstitial_id should be filled with your ad unit values from your AdMob account.\nWe need to initialize the module:\nfunc _ready(): if Engine.has_singleton(\"AdMob\"): admob = Engine.get_singleton(\"AdMob\") admob.init(real_ads, get_instance_id()) admob.loadBanner(ad_banner_id, banner_top) admob.loadInterstitial(ad_interstitial_id) We first check that the module singleton exists. If it’s found, we can initialize the module and load the ad units.\nfunc show_ad_banner(): if admob and enable_ads: admob.showBanner() func hide_ad_banner(): if admob: admob.hideBanner() Next, we have functions to let us show/hide the banner. We only want it showing in the menu screens, not during actual gameplay.\nfunc show_ad_interstitial(): if admob and enable_ads: admob.showInterstitial() We’ll use this function to show the interstitial ad at the end of a game.\nfunc _on_interstitial_close(): if admob and enable_ads: show_ad_banner() The module looks for this callback to run any code when the interstitial ad closes. Since we’ll be at the end of a game and going back to the menu, we’ll show the banner again.\nNow we need to call these functions from the game. Open Main.gd and add the following:\nIn new_game(), add settings.hide_ad_banner(). At the end of _on_Jumper_died() add settings.show_ad_interstitial(). Run the game on your device, and you should see the test ad appear:\nDisabling ads Many games allow ads to be disabled, whether via in-app purchases, reaching a certain level, etc. In our case, we’ll add it as a button on the “Settings” screen.\nFirst, we’ll change the enable_ads to give it a setter function:\nvar enable_ads = true setget set_enable_ads And add the setter function:\nfunc set_enable_ads(value): enable_ads = value if enable_ads: show_ad_banner() if !enable_ads: hide_ad_banner() This will cause the banner add to appear/disappear instantly when pressing the button.\nTo add the button, we’ll need a third row of buttons. Open the BaseScreen scene and duplicate the first HBoxContainer.\nIn the SettingsScreen scene add a Button called “Ads” to the middle row. Set its text to “Disable Ads”, its Custom Font (a size of 48 works well), and set its Custom Styles all to “New StyleBoxEmpty”. Don’t forget to add the button to the “buttons” group.\nIn Screens.gd, add the following to the match statement that processes the buttons:\nmatch button.name: \"Ads\": settings.enable_ads = !settings.enable_ads if settings.enable_ads: button.text = \"Disable Ads\" else: button.text = \"Enable Ads\" Run the game on your device and verify that you can enable/disable ads.\nFollow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Mobile ads","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_11/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 airplane controller in 3D, but don’t need a fully accurate flight-simulator.\nSolution In this recipe, we’re going to make a simplified airplane controller. By “simplified” we mean stripping things down to the basics. We’re looking for the “feel” of flying a plane - one that you can just jump in and start flying effortlessly, with a minimal control scheme.\nNote This recipe is not an accurate flight simulator. We are not simulating aerodynamics, so this doesn’t fly like a real airplane. We’re going for simplicity and “fun” here, not accuracy.\nNode setup We’re going to use a CharacterBody3D for this. Since we won’t be simulating actual flight physics (lift, drag, etc.), we don’t need RigidBody3D in this case.\nHere’s our model setup:\nWe’re using a cylinder for the collision shape, sized to match the plane’s fuselage. This will allow for detecting the ground, which is all we’re concerned with for this demo.\nTo start the script, let’s look at our plane’s properties:\nextends CharacterBody3D # Can't fly below this speed var min_flight_speed = 12 # Maximum airspeed var max_flight_speed = 40 # Turn rate var turn_speed = 0.75 # Climb/dive rate var pitch_speed = 0.5 # Wings \"autolevel\" speed var level_speed = 3.0 # Throttle change speed var throttle_delta = 50 # Acceleration/deceleration var acceleration = 6.0 # Current speed var forward_speed = 0 # Throttle input speed var target_speed = 0 # Lets us change behavior when grounded var grounded = false var turn_input = 0 var pitch_input = 0 Controls We’ll need the following input actions for our controls. We’re using a game controller in this demo, but you can add keyboard inputs as well if you like.\nThis function captures the inputs and sets the input values. Note that increasing/decreasing throttle changes the target_speed, not the actual speed. This will allow us to acclerate/decelerate from the current speed to the target speed.\nfunc get_input(delta): # Throttle input if Input.is_action_pressed(\"throttle_up\"): target_speed = min(forward_speed + throttle_delta * delta, max_flight_speed) if Input.is_action_pressed(\"throttle_down\"): var limit = 0 if grounded else min_flight_speed target_speed = max(forward_speed - throttle_delta * delta, limit) # Turn (roll/yaw) input turn_input = Input.get_axis(\"roll_right\", \"roll_left\") # Pitch (climb/dive) input pitch_input = Input.get_axis(\"pitch_down\", \"pitch_up\") Movement Movement happens in _physics_process(), first lerping the speed towards the target speed and then using move_and_slide():\nfunc _physics_process(delta): get_input(delta) # Accelerate/decelerate forward_speed = lerpf(forward_speed, target_speed, acceleration * delta) # Movement is always forward velocity = -transform.basis.z * forward_speed move_and_slide() To test, add the plane to a test scene (don’t forget a Camera). Press the \"throttle_up\" input and you should see the plane accelerate forward.\nTip We’re using the Interpolated Camera recipe in this demo.\nNext, let’s handle changing the pitch of the plane. Add this right after calling get_input() in _physics_process():\ntransform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) Run the scene again and try pitching up and down:\nAfter that, add the following for the turn input:\ntransform.basis = transform.basis.rotated(Vector3.UP, turn_input * turn_speed * delta) Notice that while the plane turns, it doesn’t really look natural. Airplanes bank when they turn, so let’s animate that by changing the rotation of the mesh:\nmesh.rotation.z = lerpf(mesh.rotation.z, -turn_input, level_speed * delta) Where mesh is a reference to the MeshInstance3D in the plane scene (in the example, this is $cartoon_plane).\nThe amount of roll is related to the turn_input so a shallow turn banks less. Going straight will “auto” level the plane.\nThat’s it! You now have the basic flying controls working correctly, and it should feel comfortable and natural to fly around. Try adjusting the various properties to see how they affect the movement.\nLanding/taking off While the above is fine for flying, it doesn’t handle the ground very well. Here, we’ll simulate landing using a simplistic approach (by “simplistic”, we mean doing so in a very basic way - you’ll probably want to expand on it depending on what your game may need).\nFirst, we’ll want to distinguish between being on the ground and being in the air. On the ground, we can slow down to 0; in the air, we must maintain the minimum airspeed. Also, when on the ground, we won’t bank when turning (we don’t want our wings digging into the ground!).\nfunc _physics_process(delta): get_input(delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(Vector3.UP, turn_input * turn_speed * delta) # Bank when turning if grounded: mesh.rotation.z = 0 else: mesh.rotation.z = lerpf(mesh.rotation.z, -turn_input, level_speed * delta) # Accelerate/decelerate forward_speed = lerpf(forward_speed, target_speed, acceleration * delta) # Movement is always forward velocity = -transform.basis.z * forward_speed # Landing if is_on_floor(): if not grounded: rotation.x = 0 grounded = true else: grounded = false move_and_slide() Meanwhile, in the get_input() function, we’ll also take into account grounded when throttling down and when pitching down, and only allow takeoff if above min_flight_speed:\nfunc get_input(delta): # Throttle input if Input.is_action_pressed(\"throttle_up\"): target_speed = min(forward_speed + throttle_delta * delta, max_flight_speed) if Input.is_action_pressed(\"throttle_down\"): var limit = 0 if grounded else min_flight_speed target_speed = max(forward_speed - throttle_delta * delta, limit) # Turn (roll/yaw) input turn_input = Input.get_axis(\"roll_right\", \"roll_left\") if forward_speed \u003c= 0.5: turn_input = 0 # Pitch (climb/dive) input pitch_input = 0 if not grounded: pitch_input -= Input.get_action_strength(\"pitch_down\") if forward_speed \u003e= min_flight_speed: pitch_input += Input.get_action_strength(\"pitch_up\") Full script Here’s the full script:\nClick to expand… extends CharacterBody3D # Can't fly below this speed var min_flight_speed = 12 # Maximum airspeed var max_flight_speed = 40 # Turn rate var turn_speed = 0.75 # Climb/dive rate var pitch_speed = 0.5 # Wings \"autolevel\" speed var level_speed = 3.0 # Throttle change speed var throttle_delta = 50 # Acceleration/deceleration var acceleration = 6.0 # Current speed var forward_speed = 0 # Throttle input speed var target_speed = 0 # Lets us change behavior when grounded var grounded = false var turn_input = 0 var pitch_input = 0 var tracer_scene = preload(\"res://tracer.tscn\") var can_shoot = true @onready var mesh = $cartoon_plane func _ready(): $cartoon_plane/AnimationPlayer.play(\"prop_spin\") func get_input(delta): # Throttle input if Input.is_action_pressed(\"throttle_up\"): target_speed = min(forward_speed + throttle_delta * delta, max_flight_speed) if Input.is_action_pressed(\"throttle_down\"): var limit = 0 if grounded else min_flight_speed target_speed = max(forward_speed - throttle_delta * delta, limit) # Turn (roll/yaw) input turn_input = Input.get_axis(\"roll_right\", \"roll_left\") if forward_speed \u003c= 0.5: turn_input = 0 # Pitch (climb/dive) input pitch_input = 0 if not grounded: pitch_input -= Input.get_action_strength(\"pitch_down\") if forward_speed \u003e= min_flight_speed: pitch_input += Input.get_action_strength(\"pitch_up\") #\tpitch_input = Input.get_axis(\"pitch_down\", \"pitch_up\") func _physics_process(delta): get_input(delta) transform.basis = transform.basis.rotated(transform.basis.x, pitch_input * pitch_speed * delta) transform.basis = transform.basis.rotated(Vector3.UP, turn_input * turn_speed * delta) # Bank when turning if grounded: mesh.rotation.z = 0 else: mesh.rotation.z = lerpf(mesh.rotation.z, -turn_input, level_speed * delta) # Accelerate/decelerate forward_speed = lerpf(forward_speed, target_speed, acceleration * delta) # Movement is always forward velocity = -transform.basis.z * forward_speed # Landing if is_on_floor(): if not grounded: rotation.x = 0 grounded = true else: grounded = false move_and_slide() Wrapping up You can adapt this technique to a variety of arcade-style flying games. For example, for mouse control, you could use the relative property of InputEventMouseMotion to set the pitch and turn input.\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/3d_airplane_demo\n","description":"","tags":null,"title":"Arcade-style Airplane","uri":"/godot_recipes/4.x/3d/simple_airplane/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 CharacterBody3D: 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want a 2D bullet that travels in an arc, or ballistic curve.\nSolution One approach to this problem would be to use a RigidBody2D - with its built-in physics, gravity would automatically pull it back to earth after firing it.\nHowever, as mentioned in the 2D shooting recipe, Area2D is a great choice for simple bullets and other projectiles - when you don’t need collisions, bouncing, or other physics reactions. Ballistic motion is easy enough to calculate that we won’t need the help of the physics engine.\nSetting up the bullet - Bullet (Area2D) - Sprite - CollisionShape2D We can use Area2D’s gravity property. Set it to 150 for the initial test.\nextends Area2D var velocity = Vector2(350, 0) func _process(delta): velocity.y += gravity * delta position += velocity * delta rotation = velocity.angle() func _on_BallisticBullet_body_entered(body): queue_free() Using the standard equations of motion is all we need to do here. The initial value for velocity is just for testing. Run the bullet scene:\nNow in your object that’s doing the shooting, you can instance the bullet and set its initial properties. Put this in whatever function/input handles shooting:\n@export var muzzle_velocity = 350 @export var gravity = 250 func shoot(): var b = Bullet.instantiate() owner.add_child(b) b.transform = $Barrel/Marker2D.global_transform b.velocity = b.transform.x * muzzle_velocity b.gravity = gravity Here’s an example in action:\nRelated recipes 2D shooting recipe 2D: Draw trajectory ","description":"","tags":null,"title":"Ballistic bullet","uri":"/godot_recipes/4.x/2d/ballistic_bullet/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want units to display damage as floating numbers when hit.\nSolution There are many ways to approach this problem. For example, you could use a bitmap font and build an image for each number out of its digits, then use a Sprite2D node to display and move it.\nHowever, for this recipe, we’ll use a Label node (named “FCT”). This will give us the flexibility to change the font, as well as making it easy to display the number as a string - or even other messages such as “miss”.\nAdd a LabelSettings resource and use your favorite font. In this example, we’re using “Xolonium.ttf” with a font size of 28 and a black outline of 4 pixels.\nAdd a script to the label.\nextends Label func show_value(value, travel, duration, spread, crit=false): When we spawn the floating text, we’ll call this function to set the parameters:\nvalue - the number (or string) to display travel - a Vector2 representing the direction of travel duration - how long the text will last spread - movement will be randomly spread across this arc crit - if true, indicates the damage was a “critical” hit Here’s what the function does:\ntext = value var movement = travel.rotated(rand_range(-spread/2, spread/2)) rect_pivot_offset = rect_size / 2 First, assign the value and randomize the movement based on the given spread (+/-90 degrees, for example). Since we may also be animating the scale, we set the rect_pivot_offset to the center of the control so that it will scale from the center.\n$Tween.interpolate_property(self, \"rect_position\", rect_position, rect_position + movement, duration, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) $Tween.interpolate_property(self, \"modulate:a\", 1.0, 0.0, duration, Tween.TRANS_LINEAR, Tween.EASE_IN_OUT) Next, we have two properties to interpolate: rect_position for the movement and modulate.a for the visibility.\nif crit: modulate = Color(1, 0, 0) $Tween.interpolate_property(self, \"rect_scale\", rect_scale*2, rect_scale, 0.4, Tween.TRANS_BACK, Tween.EASE_IN) If the hit is a critical, we’ll also change the color and animate the scale for a bigger effect. Note, I’ve hardcoded this to be red, but you should probably make this a configurable value.\n$Tween.start() yield($Tween, \"tween_all_completed\") queue_free() Finally, we start the Tween and wait for it to finish, then remove the Label.\nFloating text manager Next we’ll crate a small node to manage placing and spawning the floating text. This node will be attached to the game entities that you want to display floating text effects.\nThis is a Node2D named “FCTManager”. It contains the following script:\nextends Node2D var FCT = preload(\"res://FCT.tscn\") @export var travel = Vector2(0, -80) @export var duration = 2 @export var spread = PI/2 func show_value(value, crit=false): var fct = FCT.instantiate() add_child(fct) fct.show_value(str(value), travel, duration, spread, crit) Here you can expose the settings to the Inspector for convenient changes. The show_value() method here spawns the floating labels and sets their properties.\nIn your game unit, you’d attach an instance of this node, and position it wherever you want the text to appear. Then add something like the following to the unit’s take_damage() method:\n$FCTManager.show_value(dmg, crit) Wrapping up Optimization: in the case where you have a very large number of enemies/bullets, you may experience some performance impact from repeatedly spawning and freeing floating text. In this case, you can spawn a fixed number of text objects in the manager, and show/hide them rather than freeing them at the end of the animation.\nNote Art in this demo by Luis Zuno\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/floating_combat_text\n","description":"","tags":null,"title":"Floating combat text","uri":"/godot_recipes/4.x/ui/floating_text/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem 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 to have collisions with a Line2D.\nSolution Node setup Add the following nodes to your scene, and draw your line as desired:\nLine2D StaticBody2D Don’t add a collision shape to the body yet!\nNote You can use an Area2D instead if you want to detect overlap with the line rather than collision.\nNext, we need to add collision shapes to the body. We have two options:\nOption 1: Using SegmentShape2D SegmentShape2D is a line-segment collision shape. The idea here is to create a segment collision for each pair of points in the line.\nextends Line2D func _ready(): for i in points.size() - 1: var new_shape = CollisionShape2D.new() $StaticBody2D.add_child(new_shape) var segment = SegmentShape2D.new() segment.a = points[i] segment.b = points[i + 1] new_shape.shape = segment Option 2: Using RectangleShape2D SegmentShape2D does not have any width component, so if you need your line collision to have a thickness, you can use a rectangle collision instead.\nextends Line2D func _ready(): for i in points.size() - 1: var new_shape = CollisionShape2D.new() $StaticBody2D.add_child(new_shape) var rect = RectangleShape2D.new() new_shape.position = (points[i] + points[i + 1]) / 2 new_shape.rotation = points[i].direction_to(points[i + 1]).angle() var length = points[i].distance_to(points[i + 1]) rect.extents = Vector2(length / 2, width / 2) new_shape.shape = rect Download This Project Download the project’s example code here: https://github.com/godotrecipes/line2d_collision\n","description":"","tags":null,"title":"Line2D Collision","uri":"/godot_recipes/4.x/2d/line_collision/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":" Tip This article is being updated from Godot 3 to Godot 4.\nSaving settings We’ve added three toggle properties in the game - which works fine - but the settings aren’t preserved when we quit. We need to save those settings so the next time you run the game, they persist.\nFirst, we’ll define our settings file in res://settings.gd:\nvar settings_file = \"user://settings.save\" Next, we’ll add saving/loading functions for the three game settings that we want to save.\nfunc save_settings(): var f = File.new() f.open(settings_file, File.WRITE) f.store_var(enable_sound) f.store_var(enable_music) f.store_var(enable_ads) f.close() func load_settings(): var f = File.new() if f.file_exists(settings_file): f.open(settings_file, File.READ) enable_sound = f.get_var() enable_music = f.get_var() self.enable_ads = f.get_var() f.close() Call load_settings() in _ready() and save_settings() at the end of set_enable_ads(). Also, in Screens.gd we need to save the state when the sound/music settings change, so add settings.save_settings() in each of those parts of the match statement.\nAnother problem we’ll have is when the game starts, the icons in the settings menu won’t reflect the state that we just loaded from the save file. We can set that in register_buttons() which is already looping through all buttons to connect their signals:\nfor button in buttons: button.connect(\"pressed\", self, \"_on_button_pressed\", [button]) match button.name: \"Ads\": if settings.enable_ads: button.text = \"Disable Ads\" else: button.text = \"Enable Ads\" \"Sound\": button.texture_normal = sound_buttons[settings.enable_sound] \"Music\": button.texture_normal = music_buttons[settings.enable_music] About screen The other thing we’ll add in this part is an “About” screen. This is where we’ll let the player know what the game’s all about and link to its license and to this page, since it is a tutorial game.\nWarning Complying with license terms is very important. You can find out what’s required by Godot here: Complying with Licenses. Note that the art you’re using may also require credit, links, or other acknowledgement.\nTo reach it, we’ve added a new button on the “Title” screen:\nThe button is setup just like the others - add it to the “buttons” group so that it will get registered. In the Screens.gd, add another match for this button’s name:\n\"About\": change_screen($AboutScreen) Here’s what the “About” screen looks like:\nExtending “BaseScreen.tscn”, we’ve added a TextEdit and another container for a single “Home” button.\nIn the TextEdit, set BBCode enabled and put the following in the Text property:\n[center][u]Circle Jump[/u] [img]res://assets/images/godot_logo.png[/img][/center] Circle Jump is an open source tutorial game made with the Godot Game Engine. You can find the tutorial and the game's source code here: [url=https://github.com/kidscancode/circle_jump]Circle Jump Source[/url] Copyright © 2019 KidsCanCode [url=https://github.com/kidscancode/circle_jump/blob/master/LICENSE]License Information[/url] Note See BBCode in RichTextLabel for details on how BBCode formatting works.\nTo allow clicking on URLs, connect the meta_clicked signal of the TextEdit:\nfunc _on_TextEdit_meta_clicked(meta): OS.shell_open(meta) Follow this project on Github: https://github.com/kidscancode/circle_jump\nDo you prefer video? ","description":"","tags":null,"title":"Saving settings","uri":"/godot_recipes/4.x/games/circle_jump/circle_jump_12/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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You need a touch-controlled 2D camera for your mobile game.\nSolution In this recipe, we’ll create a generic 2D camera with multiple touch controls:\nDrag to pan Pinch to zoom Setup Our camera will extend the built-in node, so add a Camera2D to a new scene and name it “TouchCamera”. Save and attach a script.\nHere are the variables we’ll need:\nextends Camera2D @export var target: NodePath # Optional: export these properties for convenient editing. var target_return_enabled = true var target_return_rate = 0.02 var min_zoom = 0.5 var max_zoom = 2 var zoom_sensitivity = 10 var zoom_speed = 0.05 var events = {} var last_drag_distance = 0 If a target is assigned, then the camera can follow and/or automatically return to it. The other properties that control how the camera works:\ntarget_return_enabled - If this is true, the camera will automatically return to the target after dragging. target_return_rate - Controls how fast the camera returns to its target. min_zoom / max_zoom - Limits how far you can zoom in/out. zoom_sensitivity - Sets how sensitive pinch-to-zoom will be - it’s the number of pixels’ movement needed to “start” a zoom. zoom_speed - Used to smooth the zooming. You can export these properties as well, if you’d like to be able to adjust them in the Inspector.\nThe other variables track the state of the camera. events is a dictionary that will hold the active touchscreen events, using the event’s index as its key. last_drag_distance keeps track of the distance between the two drag events in a “pinch” gesture.\nIn the _process() function, we’ll move the camera towards the target (if target return is enabled and there’s no touch event active).\nfunc _process(delta): if target and target_return_enabled and events.size() == 0: position = lerp(position, get_node(target).position, target_return_rate) This will allow us to pan the camera around and it will return to the player when we release the touch.\nNow we’re ready to start adding the gestures, starting with “pan”.\nPan Note You can test this gesture your computer by enabling “Emulate Touch From Mouse” in Project Settings -\u003e Input Devices -\u003e Pointing.\nJust like mouse or keyboard events, touch events extend InputEvent and follow the same input priority. We’ll use _unhandled_input() for processing so that other nodes, such as Control nodes, can process events first:\nfunc _unhandled_input(event): if event is InputEventScreenTouch: if event.pressed: events[event.index] = event else: events.erase(event.index) First we’re checking for a touch event (InputEventScreenTouch). We add the event to the events dictionary. The event’s index property is our dictionary’s key. We also remove the event if it’s not pressed, which means the touch has ended.\nNext, we need to handle a drag that comes after the touch:\nif event is InputEventScreenDrag: events[event.index] = event if events.size() == 1: position += event.relative.rotated(rotation) * zoom.x If we get a drag event, we also add to the dictionary. Note that this will be updating the value - index 0 was already there from the first touch event, for example, and has now become a drag event.\nIf there’s only one event active, then this must be a one-finger drag, and we can adjust our camera’s position accordingly. Note that we need to scale the movement based on the current zoom, or else our drag movement will be disproportionately large when zoomed in and small when zoomed out. Similarly, if the camera is rotated, that rotation should be applied to the relative value as well so that the drag moves the camera in the correct direction.\nHere’s an example captured directly from a mobile device. The yellow circle indicates the touch location.\nZoom Note You won’t be able to test this gesture on your computer because it requires 2 touch events, which the mouse can’t emulate.\nA “pinch” gesture will trigger the camera to zoom. This happens when we detect two drag events. If the drag events move toward each other, we’ll zoom in; away from each other, we’ll zoom out.\nif event is InputEventScreenDrag: events[event.index] = event if events.size() == 1: position += event.relative.rotated(rotation) * zoom.x elif events.size() == 2: var drag_distance = events[0].position.distance_to(events[1].position) if abs(drag_distance - last_drag_distance) \u003e zoom_sensitivity: var new_zoom = (1 + zoom_speed) if drag_distance \u003c last_drag_distance else (1 - zoom_speed) new_zoom = clamp(zoom.x * new_zoom, min_zoom, max_zoom) zoom = Vector2.ONE * new_zoom last_drag_distance = drag_distance Here we handle the case of 2 active drag events. drag_distance tells us how far apart they are, and we can compare it with last_drag_distance to see if it’s larger or smaller. zoom_speed is a factor, so we’ll be multiplying the zoom by 1.05 (for zooming in) and 0.95 (for zooming out). We can then clamp the resulting zoom so that it doesn’t exceed our designated limits, and then assign the new zoom level. Finally, we update last_drag_distance for the next event.\nWrapping up You can use this camera as a basis for your own camera needs. Here are some suggestions you can try to make yourself:\nUse lerp() to smooth the zooming. Automatically return zoom to default level. Double-tap to reset. Add more gestures -three fingers, etc. For completeness, here’s the full TouchCamera.gd script:\nextends Camera2D @export var target: NodePath var target_return_enabled = true var target_return_rate = 0.02 var min_zoom = 0.5 var max_zoom = 2 var zoom_sensitivity = 10 var zoom_speed = 0.05 var events = {} var last_drag_distance = 0 func _process(delta): if target and target_return_enabled and events.size() == 0: position = lerp(position, get_node(target).position, target_return_rate) func _unhandled_input(event): if event is InputEventScreenTouch: if event.pressed: events[event.index] = event else: events.erase(event.index) if event is InputEventScreenDrag: events[event.index] = event if events.size() == 1: position += event.relative.rotated(rotation) * zoom.x elif events.size() == 2: var drag_distance = events[0].position.distance_to(events[1].position) if abs(drag_distance - last_drag_distance) \u003e zoom_sensitivity: var new_zoom = (1 + zoom_speed) if drag_distance \u003c last_drag_distance else (1 - zoom_speed) new_zoom = clamp(zoom.x * new_zoom, min_zoom, max_zoom) zoom = Vector2.ONE * new_zoom last_drag_distance = drag_distance Related recipes Input: Input Actions Drag-select multiple units Like video? ","description":"","tags":null,"title":"Touchscreen Camera","uri":"/godot_recipes/4.x/2d/touchscreen_camera/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:\n\u003e A ⋅ B = ∥ A ∥ ∥ B ∥ cos θ Where θ 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:\n\u003e A ⋅ B = cos θ 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:\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":" Tip This article is being updated from Godot 3 to Godot 4.\nProblem You want to draw the trajectory of a ballistic shot, like from a tank.\nSolution Setup For this example, we’re using the “Ballistic Bullet” from this recipe:\nBallistic bullet and a tank set up like so, with a Marker2D designating the “muzzle” where the bullet will be spawned:\nIn the tank’s script, we instance the bullet like so:\nfunc _unhandled_input(event): if event.is_action_released(\"shoot\") and can_shoot: var b = Bullet.instantiate() owner.add_child(b) b.transform = $Barrel/Muzzle.global_transform b.velocity = b.transform.x * muzzle_velocity b.gravity = gravity can_shoot = false This instances the bullet, adds it as a child to the “world” node (the tank’s owner) and sets its initial properties. Note that we’re using the tank to define gravity, but that’s just for this example - in a full project you would likely use a global value for this.\nHere’s our starting setup in action:\nLine setup In the main scene, which contains the tank and the ground, we’ve added a Line2D. This is what we’ll use to draw the trajectory.\nTo improve the line’s appearance, we’ve set the Width to 15 and all of the Capping options to “Round”. We’ve also added a Gradient in the Fill section:\nDrawing the line Now we’re ready to draw the line. The goal will be to move along the projected trajectory and add points to the line as we go. Since we know the starting velocity and the gravity that the bullet is using, we can use the same calculation.\n@onready var tank = $Tank @onready var muzzle = $Tank/Barrel/Muzzle @onready var line = $Line2D var max_points = 250 func update_trajectory(delta): line.clear_points() var pos = muzzle.global_position var vel = muzzle.global_transform.x * tank.muzzle_velocity for i in max_points: line.add_point(pos) vel.y += tank.gravity * delta pos += vel * delta if pos.y \u003e $Ground.position.y - 25: break func _process(delta): if Input.is_action_pressed(\"shoot\"): line.show() update_trajectory(delta) func _on_Bullet_exploded(pos): tank.can_shoot = true line.hide() max_points sets the maximum number of points you want to add to the line. In the update_trajectory() function, we get the bullet’s starting position and velocity from the tank (remember, gravity is defined in the tank too, for this example). We then iterate through those points, moving the position each “step” by the same amount the bullet will move during one frame.\nWe’ve also added a break if the path contacts the position of the top of the ground, so that we don’t keep drawing in that case.\nFinally, we show/hide the line when shooting or not.\nRelated recipes 2D shooting recipe 2D ballistic bullet ","description":"","tags":null,"title":"Draw trajectory","uri":"/godot_recipes/4.x/2d/2d_draw_trajectory/index.html"},{"content":"Problem You want a radial menu - a ring of buttons that pops up for you to choose an option.\nSolution Radial menus are used in a variety of games to allow access to a selection of buttons. For example, clicking on an NPC in a game allows you to choose what action to take: talk, inspect, attack, etc.\nThe specific look-and-feel of your menu should match with your game’s esthetic. For this demo, we’ll focus on the mechanics of making the menu work, and leave the styling choices to you.\nHere’s the node setup:\nWe’re using a TextureButton as our root node. This is the button you’ll click to open/close the menu.\nThe Buttons Control node is the container where you’ll place any number of items that you want. Make sure to set this control’s Mouse/Filter property to “Ignore” so that it won’t intercept mouse clicks.\nFor this example, we’re using 9 buttons from our Cooldown Button recipe.\nNow, let’s look at the script for the button:\nextends TextureButton class_name RadialMenuButton @export var radius = 120 @export var speed = 0.25 var num var active = false Here are our variables. radius represents the “size” of the menu: the radius of the circle. speed is for the animation - smaller numbers are faster.\nnum keeps track of how many buttons there are, while active is a flag to track whether the menu is open or closed.\nfunc _ready(): $Buttons.hide() num = $Buttons.get_child_count() for b in $Buttons.get_children(): b.position = position In _ready() we start setting things up: hiding the menu buttons by default, and setting their positions to that of the main button.\nNow connect the pressed signal of the main button.\nfunc _on_pressed(): disabled = true if active: hide_menu() else: show_menu() Clicking the button shows/hides the menu. We also need to disable the button, or else clicking again while the tween is playing would restart it.\nfunc _on_tween_finished(): disabled = false if not active: $Buttons.hide() When the tween animation finishes, toggle the active state and enable the button again.\nLet’s look at the show_menu() function:\nfunc show_menu(): $Buttons.show() var spacing = TAU / num active = true var tw = create_tween().set_parallel() tw.finished.connect(_on_tween_finished) for b in $Buttons.get_children(): # Subtract PI/2 to align the first button to the top var a = spacing * b.get_position_in_parent() - PI / 2 var dest = Vector2(radius, 0).rotated(a) tw.tween_property(b, \"position\", dest, speed).from(Vector2.ZERO).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_OUT) tw.tween_property(b, \"scale\", Vector2.ONE, speed).from(Vector2(0.5, 0.5)).set_trans(Tween.TRANS_LINEAR) In this function we calculate the angle we need between each item (spacing). We then loop through each button and find its destination (dest) based on this angle and the chosen radius. For each button, we’re tweening two properties, position and scale, to get our desired effect.\nhide_menu() performs the exact opposite function:\nfunc hide_menu(): active = false var tw = create_tween().set_parallel() tw.finished.connect(_on_tween_finished) for b in $Buttons.get_children(): tw.tween_property(b, \"position\", Vector2.ZERO, speed).set_trans(Tween.TRANS_BACK).set_ease(Tween.EASE_IN) tw.tween_property(b, \"scale\", Vector2(0.5, 0.5), speed).set_trans(Tween.TRANS_LINEAR) Here’s the end result:\nDownload This Project Download the project’s example code here: https://github.com/godotrecipes/ui_radial_menu\nRelated recipes UI: Cooldown Button ","description":"","tags":null,"title":"Radial Popup Menu","uri":"/godot_recipes/4.x/ui/radial_menu/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.\nIn this section: Your First 2D Game Mobile Game: Circle Jump ","description":"","tags":null,"title":"Game Tutorials","uri":"/godot_recipes/4.x/games/index.html"},{"content":" \u0026nbsp 3D Car Making a 3D car using CharacterBody3D.\nIn this section: 3D Kinematic Car: Base 3D Kinematic Car: Traction/Drifting 3D Kinematic Car: Chase Camera 3D Kinematic Car: Slopes \u0026 Ramps ","description":"","tags":null,"title":"3D Kinematic Car","uri":"/godot_recipes/4.x/3d/kinematic_car/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.\nThis site also has lots of learning material for Godot 3 - much of it is still useful! 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":"Label Label is a Control node for displaying unformatted text, with options for controlling the text’s alignment, wrapping, etc.\nAPI Documentation\nNode properties See the documentation for the full list, but here we’ll review the most commonly used properties of the node:\ntext - this property is the contents of the label. Change this in code to change what the label displays. If you’re displaying numerical values, don’t forget to convert them to strings! For example, to update a label with a given numerical value: func update_label(value): $Label.text = str(value) align - this property allows you to align the text right/center/left.\npercent_visible - this property limits the number of characters displayed. For example setting 0.5 would show half of the contents. Try animating this value to create a “typewriter” effect.\nAdding a font As soon as you type something into the Text property, you’ll see that Godot’s default font is probably too small for your needs. Here’s how you can change the font:\nFirst, make sure you have a TTF or OTF font file in your project folder.\nIn the Label’s properties under “Custom Fonts”, choose “New DynamicFont”. DynamicFont is a Resource type that renders text from a given font.\nClick on the “DynamicFont” you added, and under “Font/Font Data”, choose “Load” and select your font file. You should also set the font’s Size.\n","description":"","tags":null,"title":"Label","uri":"/godot_recipes/4.x/kyn/label/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nPath2D \u0026 PathFollow2D A path is a sequence of points in 2D space, defined by a Curve2D resource. The Path2D is a node that allows you to position a path in 2D space, and do create a new path in the editor.\nPaths have a variety of uses. You can make a patrol path for an enemy mob to follow, a winding path for an animated visual effect, a pattern for a moving platform to follow, etc.\nAbout Curve2D The data of the path is held in this Resource object. It contains the mathematical representation of the curve, and provides some ways to interact with that data. The API Documentation contains the details, but here are a few useful methods that you may want to use:\nadd_point() / remove_point() / clear_points() If you need to manipulate the path’s points in code, these functions will help you.\nget_closest_point() This method returns the closest of the path’s points to any given point in space.\nget_closest_offset() Distinct from the above, this method returns the position along the path that’s closest to the given point. Note that this may be in-between two of the path’s defined points.\ntesselate() This method returns a list of points along the curve. These points will be more densely packed in the parts of the path with a higher curvature.\nDrawing paths When you select a Path2D node, some new icons appear on the icon bar:\nSelecting one of these icons changes the behavior of the mouse cursor. You can hover over them to see their names.\nSelect Points - Lets you move existing points by clicking and dragging. Select Control Points - Adds control handles to a point, allowing you to adjust the curve (see below). Add Point - Add a point by clicking in empty space. Delete Point - Click to delete a point. Close Curve - Connects the last point in the curve to the first one, creating a loop. Select “Add Point” and click in the editor window to create points.\nTo create a smoother, rounded curve, select “Select Control Points” and drag any of the points in the curve to adjust their “in” and “out” handles:\nFollowing a path By itself, a Path2D doesn’t have much functionality. In order to move along the path, you need to use a PathFollow2D node as well. This is a node whose function is to move along a parent Path2D.\nMost useful properties:\noffset and unit_offset - these properties represent the distance along the path relative to the beginning. offset is measured in pixels while unit_offset is a percentage (eg 0 is the start, .5 is halfway, 1.0 is the end)\nrotate - this boolean determines whether the node should rotate as it moves along the path.\nloop - if this boolean is true, then offsets greater than the path length will “wrap around”. Use this if you want a repeatable path.\nFor example, consider this plane moving along a path (you can make the path visible by setting Debug\u003eVisible Navigation):\nThis is done by making the plane Sprite a child of the PathFollow2D and adding the following to _process():\nfunc _process(delta): $Path2D/PathFollow2D.offset += 250 * delta As the offset is increased, the node moves along the path.\nNote the Rotate property of PathFollow2D which keeps the node (and therefore its children) rotated to point along the path as it moves.\nExample Find path direction Consider this example, from the AI: Context-based Steering recipe:\nIn this example, the AI agents avoid walls and each other, but also “want” to continue along the track in the correct direction. There is a Path2D drawn along the track, and the agents query it to find out what direction it’s pointing:\nfunc get_path_direction(pos): var offset = $Path2D.curve.get_closest_offset(pos) $Path2D/PathFollow2D.offset = offset return $Path2D/PathFollow2D.transform.x At any given point along the path, the PathFollow2D’s forward direction (transform.x) points along the path.\n","description":"","tags":null,"title":"Path2D \u0026 PathFollow2D","uri":"/godot_recipes/4.x/kyn/path2d/index.html"},{"content":" Tip This article is being updated from Godot 3 to Godot 4.\nRayCast2D 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"}]