| name | godot_docs |
| description | Comprehensive assistance with godot_docs |
Godot_Docs Skill
Comprehensive assistance with godot_docs development, generated from official documentation.
When to Use This Skill
This skill should be triggered when:
- Working with godot_docs
- Asking about godot_docs features or APIs
- Implementing godot_docs solutions
- Debugging godot_docs code
- Learning godot_docs best practices
Quick Reference
Common Patterns
Pattern 1: 3D Particle system properties Emitter properties The checkbox next to the Emitting property activates and deactivates the particle system. Particles will only be processed and rendered if the box is checked. You can set this property at runtime if you want to activate or deactivate particle systems dynamically. The Amount property controls the maximum number of particles visible at any given time. Increase the value to spawn more particles at the cost of performance. The Amount Ratio property is the ratio of particles compared to the amount that will be emitted. If it's less than 1.0, the amount of particles emitted through the lifetime will be the Amount * Amount Ratio. Changing this value while emitted doesn't affect already created particles and doesn't cause the particle system to restart. It's useful for making effects where the number of emitted particles varies over time. You can set another particle node as a Sub Emitter, which will be spawned as a child of each particle. See the Sub-emitters section in this manual for a detailed explanation of how to add a sub-emitter to a particle system. Time properties The Lifetime property controls how long each particle exists before it disappears again. It is measured in seconds. A lot of particle properties can be set to change over the particle's lifetime and blend smoothly from one value to another. Lifetime and Amount are related. They determine the particle system's emission rate. Whenever you want to know how many particles are spawned per second, this is the formula you would use: [Particles per second = \frac{Amount}{Lifetime}] Example: Emitting 32 particles with a lifetime of 4 seconds each would mean the system emits 8 particles per second. The Interp to End property causes all the particles in the node to interpolate towards the end of their lifetime. If the checkbox next to the One Shot property is checked, the particle system will emit amount particles and then disable itself. It "runs" only once. This property is unchecked by default, so the system will keep emitting particles until it is disabled or destroyed manually. One-shot particles are a good fit for effects that react to a single event, like item pickups or splinters that burst away when a bullet hits a wall. The Preprocess property is a way to fast-forward to a point in the middle of the particle system's lifetime and start rendering from there. It is measured in seconds. A value of 1 means that when the particle system starts, it will look as if it has been running for one second already. This can be useful if you want the particle system to look like it has been active for a while even though it was just loaded into the scene. Consider the example below. Both particle systems simulate dust flying around in the area. With a preprocess value of 0, there wouldn't be any dust for the first couple of seconds because the system has not yet emitted enough particles for the effect to become noticeable. This can be seen in the video on the left. Compare that to the video on the right where the particle system is preprocessed for 4 seconds. The dust is fully visible from the very beginning because we skipped the first four seconds of "setup" time. No preprocess (left) vs. 4 seconds of preprocess (right) You can slow down or speed up the particle system with the Speed Scale property. This applies to processing the data as well as rendering the particles. Set it to 0 to pause the particle system completely or set it to something like 2 to make it move twice as fast. Different speed scale values: 0.1 (left), 0.5 (middle), 1.0 (right) The Explosiveness property controls whether particles are emitted sequentially or simultaneously. A value of 0 means that particles emit one after the other. A value of 1 means that all amount particles emit at the same time, giving the effect a more "explosive" appearance. The Randomness property adds some randomness to the particle emission timing. When set to 0, there is no randomness at all and the interval between the emission of one particle and the next is always the same: the particles are emitted at regular intervals. A Randomness value of 1 makes the interval completely random. You can use this property to break up some of the uniformity in your effects. When Explosiveness is set to 1, this property has no effect. Interpolation off (left) vs. on (right) The Fixed FPS property limits how often the particle system is processed. This includes property updates as well as collision and attractors. This can improve performance a lot, especially in scenes that make heavy use of particle collision. Note that this does not change the speed at which particles move or rotate. You would use the Speed Scale property for that. When you set Fixed FPS to very low values, you will notice that the particle animation starts to look choppy. This can sometimes be desired if it fits the art direction, but most of the time, you'll want particle systems to animate smoothly. That's what the Interpolate property does. It blends particle properties between updates so that even a particle system running at 10 FPS appears as smooth as running at 60. Note When using particle collision, tunneling can occur if the particles move fast and colliders are thin. This can be remedied by increasing Fixed FPS (at a performance cost). Collision properties See also Setting up particle collision requires following further steps described in 3D Particle collisions. The Base Size property defines each particle's default collision size, which is used to check whether a particle is currently colliding with the environment. You would usually want this to be about the same size as the particle. It can make sense to increase this value for particles that are very small and move very fast to prevent them from clipping through the collision geometry. Drawing properties The Visibility AABB property defines a box around the particle system's origin. As long as any part of this box is in the camera's field of view, the particle system is visible. As soon as it leaves the camera's field of view, the particle system stops being rendered at all. You can use this property to boost performance by keeping the box as small as possible. One thing to keep in mind when you set a size for the Visibility AABB is that particles that are outside of its bounds disappear instantly when it leaves the camera's field of view. Particle collision will also not occur outside the Visibility AABB. While not technically a bug, this can have a negative effect on the visual experience. When the Local Coords property is checked, all particle calculations use the local coordinate system to determine things like up and down, gravity, and movement direction. Up and down, for example, would follow the particle system's or its parent node's rotation. When the property is unchecked, the global world space is used for these calculations: Down will always be -Y in world space, regardless of the particle system's rotation. Local space coordinates (left) vs. world space coordinates (right) The Draw Order property controls the order in which individual particles are drawn. Index means that they are drawn in the order of emission: particles that are spawned later are drawn on top of earlier ones. Lifetime means that they are drawn in the order of their remaining lifetime. Reverse Lifetime reverses the Lifetime draw order. View Depth means particles are drawn according to their distance from the camera: The ones closer to the camera on top of those farther away. The Transform Align property controls the particle's default rotation. Disabled means they don't align in any particular way. Instead, their rotation is determined by the values set in the process material. Z-Billboard means that the particles will always face the camera. This is similar to the Billboard property in the Standard Material. Y to Velocity means that each particle's Y-axis aligns with its movement direction. This can be useful for things like bullets or arrows, where you want particles to always point "forward". Z-Billboard + Y to Velocity combines the previous two modes. Each particle's Z-axis will point towards the camera while its Y-axis will align with their velocity. Trail properties Particle trail properties The Enabled property controls whether particles are rendered as trails. The box needs to be checked if you want to make use of particle trails. The Length Secs property controls for how long a trail should be emitted. The longer this duration is, the longer the trail will be. See the Particle trails section in this manual for a detailed explanation of how particle trails work and how to set them up. Previous Next User-contributed notes Please read the User-contributed notes policy before submitting a comment.
Emitting
Pattern 2: Example: Emitting 32 particles with a lifetime of 4 seconds each would mean the system emits 8 particles per second.
Interp to End
Pattern 3: Advanced Import Settings While the regular import panel provides many essential options for imported 3D models, the advanced import settings provides per object options, model previews, and animation previews. To open it select the Advanced... button at the bottom of the import dock. This is available for 3D models imported as scenes, as well as animation libraries. Note This page does not go over options also available in the import dock, or anything outside of the advanced import settings. For information on those please read the Import configuration page. Using the Advanced Import Settings dialog The first tab you'll see is the Scene tab. The options available in the panel on the right are identical to the Import dock, but you have access to a 3D preview. The 3D preview can be rotated by holding down the left mouse button then dragging the mouse. Zoom can be adjusted using the mouse wheel. Advanced Import Settings dialog (Scene tab). Credit: Modern Arm Chair 01 - Poly Haven Configuring node import options You can select individual nodes that compose the scene while in the Scene tab using the tree view at the left: Selecting a node in the Advanced Import Settings dialog (Materials tab) This exposes several per-node import options: Skip Import: If checked, the node will not be present in the final imported scene. Enabling this disables all other options. Generate > Physics: If checked, generates a PhysicsBody3D parent node with collision shapes that are siblings to the MeshInstance3D node. Generate > NavMesh: If checked, generates a NavigationRegion3D child node for navigation. Mesh + NavMesh will keep the original mesh visible, while NavMesh Only will only import the navigation mesh (without a visual representation). NavMesh Only is meant to be used when you've manually authored a simplified mesh for navigation. Generate > Occluder: If checked, generates an OccluderInstance3D sibling node for occlusion culling using the mesh's geometry as a basis for the occluder's shape. Mesh + Occluder will keep the original mesh visible, while Occluder Only will only import the occluder (without a visual representation). Occluder Only is meant to be used when you've manually authored a simplified mesh for occlusion culling. These options are only visible if some of the above options are enabled: Physics > Body Type: Only visible if Generate > Physics is enabled. Controls the PhysicsBody3D that should be created. Static creates a StaticBody3D, Dynamic creates a RigidBody3D, Area creates an Area3D. Physics > Shape Type: Only visible if Generate > Physics is enabled. Trimesh allows for precise per-triangle collision, but it can only be used with a Static body type. Other types are less precise and may require manual configuration, but can be used with any body type. For static level geometry, use Trimesh. For dynamic geometry, use primitive shapes if possible for better performance, or use one of the convex decomposition modes if the shape is large and complex. Decomposition > Advanced: Only visible if Physics > Shape Type is Decompose Convex. If checked, allows adjusting advanced decomposition options. If disabled, only a preset Precision can be adjusted (which is usually sufficient). Decomposition > Precision: Only visible if Physics > Shape Type is Decompose Convex. Controls the precision to use for convex decomposition. Higher values result in more detailed collision, at the cost of slower generation and increased CPU usage during physics simulation. To improve performance, it's recommended to keep this value as low as possible for your use cases. Occluder > Simplification Distance: Only visible if Generate > Occluder is set to Mesh + Occluder or Occluder Only. Higher values result in an occluder mesh with fewer vertices (resulting in decreased CPU utilization), at the cost of more occlusion culling issues (such as false positives or false negatives). If you run into objects disappearing when they shouldn't when the camera is near a certain mesh, try decreasing this value. Configuring mesh and material import options In the Advanced Import Settings dialog, there are 2 ways to select individual meshes or materials: Switch to the Meshes or Materials tab in the top-left corner of the dialog. Stay in the Scene tab, but unfold the options on the tree view on the left. After choosing a mesh or material, this presents the same information as the Meshes and Materials tabs, but in a tree view instead of a list. If you select a mesh, different options will appear in the panel on the right: Advanced Import Settings dialog (Meshes tab) The options are as follows: Save to File: Saves the Mesh resource to an external file (this isn't a scene file). You generally don't need to use this for placing the mesh in a 3D scene – instead, you should instance the 3D scene directly. However, having direct access to the Mesh resource is useful for specific nodes, such as MeshInstance3D, MultiMeshInstance3D, GPUParticles3D or CPUParticles3D. - You will also need to specify an output file path using the option that appears after enabling Save to File. It's recommended to use the .res output file extension for smaller file sizes and faster loading speeds, as .tres is inefficient for writing large amounts of data. Generate > Shadow Meshes: Per-mesh override for the Meshes > Create Shadow Meshes scene-wide import option described in Using the Import dock. Default will use the scene-wide import option, while Enable or Disable can forcibly enable or disable this behavior on a specific mesh. Generate > Lightmap UV: Per-mesh override for the Meshes > Light Baking scene-wide import option described in Using the Import dock. Default will use the scene-wide import option, while Enable or Disable can forcibly enable or disable this behavior on a specific mesh. - Setting this to Enable on a scene with the Static light baking mode is equivalent to configuring this mesh to use Static Lightmaps. Setting this to Disable on a scene with the Static Lightmaps light baking mode is equivalent to configuring this mesh to use Static instead. Generate > LODs: Per-mesh override for the Meshes > Generate LODs scene-wide import option described in Using the Import dock. Default will use the scene-wide import option, while Enable or Disable can forcibly enable or disable this behavior on a specific mesh. LODs > Normal Merge Angle: The minimum angle difference between two vertices required to preserve a geometry edge in mesh LOD generation. If running into visual issues with LOD generation, decreasing this value may help (at the cost of less efficient LOD generation). If you select a material, only one option will appear in the panel on the right: Advanced Import Settings dialog (Materials tab) When Use External is checked and an output path is specified, this lets you use an external material instead of the material that is included in the original 3D scene file; see the section below. Extracting materials to separate files While Godot can import materials authored in 3D modeling software, the default configuration may not be suitable for your needs. For example: You want to configure material features not supported by your 3D application. You want to use a different texture filtering mode, as this option is configured in the material since Godot 4.0 (and not in the image). You want to replace one of the materials with an entirely different material, such as a custom shader. To be able to modify the 3D scene's materials in the Godot editor, you need to use external material resources. In the top-left corner of the Advanced Import Settings dialog, choose Actions… > Extract Materials: Extracting all built-in materials to external resources in the Advanced Import Settings dialog After choosing this option, select a folder to extract material .tres files to, then confirm the extraction: Confirming material extraction in the Advanced Import Settings subdialog Note After extracting materials, the 3D scene will automatically be configured to use external material references. As a result, you don't need to manually enable Use External on every material to make the external .tres material effective. When Use External is enabled, remember that the Advanced Import Settings dialog will keep displaying the mesh's original materials (the ones designed in the 3D modeling software). This means your customizations to the materials won't be visible within this dialog. To preview your modified materials, you need to place the imported 3D scene in another scene using the editor. Godot will not overwrite changes made to extracted materials when the source 3D scene is reimported. However, if the material name is changed in the source 3D file, the link between the original material and the extracted material will be lost. As a result, you'll need to use the Advanced Import Settings dialog to associate the renamed material to the existing extracted material. The above can be done in the dialog's Materials tab by selecting the material, enabling Save to File, then specifying the save path using the Path option that appears after enabling Save to File. Animation options Several extra options are available for the generated AnimationPlayer nodes, as well as their individual animations when they're selected in the Scene tab. Optimizer When animations are imported, an optimizer is run, which reduces the size of the animation considerably. In general, this should always be turned on unless you suspect that an animation might be broken due to it being enabled. Save to file By default, animations are saved as built-in. It is possible to save them to a file instead. This allows adding custom tracks to the animations and keeping them after a reimport. Slices It is possible to specify multiple animations from a single timeline as slices. For this to work, the model must have only one animation that is named default. To create slices, change the slice amount to something greater than zero. You can then name a slice, specify which frames it starts and stops on, and choose whether the animation loops or not. Previous Next User-contributed notes Please read the User-contributed notes policy before submitting a comment.
.res
Pattern 4: While Godot can import materials authored in 3D modeling software, the default configuration may not be suitable for your needs. For example:
.tres
Pattern 5: Advanced vector math Planes The dot product has another interesting property with unit vectors. Imagine that perpendicular to that vector (and through the origin) passes a plane. Planes divide the entire space into positive (over the plane) and negative (under the plane), and (contrary to popular belief) you can also use their math in 2D: Unit vectors that are perpendicular to a surface (so, they describe the orientation of the surface) are called unit normal vectors. Though, usually they are just abbreviated as normals. Normals appear in planes, 3D geometry (to determine where each face or vertex is siding), etc. A normal is a unit vector, but it's called normal because of its usage. (Just like we call (0,0) the Origin!). The plane passes by the origin and the surface of it is perpendicular to the unit vector (or normal). The side the vector points to is the positive half-space, while the other side is the negative half-space. In 3D this is exactly the same, except that the plane is an infinite surface (imagine an infinite, flat sheet of paper that you can orient and is pinned to the origin) instead of a line. Distance to plane Now that it's clear what a plane is, let's go back to the dot product. The dot product between a unit vector and any point in space (yes, this time we do dot product between vector and position), returns the distance from the point to the plane: GDScriptC#var distance = normal.dot(point) var distance = normal.Dot(point); But not just the absolute distance, if the point is in the negative half space the distance will be negative, too: This allows us to tell which side of the plane a point is. Away from the origin I know what you are thinking! So far this is nice, but real planes are everywhere in space, not only passing through the origin. You want real plane action and you want it now. Remember that planes not only split space in two, but they also have polarity. This means that it is possible to have perfectly overlapping planes, but their negative and positive half-spaces are swapped. With this in mind, let's describe a full plane as a normal N and a distance from the origin scalar D. Thus, our plane is represented by N and D. For example: For 3D math, Godot provides a Plane built-in type that handles this. Basically, N and D can represent any plane in space, be it for 2D or 3D (depending on the amount of dimensions of N) and the math is the same for both. It's the same as before, but D is the distance from the origin to the plane, travelling in N direction. As an example, imagine you want to reach a point in the plane, you will just do: GDScriptC#var point_in_plane = N*D var pointInPlane = N * D; This will stretch (resize) the normal vector and make it touch the plane. This math might seem confusing, but it's actually much simpler than it seems. If we want to tell, again, the distance from the point to the plane, we do the same but adjusting for distance: GDScriptC#var distance = N.dot(point) - D var distance = N.Dot(point) - D; The same thing, using a built-in function: GDScriptC#var distance = plane.distance_to(point) var distance = plane.DistanceTo(point); This will, again, return either a positive or negative distance. Flipping the polarity of the plane can be done by negating both N and D. This will result in a plane in the same position, but with inverted negative and positive half spaces: GDScriptC#N = -N D = -D N = -N; D = -D; Godot also implements this operator in Plane. So, using the format below will work as expected: GDScriptC#var inverted_plane = -plane var invertedPlane = -plane; So, remember, the plane's main practical use is that we can calculate the distance to it. So, when is it useful to calculate the distance from a point to a plane? Let's see some examples. Constructing a plane in 2D Planes clearly don't come out of nowhere, so they must be built. Constructing them in 2D is easy, this can be done from either a normal (unit vector) and a point, or from two points in space. In the case of a normal and a point, most of the work is done, as the normal is already computed, so calculate D from the dot product of the normal and the point. GDScriptC#var N = normal var D = normal.dot(point) var N = normal; var D = normal.Dot(point); For two points in space, there are actually two planes that pass through them, sharing the same space but with normal pointing to the opposite directions. To compute the normal from the two points, the direction vector must be obtained first, and then it needs to be rotated 90 degrees to either side: GDScriptC## Calculate vector from a to b. var dvec = point_a.direction_to(point_b) # Rotate 90 degrees. var normal = Vector2(dvec.y, -dvec.x) # Alternatively (depending the desired side of the normal): # var normal = Vector2(-dvec.y, dvec.x) // Calculate vector from a to b. var dvec = pointA.DirectionTo(pointB); // Rotate 90 degrees. var normal = new Vector2(dvec.Y, -dvec.X); // Alternatively (depending the desired side of the normal): // var normal = new Vector2(-dvec.Y, dvec.X); The rest is the same as the previous example. Either point_a or point_b will work, as they are in the same plane: GDScriptC#var N = normal var D = normal.dot(point_a) # this works the same # var D = normal.dot(point_b) var N = normal; var D = normal.Dot(pointA); // this works the same // var D = normal.Dot(pointB); Doing the same in 3D is a little more complex and is explained further down. Some examples of planes Here is an example of what planes are useful for. Imagine you have a convex polygon. For example, a rectangle, a trapezoid, a triangle, or just any polygon where no faces bend inwards. For every segment of the polygon, we compute the plane that passes by that segment. Once we have the list of planes, we can do neat things, for example checking if a point is inside the polygon. We go through all planes, if we can find a plane where the distance to the point is positive, then the point is outside the polygon. If we can't, then the point is inside. Code should be something like this: GDScriptC#var inside = true for p in planes: # check if distance to plane is positive if (p.distance_to(point) > 0): inside = false break # with one that fails, it's enough var inside = true; foreach (var p in planes) { // check if distance to plane is positive if (p.DistanceTo(point) > 0) { inside = false; break; // with one that fails, it's enough } } Pretty cool, huh? But this gets much better! With a little more effort, similar logic will let us know when two convex polygons are overlapping too. This is called the Separating Axis Theorem (or SAT) and most physics engines use this to detect collision. With a point, just checking if a plane returns a positive distance is enough to tell if the point is outside. With another polygon, we must find a plane where all the other polygon points return a positive distance to it. This check is performed with the planes of A against the points of B, and then with the planes of B against the points of A: Code should be something like this: GDScriptC#var overlapping = true for p in planes_of_A: var all_out = true for v in points_of_B: if (p.distance_to(v) < 0): all_out = false break if (all_out): # a separating plane was found # do not continue testing overlapping = false break if (overlapping): # only do this check if no separating plane # was found in planes of A for p in planes_of_B: var all_out = true for v in points_of_A: if (p.distance_to(v) < 0): all_out = false break if (all_out): overlapping = false break if (overlapping): print("Polygons Collided!") var overlapping = true; foreach (Plane plane in planesOfA) { var allOut = true; foreach (Vector3 point in pointsOfB) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { // a separating plane was found // do not continue testing overlapping = false; break; } } if (overlapping) { // only do this check if no separating plane // was found in planes of A foreach (Plane plane in planesOfB) { var allOut = true; foreach (Vector3 point in pointsOfA) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { overlapping = false; break; } } } if (overlapping) { GD.Print("Polygons Collided!"); } As you can see, planes are quite useful, and this is the tip of the iceberg. You might be wondering what happens with non convex polygons. This is usually just handled by splitting the concave polygon into smaller convex polygons, or using a technique such as BSP (which is not used much nowadays). Collision detection in 3D This is another bonus bit, a reward for being patient and keeping up with this long tutorial. Here is another piece of wisdom. This might not be something with a direct use case (Godot already does collision detection pretty well) but it's used by almost all physics engines and collision detection libraries :) Remember that converting a convex shape in 2D to an array of 2D planes was useful for collision detection? You could detect if a point was inside any convex shape, or if two 2D convex shapes were overlapping. Well, this works in 3D too, if two 3D polyhedral shapes are colliding, you won't be able to find a separating plane. If a separating plane is found, then the shapes are definitely not colliding. To refresh a bit a separating plane means that all vertices of polygon A are in one side of the plane, and all vertices of polygon B are in the other side. This plane is always one of the face-planes of either polygon A or polygon B. In 3D though, there is a problem to this approach, because it is possible that, in some cases a separating plane can't be found. This is an example of such situation: To avoid it, some extra planes need to be tested as separators, these planes are the cross product between the edges of polygon A and the edges of polygon B So the final algorithm is something like: GDScriptC#var overlapping = true for p in planes_of_A: var all_out = true for v in points_of_B: if (p.distance_to(v) < 0): all_out = false break if (all_out): # a separating plane was found # do not continue testing overlapping = false break if (overlapping): # only do this check if no separating plane # was found in planes of A for p in planes_of_B: var all_out = true for v in points_of_A: if (p.distance_to(v) < 0): all_out = false break if (all_out): overlapping = false break if (overlapping): for ea in edges_of_A: for eb in edges_of_B: var n = ea.cross(eb) if (n.length() == 0): continue var max_A = -1e20 # tiny number var min_A = 1e20 # huge number # we are using the dot product directly # so we can map a maximum and minimum range # for each polygon, then check if they # overlap. for v in points_of_A: var d = n.dot(v) max_A = max(max_A, d) min_A = min(min_A, d) var max_B = -1e20 # tiny number var min_B = 1e20 # huge number for v in points_of_B: var d = n.dot(v) max_B = max(max_B, d) min_B = min(min_B, d) if (min_A > max_B or min_B > max_A): # not overlapping! overlapping = false break if (not overlapping): break if (overlapping): print("Polygons collided!") var overlapping = true; foreach (Plane plane in planesOfA) { var allOut = true; foreach (Vector3 point in pointsOfB) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { // a separating plane was found // do not continue testing overlapping = false; break; } } if (overlapping) { // only do this check if no separating plane // was found in planes of A foreach (Plane plane in planesOfB) { var allOut = true; foreach (Vector3 point in pointsOfA) { if (plane.DistanceTo(point) < 0) { allOut = false; break; } } if (allOut) { overlapping = false; break; } } } if (overlapping) { foreach (Vector3 edgeA in edgesOfA) { foreach (Vector3 edgeB in edgesOfB) { var normal = edgeA.Cross(edgeB); if (normal.Length() == 0) { continue; } var maxA = float.MinValue; // tiny number var minA = float.MaxValue; // huge number // we are using the dot product directly // so we can map a maximum and minimum range // for each polygon, then check if they // overlap. foreach (Vector3 point in pointsOfA) { var distance = normal.Dot(point); maxA = Mathf.Max(maxA, distance); minA = Mathf.Min(minA, distance); } var maxB = float.MinValue; // tiny number var minB = float.MaxValue; // huge number foreach (Vector3 point in pointsOfB) { var distance = normal.Dot(point); maxB = Mathf.Max(maxB, distance); minB = Mathf.Min(minB, distance); } if (minA > maxB || minB > maxA) { // not overlapping! overlapping = false; break; } } if (!overlapping) { break; } } } if (overlapping) { GD.Print("Polygons Collided!"); } More information For more information on using vector math in Godot, see the following article: Matrices and transforms If you would like additional explanation, you should check out 3Blue1Brown's excellent video series Essence of Linear Algebra. Previous Next User-contributed notes Please read the User-contributed notes policy before submitting a comment.
var distance = normal.dot(point)
Pattern 6: With this in mind, let's describe a full plane as a normal N and a distance from the origin scalar D. Thus, our plane is represented by N and D. For example:
var point_in_plane = N*D
Pattern 7: Android in-app purchases Godot offers a first-party GodotGooglePlayBilling Android plugin compatible with Godot 4.2+ which uses the Google Play Billing library. Usage Getting started Make sure you have enabled and successfully set up Android Gradle Builds. Follow the installation instructions on the GodotGooglePlayBilling github page. Initialize the plugin To use the GodotGooglePlayBilling API: Access the BillingClient. Connect to its signals to receive billing results. Call start_connection. Initialization example: var billing_client: BillingClient func _ready(): billing_client = BillingClient.new() billing_client.connected.connect(_on_connected) # No params billing_client.disconnected.connect(_on_disconnected) # No params billing_client.connect_error.connect(_on_connect_error) # response_code: int, debug_message: String billing_client.query_product_details_response.connect(_on_query_product_details_response) # response: Dictionary billing_client.query_purchases_response.connect(_on_query_purchases_response) # response: Dictionary billing_client.on_purchase_updated.connect(_on_purchase_updated) # response: Dictionary billing_client.consume_purchase_response.connect(_on_consume_purchase_response) # response: Dictionary billing_client.acknowledge_purchase_response.connect(_on_acknowledge_purchase_response) # response: Dictionary billing_client.start_connection() The API must be in a connected state prior to use. The connected signal is sent when the connection process succeeds. You can also use is_ready() to determine if the plugin is ready for use. The get_connection_state() function returns the current connection state of the plugin. Return values for get_connection_state(): # Matches BillingClient.ConnectionState in the Play Billing Library. # Access in your script as: BillingClient.ConnectionState.CONNECTED enum ConnectionState { DISCONNECTED, # This client was not yet connected to billing service or was already closed. CONNECTING, # This client is currently in process of connecting to billing service. CONNECTED, # This client is currently connected to billing service. CLOSED, # This client was already closed and shouldn't be used again. } Query available items Once the API has connected, query product IDs using query_product_details(). You must successfully complete a product details query before calling the purchase(), purchase_subscription(), or update_subscription() functions, or they will return an error. query_product_details() takes two parameters: an array of product ID strings and the type of product being queried. The product type should be BillingClient.ProductType.INAPP for normal in-app purchases or BillingClient.ProductType.SUBS for subscriptions. The ID strings in the array should match the product IDs defined in the Google Play Console entry for your app. Example use of query_product_details(): func _on_connected(): billing_client.query_product_details(["my_iap_item"], BillingClient.ProductType.INAPP) # BillingClient.ProductType.SUBS for subscriptions. func _on_query_product_details_response(query_result: Dictionary): if query_result.response_code == BillingClient.BillingResponseCode.OK: print("Product details query success") for available_product in query_result.product_details: print(available_product) else: print("Product details query failed") print("response_code: ", query_result.response_code, "debug_message: ", query_result.debug_message) Query user purchases To retrieve a user's purchases, call the query_purchases() function passing a product type to query. The product type should be BillingClient.ProductType.INAPP for normal in-app purchases or BillingClient.ProductType.SUBS for subscriptions. The query_purchases_response signal is sent with the result. The signal has a single parameter: a Dictionary with a response code and either an array of purchases or a debug message. Only active subscriptions and non-consumed one-time purchases are included in the purchase array. Example use of query_purchases(): func _query_purchases(): billing_client.query_purchases(BillingClient.ProductType.INAPP) # Or BillingClient.ProductType.SUBS for subscriptions. func _on_query_purchases_response(query_result: Dictionary): if query_result.response_code == BillingClient.BillingResponseCode.OK: print("Purchase query success") for purchase in query_result.purchases: _process_purchase(purchase) else: print("Purchase query failed") print("response_code: ", query_result.response_code, "debug_message: ", query_result.debug_message) Purchase an item To launch the billing flow for an item: Use purchase() for in-app products, passing the product ID string. Use purchase_subscription() for subscriptions, passing the product ID and base plan ID. You may also optionally provide an offer ID. For both purchase() and purchase_subscription(), you can optionally pass a boolean to indicate whether offers are personallised Reminder: you must query the product details for an item before you can pass it to purchase(). This method returns a dictionary indicating whether the billing flow was successfully launched. It includes a response code and either an array of purchases or a debug message. Example use of purchase(): var result = billing_client.purchase("my_iap_item") if result.response_code == BillingClient.BillingResponseCode.OK: print("Billing flow launch success") else: print("Billing flow launch failed") print("response_code: ", result.response_code, "debug_message: ", result.debug_message) The result of the purchase will be sent through the on_purchases_updated signal. func _on_purchases_updated(result: Dictionary): if result.response_code == BillingClient.BillingResponseCode.OK: print("Purchase update received") for purchase in result.purchases: _process_purchase(purchase) else: print("Purchase update error") print("response_code: ", result.response_code, "debug_message: ", result.debug_message) Processing a purchase item The query_purchases_response and on_purchases_updated signals provide an array of purchases in Dictionary format. The purchase Dictionary includes keys that map to values of the Google Play Billing Purchase class. Purchase fields: order_id: String purchase_token: String package_name: String purchase_state: int purchase_time: int (milliseconds since the epoch (Jan 1, 1970)) original_json: String is_acknowledged: bool is_auto_renewing: bool quantity: int signature: String product_ids: PackedStringArray Check purchase state Check the purchase_state value of a purchase to determine if a purchase was completed or is still pending. PurchaseState values: # Matches Purchase.PurchaseState in the Play Billing Library # Access in your script as: BillingClient.PurchaseState.PURCHASED enum PurchaseState { UNSPECIFIED, PURCHASED, PENDING, } If a purchase is in a PENDING state, you should not award the contents of the purchase or do any further processing of the purchase until it reaches the PURCHASED state. If you have a store interface, you may wish to display information about pending purchases needing to be completed in the Google Play Store. For more details on pending purchases, see Handling pending transactions in the Google Play Billing Library documentation. Consumables If your in-app item is not a one-time purchase but a consumable item (e.g. coins) which can be purchased multiple times, you can consume an item by calling consume_purchase() passing the purchase_token value from the purchase dictionary. Calling consume_purchase() automatically acknowledges a purchase. Consuming a product allows the user to purchase it again, it will no longer appear in subsequent query_purchases() calls unless it is repurchased. Example use of consume_purchase(): func _process_purchase(purchase): if "my_consumable_iap_item" in purchase.product_ids and purchase.purchase_state == BillingClient.PurchaseState.PURCHASED: # Add code to store payment so we can reconcile the purchase token # in the completion callback against the original purchase billing_client.consume_purchase(purchase.purchase_token) func _on_consume_purchase_response(result: Dictionary): if result.response_code == BillingClient.BillingResponseCode.OK: print("Consume purchase success") _handle_purchase_token(result.token, true) else: print("Consume purchase failed") print("response_code: ", result.response_code, "debug_message: ", result.debug_message, "purchase_token: ", result.token) # Find the product associated with the purchase token and award the # product if successful func _handle_purchase_token(purchase_token, purchase_successful): # check/award logic, remove purchase from tracking list Acknowledging purchases If your in-app item is a one-time purchase, you must acknowledge the purchase by calling the acknowledge_purchase() function, passing the purchase_token value from the purchase dictionary. If you do not acknowledge a purchase within three days, the user automatically receives a refund, and Google Play revokes the purchase. If you are calling comsume_purchase() it automatically acknowledges the purchase and you do not need to call acknowledge_purchase(). Example use of acknowledge_purchase(): func _process_purchase(purchase): if "my_one_time_iap_item" in purchase.product_ids and \ purchase.purchase_state == BillingClient.PurchaseState.PURCHASED and \ not purchase.is_acknowledged: # Add code to store payment so we can reconcile the purchase token # in the completion callback against the original purchase billing_client.acknowledge_purchase(purchase.purchase_token) func _on_acknowledge_purchase_response(result: Dictionary): if result.response_code == BillingClient.BillingResponseCode.OK: print("Acknowledge purchase success") _handle_purchase_token(result.token, true) else: print("Acknowledge purchase failed") print("response_code: ", result.response_code, "debug_message: ", result.debug_message, "purchase_token: ", result.token) # Find the product associated with the purchase token and award the # product if successful func _handle_purchase_token(purchase_token, purchase_successful): # check/award logic, remove purchase from tracking list Subscriptions Subscriptions work mostly like regular in-app items. Use BillingClient.ProductType.SUBS as the second argument to query_product_details() to get subscription details. Pass BillingClient.ProductType.SUBS to query_purchases() to get subscription purchase details. You can check is_auto_renewing in the a subscription purchase returned from query_purchases() to see if a user has cancelled an auto-renewing subscription. You need to acknowledge new subscription purchases, but not automatic subscription renewals. If you support upgrading or downgrading between different subscription levels, you should use update_subscription() to use the subscription update flow to change an active subscription. Like purchase(), results are returned by the on_purchases_updated signal. These are the parameters of update_subscription(): old_purchase_token: The purchase token of the currently active subscription replacement_mode: The replacement mode to apply to the subscription product_id: The product ID of the new subscription to switch to base_plan_id: The base plan ID of the target subscription offer_id: The offer ID under the base plan (optional) is_offer_personalized: Whether to enable personalized pricing (optional) The replacement modes values are defined as: # Access in your script as: BillingClient.ReplacementMode.WITH_TIME_PRORATION enum ReplacementMode { # Unknown... UNKNOWN_REPLACEMENT_MODE = 0, # The new plan takes effect immediately, and the remaining time will be prorated and credited to the user. # Note: This is the default behavior. WITH_TIME_PRORATION = 1, # The new plan takes effect immediately, and the billing cycle remains the same. CHARGE_PRORATED_PRICE = 2, # The new plan takes effect immediately, and the new price will be charged on next recurrence time. WITHOUT_PRORATION = 3, # Replacement takes effect immediately, and the user is charged full price of new plan and # is given a full billing cycle of subscription, plus remaining prorated time from the old plan. CHARGE_FULL_PRICE = 5, # The new purchase takes effect immediately, the new plan will take effect when the old item expires. DEFERRED = 6, } Default behavior is WITH_TIME_PRORATION. Example use of update_subscription: billing_client.update_subscription(_active_subscription_purchase.purchase_token, \ BillingClient.ReplacementMode.WITH_TIME_PRORATION, "new_sub_product_id", "base_plan_id") Previous Next User-contributed notes Please read the User-contributed notes policy before submitting a comment.
GodotGooglePlayBilling
Pattern 8: AnimatedSprite2D Inherits: Node2D < CanvasItem < Node < Object Sprite node that contains multiple textures as frames to play for animation. Description AnimatedSprite2D is similar to the Sprite2D node, except it carries multiple textures as animation frames. Animations are created using a SpriteFrames resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The SpriteFrames resource can be configured in the editor via the SpriteFrames bottom panel. Tutorials 2D Sprite animation 2D Dodge The Creeps Demo Properties StringName animation &"default" String autoplay "" bool centered true bool flip_h false bool flip_v false int frame 0 float frame_progress 0.0 Vector2 offset Vector2(0, 0) float speed_scale 1.0 SpriteFrames sprite_frames Methods float get_playing_speed() const bool is_playing() const void pause() void play(name: StringName = &"", custom_speed: float = 1.0, from_end: bool = false) void play_backwards(name: StringName = &"") void set_frame_and_progress(frame: int, progress: float) void stop() Signals animation_changed() 🔗 Emitted when animation changes. animation_finished() 🔗 Emitted when the animation reaches the end, or the start if it is played in reverse. When the animation finishes, it pauses the playback. Note: This signal is not emitted if an animation is looping. animation_looped() 🔗 Emitted when the animation loops. frame_changed() 🔗 Emitted when frame changes. sprite_frames_changed() 🔗 Emitted when sprite_frames changes. Property Descriptions StringName animation = &"default" 🔗 void set_animation(value: StringName) StringName get_animation() The current animation from the sprite_frames resource. If this value is changed, the frame counter and the frame_progress are reset. String autoplay = "" 🔗 void set_autoplay(value: String) String get_autoplay() The key of the animation to play when the scene loads. bool centered = true 🔗 void set_centered(value: bool) bool is_centered() If true, texture will be centered. Note: For games with a pixel art aesthetic, textures may appear deformed when centered. This is caused by their position being between pixels. To prevent this, set this property to false, or consider enabling ProjectSettings.rendering/2d/snap/snap_2d_vertices_to_pixel and ProjectSettings.rendering/2d/snap/snap_2d_transforms_to_pixel. bool flip_h = false 🔗 void set_flip_h(value: bool) bool is_flipped_h() If true, texture is flipped horizontally. bool flip_v = false 🔗 void set_flip_v(value: bool) bool is_flipped_v() If true, texture is flipped vertically. int frame = 0 🔗 void set_frame(value: int) int get_frame() The displayed animation frame's index. Setting this property also resets frame_progress. If this is not desired, use set_frame_and_progress(). float frame_progress = 0.0 🔗 void set_frame_progress(value: float) float get_frame_progress() The progress value between 0.0 and 1.0 until the current frame transitions to the next frame. If the animation is playing backwards, the value transitions from 1.0 to 0.0. Vector2 offset = Vector2(0, 0) 🔗 void set_offset(value: Vector2) Vector2 get_offset() The texture's drawing offset. float speed_scale = 1.0 🔗 void set_speed_scale(value: float) float get_speed_scale() The speed scaling ratio. For example, if this value is 1, then the animation plays at normal speed. If it's 0.5, then it plays at half speed. If it's 2, then it plays at double speed. If set to a negative value, the animation is played in reverse. If set to 0, the animation will not advance. SpriteFrames sprite_frames 🔗 void set_sprite_frames(value: SpriteFrames) SpriteFrames get_sprite_frames() The SpriteFrames resource containing the animation(s). Allows you the option to load, edit, clear, make unique and save the states of the SpriteFrames resource. Method Descriptions float get_playing_speed() const 🔗 Returns the actual playing speed of current animation or 0 if not playing. This speed is the speed_scale property multiplied by custom_speed argument specified when calling the play() method. Returns a negative value if the current animation is playing backwards. bool is_playing() const 🔗 Returns true if an animation is currently playing (even if speed_scale and/or custom_speed are 0). void pause() 🔗 Pauses the currently playing animation. The frame and frame_progress will be kept and calling play() or play_backwards() without arguments will resume the animation from the current playback position. See also stop(). void play(name: StringName = &"", custom_speed: float = 1.0, from_end: bool = false) 🔗 Plays the animation with key name. If custom_speed is negative and from_end is true, the animation will play backwards (which is equivalent to calling play_backwards()). If this method is called with that same animation name, or with no name parameter, the assigned animation will resume playing if it was paused. void play_backwards(name: StringName = &"") 🔗 Plays the animation with key name in reverse. This method is a shorthand for play() with custom_speed = -1.0 and from_end = true, so see its description for more information. void set_frame_and_progress(frame: int, progress: float) 🔗 Sets frame and frame_progress to the given values. Unlike setting frame, this method does not reset the frame_progress to 0.0 implicitly. Example: Change the animation while keeping the same frame and frame_progress: GDScriptvar current_frame = animated_sprite.get_frame() var current_progress = animated_sprite.get_frame_progress() animated_sprite.play("walk_another_skin") animated_sprite.set_frame_and_progress(current_frame, current_progress) void stop() 🔗 Stops the currently playing animation. The animation position is reset to 0 and the custom_speed is reset to 1.0. See also pause(). Previous Next User-contributed notes Please read the User-contributed notes policy before submitting a comment.
&"default"
Reference Files
This skill includes comprehensive documentation in references/:
- 2d.md - 2D documentation
- 3d.md - 3D documentation
- api.md - Api documentation
- getting_started.md - Getting Started documentation
- other.md - Other documentation
- physics.md - Physics documentation
- scripting.md - Scripting documentation
Use view to read specific reference files when detailed information is needed.
Working with This Skill
For Beginners
Start with the getting_started or tutorials reference files for foundational concepts.
For Specific Features
Use the appropriate category reference file (api, guides, etc.) for detailed information.
For Code Examples
The quick reference section above contains common patterns extracted from the official docs.
Resources
references/
Organized documentation extracted from official sources. These files contain:
- Detailed explanations
- Code examples with language annotations
- Links to original documentation
- Table of contents for quick navigation
scripts/
Add helper scripts here for common automation tasks.
assets/
Add templates, boilerplate, or example projects here.
Notes
- This skill was automatically generated from official documentation
- Reference files preserve the structure and examples from source docs
- Code examples include language detection for better syntax highlighting
- Quick reference patterns are extracted from common usage examples in the docs
Updating
To refresh this skill with updated documentation:
- Re-run the scraper with the same configuration
- The skill will be rebuilt with the latest information