Revamping of the docs organisation for a more coherent TOC

Only the pages were moved so far and some empty ones created,
the up-to-date toctrees come in the next commit.

(cherry picked from commit b408bdb918)
This commit is contained in:
Julian Murgia
2017-03-29 13:59:20 +02:00
committed by Rémi Verschelde
parent 6a730cb057
commit 5e05011eae
148 changed files with 0 additions and 376 deletions

View File

@@ -0,0 +1,16 @@
.. _doc_2d_and_3d_keybindings:
2D and 3D keybindings
=====================
2D viewport
-----------
.. image:: /img/keybinds_2d.png
3D viewport
-----------
.. image:: /img/keybinds_3d.png

View File

@@ -0,0 +1,147 @@
.. _doc_command_line_tutorial:
Command line tutorial
=====================
.. highlight:: shell
Some developers like using the command line extensively. Godot is
designed to be friendly to them, so here are the steps for working
entirely from the command line. Given the engine relies on little to no
external libraries, initialization times are pretty fast, making it
suitable for this workflow.
Path
----
It is recommended that your godot binary is in your PATH environment
variable, so it can be executed easily from any place by typing
``godot``. You can do so on Linux by placing the Godot binary in
``/usr/local/bin`` and making sure it is called ``godot``.
Creating a project
------------------
Creating a project from the command line is simple, just navigate the
shell to the desired place and just make an engine.cfg file exist, even
if empty.
::
user@host:~$ mkdir newgame
user@host:~$ cd newgame
user@host:~/newgame$ touch engine.cfg
That alone makes for an empty Godot project.
Running the editor
------------------
Running the editor is done by executing godot with the ``-e`` flag. This
must be done from within the project directory, or a subdirectory,
otherwise the command is ignored and the project manager appears.
::
user@host:~/newgame$ godot -e
If a scene has been created and saved, it can be edited later by running
the same code with that scene as argument.
::
user@host:~/newgame$ godot -e scene.xml
Erasing a scene
---------------
Godot is friends with your filesystem, and will not create extra
metadata files, simply use ``rm`` to erase a file. Make sure nothing
references that scene, or else an error will be thrown upon opening.
::
user@host:~/newgame$ rm scene.xml
Running the game
----------------
To run the game, simply execute Godot within the project directory or
subdirectory.
::
user@host:~/newgame$ godot
When a specific scene needs to be tested, pass that scene to the command
line.
::
user@host:~/newgame$ godot scene.xml
Debugging
---------
Catching errors in the command line can be a difficult task because they
just fly by. For this, a command line debugger is provided by adding
``-d``. It works for both running the game or a simple scene.
::
user@host:~/newgame$ godot -d
::
user@host:~/newgame$ godot -d scene.xml
Exporting
---------
Exporting the project from the command line is also supported. This is
specially useful for continuous integration setups. The version of Godot
that is headless (server build, no video) is ideal for this.
::
user@host:~/newgame$ godot -export "Linux X11" /var/builds/project
user@host:~/newgame$ godot -export Android /var/builds/project.apk
The platform names recognized by the ``-export`` switch are the same as
displayed in the export wizard of the editor. To get a list of supported
platforms from the command line, just try exporting to a non-recognized
platform and the full listing of platforms your configuration supports
will be shown.
To export a debug version of the game, use the ``-export_debug`` switch
instead of ``-export``. Their parameters and usage are the same.
Running a script
----------------
It is possible to run a simple .gd script from the command line. This
feature is specially useful in very large projects, for batch
conversion of assets or custom import/export.
The script must inherit from SceneTree or MainLoop.
Here is a simple example of how it works:
.. code:: python
#sayhello.gd
extends SceneTree
func _init():
print("Hello!")
quit()
And how to run it:
::
user@host:~/newgame$ godot -s sayhello.gd
Hello!
If no engine.cfg exists at the path, current path is assumed to be the
current working directory (unless ``-path`` is specified).

View File

View File

View File

@@ -0,0 +1,187 @@
.. _unity3D_to_godot:
.. references :
.. https://wiki.unrealengine.com/Unity3D_Developer's_Guide_to_Unreal_Engine_4
.. https://docs.unrealengine.com/latest/INT/GettingStarted/FromUnity/
From Unity3D to Godot Engine
============================
This guide provides an overview of Godot Engine from the viewpoint of a Unity user, and aims to help you migrate your existing Unity experience into the world of Godot.
Differences
-----------
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| | Unity | Godot |
+===================+===================================================================================+================================================================================================================+
| License | Proprietary, closed, free license with revenue caps and usage restrictions | MIT License, free and fully open souce without any restriction |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| OS (editor) | Windows, OSX, Linux (unofficial and unsupported) | Windows, X11 (Linux, *BSD), Haiku, OSX |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| OS (export) | | Desktop: Windows, Linux/SteamOS, OSX | | Desktop: Windows, X11, OSX |
| | | Mobile: Android, iOS, Windows Phone, Tizen, | | Mobile: Android, iOS, Blackberry (deprecated) |
| | | Web: WebGL | | Web: WebGL, HTML5 (via emscripten, broken) |
| | | Consoles: PS4, PS Vita, XBox One, XBox 360, WiiU, 3DS | |
| | | VR: Occulus Rift, SteamVR, Google Cardboard, Playstation VR, Gear VR, HoloLens | |
| | | TV: AndroidTV, Samsung SMARTTV, tvOS | |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| Scene system | | Component/Scene (GameObject > Component) | Scene tree and nodes, allowing scenes to be nested and/or inherit other scenes |
| | | Prefabs | |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| Third-party tools | Visual Studio or SharpEditor | | Android SDK for Android export |
| | | | External editors are possible |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
| Killer features | | Huge community | | Scene System |
| | | Large assets store | | Animation Pipeline |
| | | | Easy to write Shaders |
| | | | Debug on Device |
| | | |
| | | |
+-------------------+-----------------------------------------------------------------------------------+----------------------------------------------------------------------------------------------------------------+
, , ,
The editor
----------
Godot Engine provides a rich-featured editor that allows you to build your games. The pictures below display both editors with colored blocks to indicate common functionalities.
.. image:: /img/unity-gui-overlay.png
.. image:: /img/godot-gui-overlay.png
Note that Godot editor allows you to dock each panel at the side of the scene editor you wish.
While both editors may seem similar, there are many differences below the surface. Both let you organize the project using the filesystem, but Godot approach is simpler, with a single configuration file, minimalist text format, and no metadata. All this contributes to Godot being much friendlier to VCS systems such as Git, Subversion or Mercurial.
Godot's Scene panel is similar to Unity's Hierarchy panel but, as each node has a specific function, the approach used by Godot is more visually descriptive. In other words, it's easier to understand what a specific scene does at a glance.
The Inspector in Godot is more minimalist and designed to only show properties. Thanks to this, objects can export a much larger amount of useful parameters to the user, without having to hide functionality in language APIs. As a plus, Godot allows animating any of those properties visually, so changing colors, textures, enumerations or even links to resources in real-time is possible without involving code.
Finally, the Toolbar at the top of the screen is similar in the sense that it allows controlling the project playback, but projects in Godot run in a separate window, as they don't execute inside the editor (but the tree and objects can still be explored in the debugger window).
This approach has the disadvantage that the running game can't be explored from different angles (though this may be supported in the future, and displaying collision gizmos in the running game is already possible), but in exchange has several advantages:
- Running the project and closing it is very fast (Unity has to save, run the project, close the project and then reload the previous state).
- Live editing is a lot more useful, because changes done to the editor take effect immediately in the game, and are not lost (nor have to be synced) when the game is closed. This allows fantastic workflows, like creating levels while you play them.
- The editor is more stable, because the game runs in a separate process.
Finally, the top toolbar includes a menu for remote debugging. These options make it simple to deploy to a device (connected phone, tablet or browser via HTML5), and debug/live edit on it after the game was exported.
The scene system
----------------
This is the most important difference between Unity and Godot, and actually the favourite feature of most Godot users.
Unity's scene system consist in embedding all the required assets in a scene, and link them together by setting components and scripts to them.
Godot's scene system is different: it actually consists in a tree made of nodes. Each node serves a purpose: Sprite, Mesh, Light... Basically, this is similar to Unity scene system. However, each node can have multiple children, which make each a subscene of the main scene. This means you can compose a whole scene with different scenes, stored in different files.
For example, think of a platformer level. You would compose it with multiple elements:
- Bricks
- Coins
- The player
- The enemies
In Unity, you would put all the GameObjects in the scene: the player, multiple instances of enemies, bricks everywhere to form the ground of the level, and multiple instances of coins all over the level. You would then add various components to each element to link them and add logic in the level: for example, you'd add a BoxCollider2D to all the elements of the scene so that they can collide. This principle is different in Godot.
In Godot, you would split your whole scene into 3 separate, smaller scenes, which you would then instance in the main scene.
1. First, a scene for the Player alone.
Consider the player as a reusable element in other levels. It is composed of one node in particular: an AnimatedSprite node, which contains the sprite textures to form various animations (for example, walking animation)
2. Second, a scene for the Enemy.
There again, an enemy is a reusable element in other levels. It is almost the same as the Player node - the only differences are the script (that manages IA, mostly) and sprite textures used by the AnimatedSprite.
3. Lastly, the Level scene.
It is composed of Bricks (for platforms), Coins (for the player to grab) and a certain number of instances of the previous Enemy scene. These will be different, separate enemies, whose behaviour and appearance will be the same as defined in the Enemy scene. Each instance is then considered as a node in the Level scene tree. Of course, you can set different properties for each enemy node (to change its color for example).
Finally, the main scene would then be composed of one root node with 2 children: a Player instance node, and a Level instance node.
The root node can be anything, generally a "root" type such as "Node" which is the most global type, or "Node2D" (root type of all 2D-related nodes), "Spatial" (root type of all 3D-related nodes) or "Control" (root type of all GUI-related nodes).
As you can see, every scene is organized as a tree. The same goes for nodes' properties: you don't *add* a collision component to a node to make it collidable like Unity does. Instead, you make this node a *child* of a new specific node that has collision properties. Godot features various collision types nodes, depending of the use (see the `Physics introduction <../tutorials/2d/physics_introduction>`_).
- Question: What are the advantages of this system? Wouldn't this system potentially increase the depth of the scene tree? Besides, Unity allows organizing GameObjects by putting them in empty GameObjects.
- First, this system is closer to the well-known Object-Oriented paradigm: Godot provides a number of nodes which are not clearly "Game Objects", but they provide their children with their own capabilities: this is inheritance.
- Second, it allows the extraction a subtree of scene to make it a scene of its own, which answers to the second and third questions: even if a scene tree gets too deep, it can be split into smaller subtrees. This also allows a better solution for reusability, as you can include any subtree as a child of any node. Putting multiple nodes in an empty GameObject in Unity does not provide the same possibility, apart from a visual organization.
These are the most important concepts you need to remind: "node", "parent node" and "child node".
Project organization
--------------------
.. image:: /img/unity-project-organization-example.png
We previously observed that there is no perfect solution to set a project architecture. Any solution will work for Unity and Godot, so this point has a lesser importance.
However, we often observe a common architecture for Unity projects, which consists in having one Assets folder in the root directory, that contains various folders, one per type of asset: Audio, Graphics, Models, Materials, Scripts, Scenes, etc.
As described before, Godot scene system allows splitting scenes in smaller scenes. Since each scene and subscene is actually one scene file in the project, we recommend organizing your project a bit differently. This wiki provides a page for this: `Project Organization <engine/project_organization.html>`_.
Where are my prefabs?
---------------------
The concept of prefabs as provided by Unity is a 'template' element of the scene. It is reusable, and each instance of the prefab that exists in the scene has an existence of its own, but all of them have the same properties as defined by the prefab.
Godot does not provide prefabs as such, but this functionality is here again filled thanks to its scene system: as we saw the scene system is organized as a tree. Godot allows you to save a subtree of a scene as its own scene, thus saved in its own file. This new scene can then be instanced as many times as you want. Any change you make to this new, separate scene will be applied to its instances. However, any change you make to the instance will not have any impact on the 'template' scene.
.. image:: /img/save-branch-as-scene.png
To be precise, you can modify the parameters of the instance in the Inspector panel. However, the nodes that compose this instance are locked and you can unlock them if you need to by clicking the clapperboard icon next to the instance in the Scene tree, and select "Editable children" in the menu. You don't need to do this to add new children nodes to this node, but remember that these new children will belong to the instance, not the 'template' scene. If you want to add new children to all the instances of your 'template' scene, then you need to add it once in the 'template' scene.
.. image:: /img/editable-children.png
Glossary correspondance
-----------------------
GameObject -> Node
Add a component -> Inheriting
Prefab -> Externalized branch
Scripting : From C# to GDScript
-------------------------------
Design
^^^^^^
As you may know already, Unity supports 2 scripting languages for its API: C# and Javascript (called UnityScript). Both languages can be used in the same project (but not in the same file, of course). Choosing one instead of the other is a matter of personal taste, as performances seem not to be affected that much by the use of Javascript as long as the project remains small. C# benefits from its integration with Visual Studio and other specific features, such as static typing.
Godot provides its own scripting language: GDScript. This language borrows its syntax to Python, but is not related to it. If you wonder about why GDScript and not Lua, C# or any other, please read `GDScript <gdscript>`_ and `FAQ <faq>`_ pages. GDScript is strongly attached to Godot API, but it is really easy to learn: between 1 evening for an experimented programmer and 1 week for a complete beginner.
Unity allows you to attach as many scripts as you want to a GameObject. Each script adds a behaviour to the GameObject: for example, you can attach a script so that it reacts to the player's controls, and another that controls its specific game logic.
In Godot, you can only attach one script per node. You can use either an external GDScript file, or include it directly in the node. If you need to attach more scripts to one node, then you may consider 2 solutions, depending on your scene and on what you want to achieve:
- either add a new node between your target node and its current parent, then add a script to this new node.
- or, your can split your target node into multiple children and attach one script to each of them.
As you can see, it can be easy to turn a scene tree to a mess. This is why it is important to have a real reflection, and consider splitting a complicated scene into multiple, smaller branches.
Connections : groups and signals
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can control nodes by accessing them using a script, and call functions (built-in or user-defined) on them. But there's more: you can also place them in a group and call a function on all nodes contained it this group! This is explained in `this page <../tutorials/step_by_step/scripting_continued#groups>`_.
But there's more! Certain nodes throw signals when certain actions happen. You can connect these signals to call a specific function when they happen. Note that you can define your own signals and send them whenever you want. This feature is documented `here <gdscript.html#signals>`_.
Using Godot in C++
------------------
Just for your information, Godot also allows you to develop your project directly in C++ by using its API, which is not possible with Unity at the moment. As an example, you can consider Godot Engine's editor as a "game" written in C++ using Godot API.
If you are interested in using Godot in C++, you may want to start reading the `Developing in C++ <_developing.html>`_ page.

View File

@@ -0,0 +1,99 @@
.. _doc_viewport_and_canvas_transforms:
Viewport and canvas transforms
==============================
Introduction
------------
This tutorial is created after a topic that is a little dark for most
users, and explains all the 2D transforms going on for nodes from the
moment they draw their content locally to the time they are drawn into
the screen.
Canvas transform
----------------
As mentioned in the previous tutorial, :ref:`doc_canvas_layers`, every
CanvasItem node (remember that Node2D and Control based nodes use
CanvasItem as their common root) will reside in a *Canvas Layer*. Every
canvas layer has a transform (translation, rotation, scale, etc.) that
can be accessed as a :ref:`Matrix32 <class_Matrix32>`.
Also covered in the previous tutorial, nodes are drawn by default in Layer 0,
in the built-in canvas. To put nodes in a different layer, a :ref:`CanvasLayer
<class_CanvasLayer>` node can be used.
Global canvas transform
-----------------------
Viewports also have a Global Canvas transform (also a
:ref:`Matrix32 <class_Matrix32>`). This is the master transform and
affects all individual *Canvas Layer* transforms. Generally this
transform is not of much use, but is used in the CanvasItem Editor
in Godot's editor.
Stretch transform
-----------------
Finally, viewports have a *Stretch Transform*, which is used when
resizing or stretching the screen. This transform is used internally (as
described in :ref:`doc_multiple_resolutions`), but can also be manually set
on each viewport.
Input events received in the :ref:`MainLoop._input_event() <class_MainLoop__input_event>`
callback are multiplied by this transform, but lack the ones above. To
convert InputEvent coordinates to local CanvasItem coordinates, the
:ref:`CanvasItem.make_input_local() <class_CanvasItem_make_input_local>`
function was added for convenience.
Transform order
---------------
For a coordinate in CanvasItem local properties to become an actual
screen coordinate, the following chain of transforms must be applied:
.. image:: /img/viewport_transforms2.png
Transform functions
-------------------
Obtaining each transform can be achieved with the following functions:
+----------------------------------+--------------------------------------------------------------------------------------+
| Type | Transform |
+==================================+======================================================================================+
| CanvasItem | :ref:`CanvasItem.get_global_transform() <class_CanvasItem_get_global_transform>` |
+----------------------------------+--------------------------------------------------------------------------------------+
| CanvasLayer | :ref:`CanvasItem.get_canvas_transform() <class_CanvasItem_get_canvas_transform>` |
+----------------------------------+--------------------------------------------------------------------------------------+
| CanvasLayer+GlobalCanvas+Stretch | :ref:`CanvasItem.get_viewport_transform() <class_CanvasItem_get_viewport_transform>` |
+----------------------------------+--------------------------------------------------------------------------------------+
Finally then, to convert a CanvasItem local coordinates to screen
coordinates, just multiply in the following order:
::
var screen_coord = get_viewport_transform() * ( get_global_transform() * local_pos )
Keep in mind, however, that it is generally not desired to work with
screen coordinates. The recommended approach is to simply work in Canvas
coordinates (``CanvasItem.get_global_transform()``), to allow automatic
screen resolution resizing to work properly.
Feeding custom input events
---------------------------
It is often desired to feed custom input events to the scene tree. With
the above knowledge, to correctly do this, it must be done the following
way:
::
var local_pos = Vector2(10,20) # local to Control/Node2D
var ie = InputEvent()
ie.type = InputEvent.MOUSE_BUTTON
ie.button_index = BUTTON_LEFT
ie.pos = get_viewport_transform() * (get_global_transform() * local_pos)
get_tree().input_event(ie)

View File

@@ -0,0 +1,76 @@
.. _doc_canvas_layers:
Canvas layers
=============
Viewport and Canvas items
-------------------------
Regular 2D nodes, such as :ref:`Node2D <class_Node2D>` or
:ref:`Control <class_Control>` both inherit from
:ref:`CanvasItem <class_CanvasItem>`, which is the base for all 2D
nodes. CanvasItems can be arranged in trees and they will inherit
their transform. This means that when moving the parent, the children
will be moved too.
These nodes are placed as direct or indirect children to a
:ref:`Viewport <class_Viewport>`, and will be displayed through it.
Viewport has a property "canvas_transform"
:ref:`Viewport.set_canvas_transform() <class_Viewport_set_canvas_transform>`,
which allows to transform all the CanvasItem hierarchy by a custom
:ref:`Matrix32 <class_Matrix32>` transform. Nodes such as
:ref:`Camera2D <class_Camera2D>`, work by changing that transform.
Changing the canvas transform is useful because it is a lot more
efficient than moving the root canvas item (and hence the whole scene).
Canvas transform is a simple matrix that offsets the whole 2D drawing,
so it's the most efficient way to do scrolling.
Not enough...
-------------
But this is not enough. There are often situations where the game or
application may not want *everything* transformed by the canvas
transform. Examples of this are:
- **Parallax Backgrounds**: Backgrounds that move slower than the rest
of the stage.
- **HUD**: Head's up display, or user interface. If the world moves,
the life counter, score, etc. must stay static.
- **Transitions**: Effects used for transitions (fades, blends) may
also want it to remain at a fixed location.
How can these problems be solved in a single scene tree?
CanvasLayers
------------
The answer is :ref:`CanvasLayer <class_CanvasLayer>`,
which is a node that adds a separate 2D rendering layer for all its
children and grand-children. Viewport children will draw by default at
layer "0", while a CanvasLayer will draw at any numeric layer. Layers
with a greater number will be drawn above those with a smaller number.
CanvasLayers also have their own transform, and do not depend of the
transform of other layers. This allows the UI to be fixed in-place,
while the world moves.
An example of this is creating a parallax background. This can be done
with a CanvasLayer at layer "-1". The screen with the points, life
counter and pause button can also be created at layer "1".
Here's a diagram of how it looks:
.. image:: /img/canvaslayers.png
CanvasLayers are independent of tree order, and they only depend on
their layer number, so they can be instantiated when needed.
Performance
-----------
Even though there shouldn't be any performance limitation, it is not
advised to use excessive amount of layers to arrange drawing order of
nodes. The most optimal way will always be arranging them by tree order.
2d nodes also have a property for controlling their drawing order
(see :ref:`Node2D.set_z() <class_Node2D_set_z>`).

View File

@@ -0,0 +1,256 @@
.. _doc_custom_drawing_in_2d:
Custom drawing in 2D
====================
Why?
----
Godot has nodes to draw sprites, polygons, particles, and all sorts of
stuff. For most cases this is enough, but not always. Before crying in fear,
angst, and rage because a node to draw that-specific-something does not exist... it would
be good to know that it is possible to easily make any 2D node (be it
:ref:`Control <class_Control>` or :ref:`Node2D <class_Node2D>`
based) draw custom commands. It is *really* easy to do it too.
But...
------
Custom drawing manually in a node is *really* useful. Here are some
examples why:
- Drawing shapes or logic that is not handled by nodes (example: making
a node that draws a circle, an image with trails, a special kind of
animated polygon, etc).
- Visualizations that are not that compatible with nodes: (example: a
tetris board). The tetris example uses a custom draw function to draw
the blocks.
- Managing drawing logic of a large amount of simple objects (in the
hundreds of thousands). Using a thousand nodes is probably not nearly
as efficient as drawing, but a thousand of draw calls are cheap.
Check the "Shower of Bullets" demo as example.
- Making a custom UI control. There are plenty of controls available,
but it's easy to run into the need to make a new, custom one.
OK, how?
--------
Add a script to any :ref:`CanvasItem <class_CanvasItem>`
derived node, like :ref:`Control <class_Control>` or
:ref:`Node2D <class_Node2D>`. Override the _draw() function.
::
extends Node2D
func _draw():
#your draw commands here
pass
Draw commands are described in the :ref:`CanvasItem <class_CanvasItem>`
class reference. There are plenty of them.
Updating
--------
The _draw() function is only called once, and then the draw commands
are cached and remembered, so further calls are unnecessary.
If re-drawing is required because a state or something else changed,
simply call :ref:`CanvasItem.update() <class_CanvasItem_update>`
in that same node and a new _draw() call will happen.
Here is a little more complex example. A texture variable that will be
redrawn if modified:
::
extends Node2D
export var texture setget _set_texture
func _set_texture(value):
#if the texture variable is modified externally,
#this callback is called.
texture=value #texture was changed
update() #update the node
func _draw():
draw_texture(texture,Vector2())
In some cases, it may be desired to draw every frame. For this, just
call update() from the _process() callback, like this:
::
extends Node2D
func _draw():
#your draw commands here
pass
func _process(delta):
update()
func _ready():
set_process(true)
An example: drawing circular arcs
----------------------------------
We will now use the custom drawing functionality of the Godot Engine to draw something that Godot doesn't provide functions for. As an example, Godot provides a draw_circle() function that draws a whole circle. However, what about drawing a portion of a circle? You will have to code a function to perform this, and draw it yourself.
Arc function
^^^^^^^^^^^^
An arc is defined by its support circle parameters, that is: the center position, and the radius. And the arc itself is then defined by the angle it starts from, and the angle it stops at. These are the 4 parameters we have to provide to our drawing. We'll also provide the color value so we can draw the arc in different colors if we wish.
Basically, drawing a shape on screen requires it to be decomposed into a certain number of points linked one to the following one. As you can imagine, the more points your shape is made of, the smoother it will appear, but the heavier it will be in terms of processing cost. In general, if your shape is huge (or in 3D, close to the camera), it will require more points to be drawn without showing angular-looking. On the contrary, if you shape is small (or in 3D, far from the camera), you may reduce its number of points to save processing costs. This is called *Level of Detail (LoD)*. In our example, we will simply use a fixed number of points, no matter the radius.
::
func draw_circle_arc( center, radius, angle_from, angle_to, color ):
var nb_points = 32
var points_arc = Vector2Array()
for i in range(nb_points+1):
var angle_point = angle_from + i*(angle_to-angle_from)/nb_points - 90
var point = center + Vector2( cos(deg2rad(angle_point)), sin(deg2rad(angle_point)) ) * radius
points_arc.push_back( point )
for indexPoint in range(nb_points):
draw_line(points_arc[indexPoint], points_arc[indexPoint+1], color)
Remember the number of points our shape has to be decomposed into? We fixed this number in the nb_points variable to a value of 32. Then, we initialize an empty Vector2Array, which is simply an array of Vector2.
Next step consists in computing the actual positions of these 32 points that compose arc. This is done in the first for-loop: we iterate over the number of points we want to compute the positions, plus one to include the last point. We first determine the angle of each point, between the starting and ending angles.
The reason why each angle is reduced of 90° is that we will compute 2D positions out of each angle using trigonometry (you know, cosine and sine stuff...). However, to be simple, cos() and sin() use radians, not degrees. The angle of 0° (0 radian) starts at 3 o'clock, although we want to start counting at 0 o'clock. So, we just reduce each angle of 90° in order to start counting from 0'clock.
The actual position of a point located on a circle at angle 'angle' (in radians) is given by Vector2(cos(angle), sin(angle)). Since cos() and sin() return values between -1 and 1, the position is located on a circle of radius 1. To have this position on our support circle, which has a radius of 'radius', we simply need to multiply the position by 'radius'. Finally, we need to position our support circle at the 'center' position, which is performed by adding it to our Vector2 value. Finally, we insert the point in the Vector2Array which was previously defined.
Now, we need to actually draw our points. As you can imagine, we will not simply draw our 32 points: we need to draw everything that is between each of them. We could have computed every point ourselves using the previous method, and draw it one by one, but this it too complicated and inefficient (except if explicitly needed). So, we simply draw lines between each pair of points. Unless the radius of our support circle is very big, the length of each line between a pair of points will never be long enough to see them. If this happens, we simply would need to increase the number of points.
Draw the arc on screen
^^^^^^^^^^^^^^^^^^^^^^
We now have a function that draws stuff on screen: it is time to call it in the _draw() function.
::
func _draw():
var center = Vector2(200,200)
var radius = 80
var angle_from = 75
var angle_to = 195
var color = Color(1.0, 0.0, 0.0)
draw_circle_arc( center, radius, angle_from, angle_to, color )
Result:
.. image:: /img/result_drawarc.png
Arc polygon function
^^^^^^^^^^^^^^^^^^^^
We can take this a step further and write a function that draws the plain portion of the disc defined by the arc, not only its shape. The method is exactly the same a previously, except that we draw a polygon instead of lines:
::
func draw_circle_arc_poly( center, radius, angle_from, angle_to, color ):
var nb_points = 32
var points_arc = Vector2Array()
points_arc.push_back(center)
var colors = ColorArray([color])
for i in range(nb_points+1):
var angle_point = angle_from + i*(angle_to-angle_from)/nb_points - 90
points_arc.push_back(center + Vector2( cos( deg2rad(angle_point) ), sin( deg2rad(angle_point) ) ) * radius)
draw_polygon(points_arc, colors)
.. image:: /img/result_drawarc_poly.png
Dynamic custom drawing
^^^^^^^^^^^^^^^^^^^^^^
Alright, we are now able to draw custom stuff on screen. However, it is very static: let's make this shape turn around the center. The solution to do this is simply to change the angle_from and angle_to values over time. For our example, we will simply increment them by 50. This increment value has to remain constant, else the rotation speed will change accordingly.
First, we have to make both angle_from and angle_to variables global at the top of our script. Also note that you can store them in other nodes and access them using get_node().
::
extends Node2D
var rotation_ang = 50
var angle_from = 75
var angle_to = 195
We make these values change in the _process(delta) function. To activate this function, we need to call set_process(true) in the _ready() function.
We also increment our angle_from and angle_to values here. However, we must not forget to wrap() the resulting values between 0 and 360°! That is, if the angle is 361°, then it is actually 1°. If you don't wrap these values, the script will work correctly but angles values will grow bigger and bigger over time, until they reach the maximum integer value Godot can manage (2^31 - 1). When this happens, Godot may crash or produce unexpected behavior. Since Godot doesn't provide a wrap() function, we'll create it here, as it is relatively simple.
Finally, we must not forget to call the update() function, which automatically calls _draw(). This way, you can control when you want to refresh the frame.
::
func _ready():
set_process(true)
func wrap(value, min_val, max_val):
var f1 = value - min_val
var f2 = max_val - min_val
return fmod(f1, f2) + min_val
func _process(delta):
angle_from += rotation_ang
angle_to += rotation_ang
# we only wrap angles if both of them are bigger than 360
if (angle_from > 360 && angle_to > 360):
angle_from = wrap(angle_from, 0, 360)
angle_to = wrap(angle_to, 0, 360)
update()
Also, don't forget to modify the _draw() function to make use of these variables:
::
func _draw():
var center = Vector2(200,200)
var radius = 80
var color = Color(1.0, 0.0, 0.0)
draw_circle_arc( center, radius, angle_from, angle_to, color )
Let's run!
It works, but the arc is rotating insanely fast! What's wrong?
The reason is that your GPU is actually displaying the frames as fast as he can. We need to "normalize" the drawing by this speed. To achieve, we have to make use of the 'delta' parameter of the _process() function. 'delta' contains the time elapsed between the two last rendered frames. It is generally small (about 0.0003 seconds, but this depends on your hardware). So, using 'delta' to control your drawing ensures your program to run at the same speed on every hardware.
In our case, we simply need to multiply our 'rotation_ang' variable by 'delta' in the _process() function. This way, our 2 angles will be increased by a much smaller value, which directly depends on the rendering speed.
::
func _process(delta):
angle_from += rotation_ang * delta
angle_to += rotation_ang * delta
# we only wrap angles if both of them are bigger than 360
if (angle_from > 360 && angle_to > 360):
angle_from = wrap(angle_from, 0, 360)
angle_to = wrap(angle_to, 0, 360)
update()
Let's run again! This time, the rotation displays fine!
Tools
-----
Drawing your own nodes might also be desired while running them in the
editor, to use as preview or visualization of some feature or
behavior.
Remember to just use the "tool" keyword at the top of the script
(check the :ref:`doc_gdscript` reference if you forgot what this does).

View File

@@ -0,0 +1,260 @@
.. _doc_particle_systems_2d:
Particle Systems (2D)
=====================
Intro
-----
A simple (but flexible enough for most uses) particle system is
provided. Particle systems are used to simulate complex physical effects
such as sparks, fire, magic particles, smoke, mist, magic, etc.
The idea is that a "particle" is emitted at a fixed interval and with a
fixed lifetime. During his lifetime, every particle will have the same
base behavior. What makes every particle different and provides a more
organic look is the "randomness" associated to each parameter. In
essence, creating a particle system means setting base physics
parameters and then adding randomness to them.
Particles2D
~~~~~~~~~~~
Particle systems are added to the scene via the
:ref:`Particles2D <class_Particles2D>`
node. They are enabled by default and start emitting white points
downwards (as affected by the gravity). This provides a reasonable
starting point to start adapting it to our needs.
.. image:: /img/particles1.png
Texture
~~~~~~~
A particle system uses a single texture (in the future this might be
extended to animated textures via spritesheet). The texture is set via
the relevant texture property:
.. image:: /img/particles2.png
Physics variables
-----------------
Before taking a look at the global parameters for the particle system,
let's first see what happens when the physics variables are tweaked.
Direction
---------
This is the base angle at which particles emit. Default is 0 (down):
.. image:: /img/paranim1.gif
Changing it will change the emissor direction, but gravity will still
affect them:
.. image:: /img/paranim2.gif
This parameter is useful because, by rotating the node, gravity will
also be rotated. Changing direction keeps them separate.
Spread
------
Spread is the angle at which particles will randomly be emitted.
Increasing the spread will increase the angle. A spread of 180 will emit
in all directions.
.. image:: /img/paranim3.gif
Linear velocity
---------------
Linear velocity is the speed at which particles will be emitted (in
pixels/sec). Speed might later be modified by gravity or other
accelerations (as described further below).
.. image:: /img/paranim4.gif
Spin velocity
-------------
Spin velocity is the speed at which particles turn around their center
(in degrees/sec).
.. image:: /img/paranim5.gif
Orbit velocity
--------------
Orbit velocity is used to make particles turn around their center.
.. image:: /img/paranim6.gif
Gravity direction & strength
----------------------------
Gravity can be modified as in direction and strength. Gravity affects
every particle currently alive.
.. image:: /img/paranim7.gif
Radial acceleration
-------------------
If this acceleration is positive, particles are accelerated away from
the center. If negative, they are absorbed towards it.
.. image:: /img/paranim8.gif
Tangential acceleration
-----------------------
This acceleration will use the tangent vector to the center. Combining
with radial acceleration can do nice effects.
.. image:: /img/paranim9.gif
Damping
-------
Damping applies friction to the particles, forcing them to stop. It is
specially useful for sparks or explosions, which usually begin with a
high linear velocity and then stop as they fade.
.. image:: /img/paranim10.gif
Initial angle
-------------
Determines the initial angle of the particle (in degress). This parameter
is mostly useful randomized.
.. image:: /img/paranim11.gif
Initial & final size
--------------------
Determines the initial and final scales of the particle.
.. image:: /img/paranim12.gif
Color phases
------------
Particles can use up to 4 color phases. Each color phase can include
transparency.
Phases must provide an offset value from 0 to 1, and always in
ascending order. For example, a color will begin at offset 0 and end
in offset 1, but 4 colors might use different offsets, such as 0, 0.2,
0.8 and 1.0 for the different phases:
.. image:: /img/particlecolorphases.png
Will result in:
.. image:: /img/paranim13.gif
Global parameters
-----------------
These parameters affect the behavior of the entire system.
Lifetime
--------
The time in seconds that every particle will stay alive. When lifetime
ends, a new particle is created to replace it.
Lifetime: 0.5
.. image:: /img/paranim14.gif
Lifetime: 4.0
.. image:: /img/paranim15.gif
Timescale
---------
It happens often that the effect achieved is perfect, except too fast or
too slow. Timescale helps adjust the overall speed.
Timescale everything 2x:
.. image:: /img/paranim16.gif
Preprocess
----------
Particle systems begin with 0 particles emitted, then start emitting.
This can be an inconvenience when just loading a scene and systems like
a torch, mist, etc begin emitting the moment you enter. Preprocess is
used to let the system process a given amount of seconds before it is
actually shown the first time.
Emit timeout
------------
This variable will switch emission off after given amount of seconds
being on. When zero, itś disabled.
Offset
------
Allows to move the emission center away from the center
Half extents
------------
Makes the center (by default 1 pixel) wider, to the size in pixels
desired. Particles will emit randomly inside this area.
.. image:: /img/paranim17.gif
It is also possible to set an emission mask by using this value. Check
the "Particles" menu on the 2D scene editor viewport and select your
favorite texture. Opaque pixels will be used as potential emission
location, while transparent ones will be ignored:
.. image:: /img/paranim19.gif
Local space
-----------
By default this option is on, and it means that the space that particles
are emitted to is contained within the node. If the node is moved, all
particles are moved with it:
.. image:: /img/paranim20.gif
If disabled, particles will emit to global space, meaning that if the
node is moved, the emissor is moved too:
.. image:: /img/paranim21.gif
Explosiveness
-------------
If lifetime is 1 and there are 10 particles, it means every particle
will be emitted every 0.1 seconds. The explosiveness parameter changes
this, and forces particles to be emitted all together. Ranges are:
- 0: Emit all particles together.
- 1: Emit particles at equal interval.
Values in the middle are also allowed. This feature is useful for
creating explosions or sudden bursts of particles:
.. image:: /img/paranim18.gif
Randomness
----------
All physics parameters can be randomized. Random variables go from 0 to
1. the formula to randomize a parameter is:
::
initial_value = param_value + param_value*randomness

View File

@@ -0,0 +1,165 @@
.. _doc_using_tilemaps:
Using tilemaps
~~~~~~~~~~~~~~
Introduction
------------
Tilemaps are a simple and quick way to make 2D game levels. Basically,
you start with bunch of reference tiles (or pieces) that can be put in a
grid, as many times each as desired:
.. image:: /img/tilemap.png
Collisions can also be added to the tiles, allowing for both 2D side
scrolling and top down games.
Making a tileset
----------------
To begin, a tileset needs to be made. Here are some tiles for it.
They are all in the same image because artists will often prefer this.
Having them as separate images also works.
.. image:: /img/tileset.png
Create a new project and move the above png image into the directory.
We will be creating a :ref:`TileSet <class_TileSet>`
resource. While this resource exports properties, it's pretty difficult
to get complex data into it and maintain it. Here is what it would look like to
manually edit the resource:
.. image:: /img/tileset_edit_resource.png
There's enough properties to get by, and with some effort editing this
way can work, but the easiest way to edit and maintain a tileset is exporting
it from a specially-crafted scene!
TileSet scene
-------------
Create a new scene with a regular node or node2d as root. For each tile,
add a sprite as a child. Since tiles here are 50x50, enabling snap might be
a good idea.
If more than one tile is present in the source image, make sure to use
the region property of the sprite to adjust which part of the texture is being
used.
Finally, make sure to name your sprite node correctly, this will ensure
that, in subsequent edits to the tileset (for example, if added
collision, changed the region, etc), the tile will still be **identified
correctly and updated**. This name should be unique.
Sounds like a lot of requirements, so here's a screenshot that shows
where everything of relevance is:
.. image:: /img/tile_example.png
Continue adding all the tiles, adjusting the offsets if needed (if you have
multiple tiles in a single source image). Again, remember that their names must
be unique.
.. image:: /img/tile_example2.png
Collision
---------
To add collision to a tile, create a StaticBody2D child for each sprite.
This is a static collision node. Then, as a child of the StaticBody2D,
create a CollisionShape2D or CollisionPolygon. The latter is recommended
because it is easier to edit:
.. image:: /img/tile_example3.png
Finally, edit the polygon, this will give the tile a collision.
**Remember to use snap!**. Using snap will make sure collision polygons
are aligned properly, allowing a character to walk seamlessly from tile
to tile. Also **do not scale or move** the collision and/or collision
polygon nodes. leave them at offset 0,0, with scale 1,1 and rotation 0
respect to the parent sprite.
.. image:: /img/tile_example4.png
Keep adding collisions to tiles until we are done. Note that BG is just
a background, so it should not have a collision.
.. image:: /img/tile_example5.png
OK! We're done! Remember to save this scene for future edit, call it
"tileset_edit.scn" or something like that.
Exporting a TileSet
-------------------
With the scene created and opened in the editor, next step will be to
create a tileset. Use Scene > Convert To > Tile Set from the Scene Menu:
.. image:: /img/tileset_export.png
Then choose a filename, like "mytiles.res". Make sure the "Merge With
Existing" option is toggled on. This way, every time the tileset
resource file is overwritten, existing tiles are merged and updated
(they are referenced by their unique name, so again, **name your tiles
properly**).
.. image:: /img/tileset_merge.png
Using the TileSet in a TileMap
------------------------------
Create a new scene, use any node or node2d as root, then create a
:ref:`TileMap <class_TileMap>` as
a child.
.. image:: /img/tilemap_scene.png
Go to the tileset property of this node and assign the one created in
previous steps:
.. image:: /img/tileset_property.png
Also set the cell size to '50', since that is the size used by the
tiles. Quadrant size is a tuning value, which means that the engine will
draw and cull the tilemap in blocks of 16x16 tiles. This value is
usually fine and does not need to be changed, but can be used to tune
performance in specific cases (if you know what you are doing).
Painting your world
-------------------
With all set, make sure the TileMap node is selected. A red grid will
appear on screen, allowing to paint on it with the selected tile on the
left palette.
.. image:: /img/tile_example6.png
To avoid moving and selecting the tilemap node accidentally (something
common given it's a huge node), it is recommended that you lock it,
using the lock button:
.. image:: /img/tile_lock.png
Offset and scaling artifacts
----------------------------
When using a single texture for all the tiles, scaling the tileset (or
even moving to a non pixel-aligned location) will most likely result in
filtering artifacts like this:
.. image:: /img/tileset_filter.png
This can't be avoided, as it is the way the hardware bilinear filter
works. So, to avoid this situation, there are a few workarounds, try the
ones that look better for you:
- Use a single image for each tile, this will remove all artifacts but
can be more cumbersome to implement, so try the options below first.
- Disable filtering for either the tileset texture or the entire image
loader (see the :ref:`doc_managing_image_files` asset pipeline tutorial).
- Enable pixel snap (set: "Scene > Project Settings >
Display/use_2d_pixel_snap" to true).
- Viewport Scaling can often help with shrinking the map (see the
:ref:`doc_viewports` tutorial).

View File

@@ -0,0 +1,189 @@
.. _doc_3d_performance_and_limitations:
3D performance and limitations
==============================
Introduction
~~~~~~~~~~~~
Godot follows a balanced performance philosophy. In performance world,
there are always trade-offs, which consist in trading speed for
usability and flexibility. Some practical examples of this are:
- Rendering objects efficiently in high amounts is easy, but when a
large scene must be rendered it can become inefficient. To solve
this, visibility computation must be added to the rendering, which
makes rendering less efficient, but at the same time less objects are
rendered, so efficiency overall improves.
- Configuring the properties of every material for every object that
needs to be renderer is also slow. To solve this, objects are sorted
by material to reduce the costs, but at the same time sorting has a
cost.
- In 3D physics a similar situation happens. The best algorithms to
handle large amounts of physics objects (such as SAP) are very slow
at insertion/removal of objects and ray-casting. Algorithms that
allow faster insertion and removal, as well as ray-casting will not
be able to handle as many active objects.
And there are many more examples of this! Game engines strive to be
general purpose in nature, so balanced algorithms are always favored
over algorithms that might be the fast in some situations and slow in
others.. or algorithms that are fast but make usability more difficult.
Godot is not an exception and, while it is designed to have backends
swappable for different algorithms, the default ones (or more like, the
only ones that are there for now) prioritize balance and flexibility
over performance.
With this clear, the aim of this tutorial is to explain how to get the
maximum performance out of Godot.
Rendering
~~~~~~~~~
3D rendering is one of the most difficult areas to get performance from,
so this section will have a list of tips.
Reuse shaders and materials
---------------------------
Godot renderer is a little different to what is out there. It's designed
to minimize GPU state changes as much as possible.
:ref:`FixedMaterial <class_FixedMaterial>`
does a good job at reusing materials that need similar shaders but, if
custom shaders are used, make sure to reuse them as much as possible.
Godot's priorities will be like this:
- **Reusing Materials**: The less amount of different materials in the
scene, the faster the rendering will be. If a scene has a huge amount
of objects (in the hundreds or thousands) try reusing the materials
or in the worst case use atlases.
- **Reusing Shaders**: If materials can't be reused, at least try to
re-use shaders (or FixedMaterials with different parameters but same
configuration).
If a scene has, for example, 20.000 objects with 20.000 different
materials each, rendering will be really slow. If the same scene has
20.000 objects, but only uses 100 materials, rendering will be blazing
fast.
Pixels cost vs vertex cost
--------------------------
It is a common thought that the lower the polygons in a model, the
faster it will be rendered. This is *really* relative and depends on
many factors.
On a modern PC and consoles, vertex cost is low. Very low. GPUs
originally only rendered triangles, so all the vertices:
1. Had to be transformed by the CPU (including clipping).
2. Had to be sent to the GPU memory from the main RAM.
Nowadays, all this is handled inside the GPU, so the performance is
extremely high. 3D artists usually have the wrong feeling about
polycount performance because 3D DCCs (such as Blender, Max, etc.) need
to keep geometry in CPU memory in order for it to be edited, reducing
actual performance. Truth is, a model rendered by a 3D engine is much
more optimal than how 3D DCCs display them.
On mobile devices, the story is different. PC and Console GPUs are
brute-force monsters that can pull as much electricity as they need from
the power grid. Mobile GPUs are limited to a tiny battery, so they need
to be a lot more power efficient.
To be more efficient, mobile GPUs attempt to avoid *overdraw*. This
means, the same pixel on the screen being rendered (as in, with lighting
calculation, etc.) more than once. Imagine a town with several buildings,
GPUs don't really know what is visible and what is hidden until they
draw it. A house might be drawn and then another house in front of it
(rendering happened twice for the same pixel!). PC GPUs normally don't
care much about this and just throw more pixel processors to the
hardware to increase performance (but this also increases power
consumption).
On mobile, pulling more power is not an option, so a technique called
"Tile Based Rendering" is used (almost every mobile hardware uses a
variant of it), which divide the screen into a grid. Each cell keeps the
list of triangles drawn to it and sorts them by depth to minimize
*overdraw*. This technique improves performance and reduces power
consumption, but takes a toll on vertex performance. As a result, less
vertices and triangles can be processed for drawing.
Generally, this is not so bad, but there is a corner case on mobile that
must be avoided, which is to have small objects with a lot of geometry
within a small portion of the screen. This forces mobile GPUs to put a
lot of strain on a single screen cell, considerably decreasing
performance (as all the other cells must wait for it to complete in
order to display the frame).
To make it short, do not worry about vertex count so much on mobile, but
avoid concentration of vertices in small parts of the screen. If, for
example, a character, NPC, vehicle, etc. is far away (so it looks tiny),
use a smaller level of detail (LOD) model instead.
An extra situation where vertex cost must be considered is objects that
have extra processing per vertex, such as:
- Skinning (skeletal animation)
- Morphs (shape keys)
- Vertex Lit Objects (common on mobile)
Texture compression
-------------------
Godot offers to compress textures of 3D models when imported (VRAM
compression). Video RAM compression is not as efficient in size as PNG
or JPG when stored, but increase performance enormously when drawing.
This is because the main goal of texture compression is bandwidth
reduction between memory and the GPU.
In 3D, the shapes of objects depend more on the geometry than the
texture, so compression is generally not noticeable. In 2D, compression
depends more on shapes inside the textures, so the artifacting resulting
from the compression is more noticeable.
As a warning, most Android devices do not support texture compression of
textures with transparency (only opaque), so keep this in mind.
Transparent objects
-------------------
As mentioned before, Godot sorts objects by material and shader to
improve performance. This, however, can not be done on transparent
objects. Transparent objects are rendered from back to front to make
blending with what is behind work. As a result, please try to keep
transparent objects to a minimum! If an object has a small section with
transparency, try to make that section a separate material.
Level of detail (LOD)
---------------------
As also mentioned before, using objects with less vertices can improve
performance in some cases. Godot has a very simple system to use level
of detail,
:ref:`GeometryInstance <class_GeometryInstance>`
based objects have a visibility range that can be defined. Having
several GeometryInstance objects in different ranges works as LOD.
Use instancing (MultiMesh)
--------------------------
If several identical objects have to be drawn in the same place or
nearby, try using :ref:`MultiMesh <class_MultiMesh>`
instead. MultiMesh allows drawing of dozens of thousands of objects at
very little performance cost, making it ideal for flocks, grass,
particles, etc.
Bake lighting
-------------
Small lights are usually not a performance issue. Shadows a little more.
In general, if several lights need to affect a scene, it's ideal to bake
it (:ref:`doc_light_baking`). Baking can also improve the scene quality by
adding indirect light bounces.
If working on mobile, baking to texture is recommended, since this
method is even faster.

View File

@@ -0,0 +1,183 @@
.. _doc_fixed_materials:
Fixed materials
===============
Introduction
------------
Fixed materials (originally Fixed Pipeline Materials) are the most
common type of materials, using the most common material options found
in 3D DCCs (such as Maya, 3DS Max or Blender). The big advantage of
using them is that 3D artists are very familiar with this layout. They
also allow to try out different things quickly without the need of
writing shaders. Fixed Materials inherit from
:ref:`Material <class_Material>`,
which also has several options. If you haven't read it before, reading
the :ref:`doc_materials` tutorial is recommended.
Options
-------
Here is the list of all the options available for fixed materials:
.. image:: /img/fixed_materials.png
From this point, every option will be explained in detail:
Fixed flags
-----------
These are a set of flags that control general aspects of the material.
Use alpha
~~~~~~~~~
This flag needs to be active for transparent materials to blend with
what is behind, otherwise display will always be opaque. Do not enable
this flag unless the material really needs it, because it can severely
affect performance and quality. Materials with transparency also won't
cast shadows (unless they contain opaque areas and the "opaque
pre-pass" hint is turned on, see the :ref:`doc_materials` tutorial for more
information).
.. image:: /img/fixed_material_alpha.png
Use vertex colors
~~~~~~~~~~~~~~~~~
Vertex color painting is a very common technique to add detail to a
geometry. 3D DCCs all support this, and many even support baking
occlusion to it. Godot allows this information to be used in the fixed
material by modulating the diffuse color when enabled.
.. image:: /img/fixed_material_vcols.png
Point size
~~~~~~~~~~
Point size is used to set the point size (in pixels) for when rendering
points. This feature is mostly used in tools and HUDs.
Discard alpha
~~~~~~~~~~~~~
When alpha is enabled (see above) the transparent pixels are blended
with what is behind them. In some combinations (of using alpha to
render depth) it may be possible that transparent pixels cover other
objects.
If this is the case, enable this option for the material. This option
is often used in combination with "opaque pre-pass" hint (see the
:ref:`doc_materials` tutorial for more information).
Parameters
----------
Diffuse, specular, emission and specular exponent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
These are the base colors for the material.
- Diffuse color is responsible for the light that reaches the material,
and is diffusely back-scattered then. This color varies by the angle between
the face and the light and the distance to the light source
(in the case of spot and omni lights). It is
the color that best represents the material. It can also have alpha
(transparency).
- Specular color is the color of the reflected light and responsible
for shines. It is affected by the specular exponent.
- Emission is the color of the light generated within the material
(although it will not lit anything else around unless baking). This
color is constant.
- Specular Exponent (or "Shininess"/"Intensity" in some 3D DCCs) is the
way light is reflected. If the value is high, light is reflected
completely, otherwise it is diffused more and more.
Below is an example of how they interact:
.. image:: /img/fixed_material_colors.png
Shader & shader param
~~~~~~~~~~~~~~~~~~~~~
Regular shader materials allow custom lighting code. Fixed materials
come with four predefined shader types:
- **Lambert**: The standard diffuse light, where the amount of light is
proportional to the angle from the light emitter.
- **Wrap**: A variation on Lambert, where the "coverage" of the light
can be changed. This is useful for many types of materials such as
wood, clay, hair, etc.
- **Velvet**: This is similar to Lambert, but adds light scattering in
the edges. It's useful for leathers and some types of metals.
- **Toon**: Standard toon shading with a coverage parameter. The
specular component also becomes toon-ized.
.. image:: /img/fixed_material_shader.png
Detail & detail mix
~~~~~~~~~~~~~~~~~~~
Detail is a second diffuse texture which can be mixed with the first one
(more on textures later!). Detail blend and mix control how these are
added together, here's an example of what detail textures are for:
.. image:: /img/fixed_material_detail.png
Normal depth
~~~~~~~~~~~~
Normal depth controls the strength and the direction of normal-mapping.
If it is set to 1 (the default), the un-scaled normal map is applied.
Values larger than 1 make normal-mapping more pronounced (dents and bumps
become larger), while values smaller than 1 reduce the effect. A normal
depth of 0 disables normal-mapping. Negative values invert the normal map
so dents become bumps and vice versa. Here is an example showing the
influence of the normal depth on the outcome:
.. image:: /img/fixed_material_normal_depth.png
Glow
~~~~
This value controls how much of the color is sent to the glow buffer. It
can be greater than 1 for a stronger effect. For glow to work, a
WorldEnvironment must exist with Glow activated.
.. image:: /img/fixed_material_glow.png
Blend mode
~~~~~~~~~~
Objects are usually blended in Mix mode. Other blend modes (Add and Sub)
exist for special cases (usually particle effects, light rays, etc.) but
materials can be set to them:
.. image:: /img/fixed_material_blend.png
Point size, line width
~~~~~~~~~~~~~~~~~~~~~~
When drawing points or lines, the size of them can be adjusted here per
material.
Textures
--------
Almost all of the parameters above can have a texture assigned to them.
There are four options to where they can get their UV coordinates:
- **UV Coordinates (UV Array)**: This is the regular UV coordinate
array that was imported with the model.
- **UV x UV XForm**: UV Coordinates multiplied by the UV Xform matrix.
- **UV2 Coordinates**: Some imported models might have come with a
second set of UV coordinates. These are common for detail textures or
for baked light textures.
- **Sphere**: Spherical coordinates (difference of the normal at the
pixel by the camera normal).
The value of every pixel of the texture is multiplied by the original
parameter. This means that if a texture is loaded for diffuse, it will
be multiplied by the color of the diffuse color parameter. Same applies
to all the others except for specular exponent, which is replaced.

View File

@@ -0,0 +1,165 @@
.. _doc_high_dynamic_range:
High dynamic range
==================
Introduction
------------
Normally, an artist does all the 3D modelling, then all the texturing,
looks at his or her awesome looking model in the 3D DCC and says "looks
fantastic, ready for integration!" then goes into the game, lighting is
setup and the game runs.
So where does all this HDR stuff thing come from? The idea is that
instead of dealing with colors that go from black to white (0 to 1), we
use colors whiter than white (for example, 0 to 8 times white).
To be more practical, imagine that in a regular scene, the intensity
of a light (generally 1.0) is set to 5.0. The whole scene will turn
very bright (towards white) and look horrible.
After this the luminance of the scene is computed by averaging the
luminance of every pixel of it, and this value is used to bring the
scene back to normal ranges. This last operation is called
tone-mapping. Finally, we are at a similar place from where we
started:
.. image:: /img/hdr_tonemap.png
Except the scene is more contrasted, because there is a higher light
range in play. What is this all useful for? The idea is that the scene
luminance will change while you move through the world, allowing
situations like this to happen:
.. image:: /img/hdr_cave.png
Additionally, it is possible to set a threshold value to send to the
glow buffer depending on the pixel luminance. This allows for more
realistic light bleeding effects in the scene.
Linear color space
------------------
The problem with this technique is that computer monitors apply a
gamma curve to adapt better to the way the human eye sees. Artists
create their art on the screen too, so their art has an implicit gamma
curve applied to it.
The color space where images created in computer monitors exist is
called "sRGB". All visual content that people have on their computers
or download from the internet (such as pictures, movies, etc.)
is in this colorspace.
.. image:: /img/hdr_gamma.png
The mathematics of HDR require that we multiply the scene by different
values to adjust the luminance and exposure to different light ranges,
and this curve gets in the way as we need colors in linear space for
this.
Linear color space & asset pipeline
-----------------------------------
Working in HDR is not just pressing a switch. First, imported image
assets must be converted to linear space on import. There are two ways
to do this:
SRGB -> linear conversion on image import
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the most compatible way of using linear-space assets and it will
work everywhere including all mobile devices. The main issue with this
is loss of quality, as sRGB exists to avoid this same problem. Using 8
bits per channel to represent linear colors is inefficient from the
point of view of the human eye. These textures might be later compressed
too, which makes the problem worse.
In any case though, this is the easy solution that works everywhere.
Hardware sRGB -> linear conversion.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is the most correct way to use assets in linear-space, as the
texture sampler on the GPU will do the conversion after reading the
texel using floating point. This works fine on PC and consoles, but most
mobile devices do no support it, or do not support it on compressed
texture format (iOS for example).
Linear -> sRGB at the end.
~~~~~~~~~~~~~~~~~~~~~~~~~~
After all the rendering is done, the linear-space rendered image must be
converted back to sRGB. To do this, simply enable sRGB conversion in the
current :ref:`Environment <class_Environment>` (more on that below).
Keep in mind that sRGB [STRIKEOUT:> Linear and Linear]> sRGB conversions
must always be **both** enabled. Failing to enable one of them will
result in horrible visuals suitable only for avant garde experimental
indie games.
Parameters of HDR
-----------------
HDR is found in the :ref:`Environment <class_Environment>`
resource. These are found most of the time inside a
:ref:`WorldEnvironment <class_WorldEnvironment>`
node, or set in a camera. There are many parameters for HDR:
.. image:: /img/hdr_parameters.png
ToneMapper
~~~~~~~~~~
The ToneMapper is the heart of the algorithm. Many options for
tonemappers are provided:
- Linear: Simplest tonemapper. It does its job for adjusting scene
brightness, but if the differences in light are too big, it will
cause colors to be too saturated.
- Log: Similar to linear, but not as extreme.
- Reinhardt: Classical tonemapper (modified so it will not desaturate
as much)
- ReinhardtAutoWhite: Same as above, but uses the max scene luminance
to adjust the white value.
Exposure
~~~~~~~~
The same exposure parameter as in real cameras. Controls how much light
enters the camera. Higher values will result in a brighter scene and
lower values will result in a darker scene.
White
~~~~~
Maximum value of white.
Glow threshold
~~~~~~~~~~~~~~
Determine above which value (from 0 to 1 after the scene is tonemapped),
light will start bleeding.
Glow scale
~~~~~~~~~~
Determine how much light will bleed.
Min luminance
~~~~~~~~~~~~~
Lower bound value of light for the scene at which the tonemapper stops
working. This allows dark scenes to remain dark.
Max luminance
~~~~~~~~~~~~~
Upper bound value of light for the scene at which the tonemapper stops
working. This allows bright scenes to remain saturated.
Exposure adjustment speed
~~~~~~~~~~~~~~~~~~~~~~~~~
Auto-exposure will change slowly and will take a while to adjust (like
in real cameras). Bigger values means faster adjustment.

View File

@@ -0,0 +1,59 @@
.. _doc_importing_3d_meshes:
Importing 3D meshes
===================
Introduction
------------
Godot supports a flexible and powerful :ref:`3D scene importer
<doc_importing_3d_scenes>` that allows for full scene importing. For a lot of
artists and developers this is more than enough. However, many do not like this
workflow as much and prefer to import individual 3D Meshes and build the scenes
inside the Godot 3D editor themselves. (Note that for more advanced features
such as skeletal animation, there is no option to the 3D Scene Importer).
The 3D mesh import workflow is simple and works using the OBJ file
format. The imported meshes result in a .msh binary file which the user
can put into a :ref:`class_meshinstance`, which in turn can be placed
somewhere in the edited scene.
Importing
---------
Importing is done through the Import 3D Mesh menu:
.. image:: /img/mesh_import.png
Which opens the Mesh import window:
.. image:: /img/mesh_dialog.png
This dialog allows the import of one more more OBJ files into a target
path. OBJ files are converted to .msh files. Files are imported without
any material on them, material has to be added by the user (see the
:ref:`doc_fixed_materials` tutorial). If the external OBJ file is changed it
will be re-imported, while keeping the newly assigned material.
Options
-------
A few options are present. Normals are needed for regular shading, while
Tangents are needed if you plan to use normal-mapping on the material. In
general, OBJ files describe how to be shaded very well, but an option to
force smooth shading is available.
Finally, there is an option to weld vertices. Given OBJ files are
text-based, it is common to find some of these with vertices that do not
match, which results in strange shading. The weld vertices option merges
vertices that are too close to keep proper smooth shading.
Usage
-----
Mesh resources (what this importer imports to) are used inside MeshInstance
nodes. Simply set them to the Mesh property of them.
.. image:: /img/3dmesh_instance.png
And that is it.

View File

@@ -0,0 +1,434 @@
.. _doc_importing_3d_scenes:
Importing 3D scenes
===================
Introduction
------------
Most game engines just import 3D objects, which may contain skeletons or
animations, and then all further work is done in the engine UI, like
object placement, full scene animations, etc. In Godot, given the node
system is very similar to how 3D DCC tools (such as Maya, 3DS Max or Blender)
work, full 3D scenes can be imported in all their glory. Additionally, by using
a simple language tag system, it is possible to specify that objects are
imported as several things, such as collidable, rooms and portals, vehicles
and wheels, LOD distances, billboards, etc.
This allows for some interesting features:
- Importing simple scenes, rigged objects, animations, etc.
- Importing full scenes. Entire scenarios can be created and updated in
the 3D DCC and imported to Godot each time they change, then only
little editing is needed from the engine side.
- Full cutscenes can be imported, including multiple character
animation, lighting, camera motion, etc.
- Scenes can be further edited and scripted in the engine, where
shaders and environment effects can be added, enemies can be
instanced, etc. The importer will update geometry changes if the
source scene changes but keep the local changes too (in real-time
while using the Godot editor!)
- Textures can be all batch-imported and updated when the source scene
changes.
This is achieved by using a very simple language tag that will be
explained in detail later.
Exporting DAE files
-------------------
Why not FBX?
~~~~~~~~~~~~
Most game engines use the FBX format for importing 3D scenes, which is
definitely one of the most standardized in the industry. However, this
format requires the use of a closed library from Autodesk which is
distributed with a more restrictive licensing terms than Godot. The plan
is, sometime in the future, to implement an external conversion binary,
but meanwhile FBX is not really supported.
Exporting DAE files from Maya and 3DS Max
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Autodesk added built-in collada support to Maya and 3DS Max, but it's
really broken and should not be used. The best way to export this format
is by using the
`OpenCollada <https://github.com/KhronosGroup/OpenCOLLADA/wiki/OpenCOLLADA-Tools>`__
plugins. They work really well, although they are not always up-to date
with the latest version of the software.
Exporting DAE files from Blender
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Blender also has built-in collada support, but it's really broken and
should not be used either.
Godot provides a `Python
Plugin <https://github.com/godotengine/collada-exporter>`__
that will do a much better job at exporting the scenes.
The import process
------------------
Import process begins with the 3D scene import menu:
.. image:: /img/3dimp_menu.png
That opens what is probably the biggest of all the import dialogs:
.. image:: /img/3dimp_dialog.png
Many options exist in there, so each section will be explained as
follows:
Source & target paths
~~~~~~~~~~~~~~~~~~~~~
To import, two options are needed. The first is a source .dae file
(.dae stands for Collada. More import formats will eventually added,
but Collada is the most complete open format as of this writing).
A target folder needs to be provided, so the importer can import the
scene there. The imported scene will have the same filename as the
source one, except for the .scn extension, so make sure you pick good
names when you export!
The textures will be copied and converted. Textures in 3D applications
are usually just PNG or JPG files. Godot will convert them to video
memory texture compression format (s3tc, pvrtc, ericsson, etc.) by
default to improve performance and save resources.
Since the original textures, 3D file and textures are usually not needed,
it's recommended to keep them outside the project. For some hints on
how to do this the best way, you can check the :ref:`doc_project_organization`
tutorial.
Two options for textures are provided. They can be copied to the same
place as the scene, or they can be copied to a common path (configurable
in the project settings). If you choose this, make sure no two textures
are named the same.
3D rigging tips
~~~~~~~~~~~~~~~
Before going into the options, here are some tips for making sure your
rigs import properly
- Only up to 4 weights are imported per vertex, if a vertex depends of
more than 4 bones, only the 4 most important bones (the one with the
most weight) will be imported. For most models this usually works
fine, but just keep it in mind.
- Do not use non-uniform scale in bone animation, as this will likely
not import properly. Try to accomplish the same effect with more
bones.
- When exporting from Blender, make sure that objects modified by a
skeleton are children of it. Many objects can be modified by a single
skeleton, but they all should be direct children.
- The same way, when using Blender, make sure that the relative
transform of children nodes to the skeleton is zero (no rotation, no
translation, no scale. All zero and scale at 1.0). The position of
both objects (the little orange dot) should be at the same place.
3D import options
~~~~~~~~~~~~~~~~~
This section contains many options to change the way import workflow
works. Some (like HDR) will be better explained in other sections, but
in general a pattern can be visible in the options and that is, many of
the options end with "-something". For example:
- Remove Nodes (-noimp)
- Set Alpha in Materials (-alpha)
- Create Collisions (-col).
This means that the object names in the 3D DCC need to have those
options appended at the end for the importer to tell what they are. When
imported, Godot will convert them to what they are meant to be.
**Note:** Maya users must use “_" (underscore) instead of "-" (minus).
Here is an example of how a scene in the 3D DCC looks (using Blender),
and how it is imported to Godot:
.. image:: /img/3dimp_blender.png
Notice that:
- The camera was imported normally.
- A Room was created (-room).
- A Portal was created (-portal).
- The Mesh got static collision added (-col).
- The Light was not imported (-noimp).
Options in detail
~~~~~~~~~~~~~~~~~
Following is a list of most import options and what they do in more
detail.
Remove nodes (-noimp)
^^^^^^^^^^^^^^^^^^^^^
Node names that have this at the end will be removed at import time, mo
matter their type. Erasing them afterwards is most of the times
pointless because the will be restored if the source scene changes.
Import animations
^^^^^^^^^^^^^^^^^
Some scene formats (.dae) support one or more animations. If this is
checked, an :ref:`class_animationplayer` node will be
created, containing the animations.
Compress geometry
^^^^^^^^^^^^^^^^^
This option (disabled [STRIKEOUT:or more like, always enabled] at the
moment at the time of writing this) will compress geometry so it takes
less space and renders faster (at the cost of less precision).
Force generation of tangent arrays
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The importer detects when you have used a normalmap texture, or when the
source file contains tangent/binormal information. These arrays are
needed for normalmapping to work, and most exporters know what they do
when they export this. However, it might be possible to run into source
scenes that do not have this information which, as a result, make
normal-mapping not work. If you notice that normal-maps do not work when
importing the scene, turn this on!
SRGB -> linear of diffuse textures
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When rendering using HDR (High Dynamic Range) it might be desirable to
use linear-space textures to achieve a more real-life lighting.
Otherwise, colors may saturate and contrast too much when exposure
changes. This option must be used together with the SRGB option in
:ref:`class_worldenvironment`. The texture import
options also have the option to do this conversion, but if this one is
turned on, conversion will always be done to diffuse textures (usually
what is desired). For more information, read the :ref:`doc_high_dynamic_range`
tutorial.
Set alpha in materials (-alpha)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
When working with most 3D DCCs, its pretty obvious when a texture is
transparent and has opacity and this rarely affects the workflow or
final rendering. However, when dealing with real-time rendering,
materials with alpha blending are usually less optimal to draw, so they
must be explicitly marked as such.
Originally Godot detected this based on whether if the source texture
had an alpha channel, but most image manipulation applications like Photoshop or
Gimp will export this channel anyway even if not used. Code was added
later to check manually if there really was any transparency in the
texture, but artists will anyway and very often lay uvmaps into opaque
parts of a texture and leave unused areas (where no UV exists)
transparent, making this detection worthless.
Finally, it was decided that it's best to import everything as opaque
and leave artists to fix materials that need transparency when it's
obvious that they are not looking right (see the :ref:`doc_materials`
tutorial).
As a helper, since every 3D DCC allows naming the materials and keeping
their name upon export, the (-alpha) modifier in their name will hint
the 3D scene importer in Godot that this material will use the alpha
channel for transparency.
Set vert. color in materials (-vcol)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Most 3D DCCs support vertex color painting. This is generally applied as
multiplication or screen blending. However, it is also often the case
that your exporter will export this information as all 1s, or export it
as something else and you will not realize it. Since most of the cases
this option is not desired, just add this to any material to confirm
that vertex colors are desired.
Create collisions (-col, -colonly)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Option "-col" will work only for Mesh nodes. If it is detected, a child
static collision node will be added, using the same geometry as the mesh.
However, it is often the case that the visual geometry is too complex or
too un-smooth for collisions, which end up not working well. To solve
this, the "-colonly" modifier exists, which will remove the mesh upon
import and create a :ref:`class_staticbody` collision instead.
This helps the visual mesh and actual collision to be separated.
Option "-colonly" can be also used with Blender's empty objects.
On import it will create a :ref:`class_staticbody` with
collision node as a child. Collision node will have one of predefined shapes,
depending on the Blender's empty draw type:
.. image:: /img/3dimp_BlenderEmptyDrawTypes.png
- Single arrow will create :ref:`class_rayshape`
- Cube will create :ref:`class_boxshape`
- Image will create :ref:`class_planeshape`
- Sphere (and other non-listed) will create :ref:`class_sphereshape`
For better visibility in Blender's editor user can set "X-Ray" option on collision
empties and set some distinct color for them in User Preferences / Themes / 3D View / Empty.
Create rooms (-room)
^^^^^^^^^^^^^^^^^^^^
This is used to create a room. As a general rule, any node that is a
child of this node will be considered inside the room (including
portals).
.. For more information about rooms/portals, look at the [[Portals and Rooms]] tutorial.
There are two ways in which this modifier can be used. The first is
using a Dummy/Empty node in the 3D application with the "-room" tag. For this to
work, the "interior" of the room must be closed (geometry of the
children should contain walls, roof, floor, etc. and the only holes to
the outside should be covered with portals). The importer will then
create a simplified version of the geometry for the room.
The second way is to use the "-room" modifier on a mesh node. This will
use the mesh as the base for the BSP tree that contains the room bounds.
Make sure that the mesh shape is **closed**, all normals **point
outside** and that the geometry is **not self-intersecting**, otherwise
the bounds may be computed wrong (BSP Trees are too picky and difficult
to work with, which is why they are barely used anymore..).
Anyway, the room will need portals, which are described next.
Create portals (-portal)
^^^^^^^^^^^^^^^^^^^^^^^^
Portals are the view to look outside a room. They are always some flat
shape on the surface of a room. If the portal is left alone, it is used
to activate occlusion when looking inside<->outside the room.
.. Again, more information on the [[Portals and Rooms]] tutorial.
Basically, the conditions to make and import a portal from the 3D DCC
are:
- It should be a child of a room.
- It should lay on the surface of the room (this doesn't need to be
super exact, just make it as close as you can by eye and Godot will
adjust it)
- It must be a flat, convex shape, any flat and convex shape is okay, no
matter the axis or size.
- Normals for the flat shape faces must **all point towards the
OUTSIDE** of the room.
Here is how it usually looks:
.. image:: /img/3dimp_portal.png
To connect to rooms, simply make two identical portals for both rooms
and place them overlapped. This does not need to be perfectly exact,
again, as Godot will fix it.
[..]
^^^^
The rest of the tags in this section should be rather obvious, or will
be documented/changed in the future.
Double-sidedness
~~~~~~~~~~~~~~~~
Collada and other formats support specifying the double-sidedness of
the geometry (in other words, when not double-sided, back-faces are
not drawn). Godot supports this option per Material, not per Geometry.
When exporting from 3D DCCs that work with per-object double-sidedness
(such as Blender of Maya), make sure that the double sided objects do
not share a material with the single sided ones or the importer will
not be able to discern.
Animation options
~~~~~~~~~~~~~~~~~
Some things to keep in mind when importing animations. 3D DCCs allow
animating with curves for every x,y,z component, doing IK constraints
and other stuff. When imported for real-time, animations are sampled
(at small intervals) so all this information is lost. Sampled
animations are fast to process, but can use considerable amounts of
memory.
Because of this, the "Optimize" option exists but, in some cases, this
option might break an animation, so make it sure to disable it if
you notice any issues.
Some animations are meant to be cycled (like walk animations) if this is
the case, animation names that end in "-cycle" or "-loop" are
automatically set to loop.
Import script
~~~~~~~~~~~~~
Creating a script to parse the imported scene is actually really simple.
This is great for post processing, changing materials, doing funny stuff
with the geometry, etc.
Create a script that basically looks like this:
::
tool # needed so it runs in editor
extends EditorScenePostImport
func post_import(scene):
# do your stuff here
return scene # remember to return the imported scene
The post-import function takes the imported scene as parameter (the
parameter is actually the root node of the scene).
Update logic
~~~~~~~~~~~~
Other types of resources (like samples, meshes, fonts, images, etc.) are
re-imported entirely when changed and user changes are not kept.
Because of 3D Scenes can be really complex, they use a different update
strategy. The user might have done local changes to take advantage of
the engine features and it would be really frustrating if everything is
lost on re-import because the source asset changed.
This led to the implementation of a special update strategy. The idea
behind is that the user will not lose anything he or she did, and only
added data or data that can't be edited inside Godot will be updated.
It works like this:
Strategy
^^^^^^^^
Upon changes on the source asset (ie: .dae), and on re-import, the
editor will remember the way the scene originally was, and will track
your local changes like renaming nodes, moving them or reparenting them.
Finally, the following will be updated:
- Mesh Data will be replaced by the data from the updated scene.
- Materials will be kept if they were not modified by the user.
- Portal and Room shapes will be replaced by the ones from the updated
scene.
- If the user moved a node inside Godot, the transform will be kept. If
the user moved a node in the source asset, the transform will be
replaced. Finally, if the node was moved in both places, the
transform will be combined.
In general, if the user deletes anything from the imported scene (node,
mesh, material, etc.), updating the source asset will restore what was
deleted. This is a good way to revert local changes to anything. If you
really don't want a node anymore in the scene, either delete it from
both places or add the "-noimp" tag to it in the source asset.
Fresh re-import
^^^^^^^^^^^^^^^
It can also happen that the source asset changed beyond recognition and
a full fresh re-import is desired. If so, simply re-open the 3D scene
import dialog from the Import -> Re-Import menu and perform re-import.

View File

@@ -0,0 +1,236 @@
.. _doc_introduction_to_3d:
Introduction to 3D
==================
Creating a 3D game can be challenging. That extra Z coordinate makes
many of the common techniques that helped to make 2D games simple no
longer work. To aid in this transition, it is worth mentioning that
Godot uses very similar APIs for 2D and 3D. Most nodes are the same and
are present in both 2D and 3D versions. In fact, it is worth checking
the 3D platformer tutorial, or the 3D kinematic character tutorials,
which are almost identical to their 2D counterparts.
In 3D, math is a little more complex than in 2D, so also checking the
:ref:`doc_vector_math` in the wiki (which were specially created for game
developers, not mathematicians or engineers) will help pave the way into
efficiently developing 3D games.
Spatial node
~~~~~~~~~~~~
:ref:`Node2D <class_Node2D>` is the base node for 2D.
:ref:`Control <class_Control>` is the base node for everything GUI.
Following this reasoning, the 3D engine uses the :ref:`Spatial <class_Spatial>`
node for everything 3D.
.. image:: /img/tuto_3d1.png
Spatial nodes have a local transform, which is relative to the parent
node (as long as the parent node is also **or inherits** of type
Spatial). This transform can be accessed as a 4x3
:ref:`Transform <class_Transform>`, or as 3 :ref:`Vector3 <class_Vector3>`
members representing location, Euler rotation (x,y and z angles) and
scale.
.. image:: /img/tuto_3d2.png
3D content
~~~~~~~~~~
Unlike 2D, where loading image content and drawing is straightforward,
3D is a little more difficult. The content needs to be created with
special 3D tool (usually referred to as DCCs) and exported to an
exchange file format in order to be imported in Godot (3D formats are
not as standardized as images).
DCC-created models
------------------
There are two pipelines to import 3D models in Godot. The first and most
common one is through the :ref:`doc_importing_3d_scenes` importer, which allows to import
entire scenes (just as they look in the DCC), including animation,
skeletal rigs, blend shapes, etc.
The second pipeline is through the :ref:`doc_importing_3d_meshes` importer. This
second method allows importing simple .OBJ files as mesh resources,
which can be then put inside a :ref:`MeshInstance <class_MeshInstance>`
node for display.
Generated geometry
------------------
It is possible to create custom geometry by using the
:ref:`Mesh <class_Mesh>` resource directly, simply create your arrays
and use the :ref:`Mesh.add_surface() <class_Mesh_add_surface>`
function. A helper class is also available, :ref:`SurfaceTool <class_SurfaceTool>`,
which provides a more straightforward API and helpers for indexing,
generating normals, tangents, etc.
In any case, this method is meant for generating static geometry (models
that will not be updated often), as creating vertex arrays and
submitting them to the 3D API has a significant performance cost.
Immediate geometry
------------------
If, instead, there is a requirement to generate simple geometry that
will be updated often, Godot provides a special node,
:ref:`ImmediateGeometry <class_ImmediateGeometry>`
which provides an OpenGL 1.x style immediate-mode API to create points,
lines, triangles, etc.
2D in 3D
--------
While Godot packs a powerful 2D engine, many types of games use 2D in a
3D environment. By using a fixed camera (either orthogonal or
perspective) that does not rotate, nodes such as
:ref:`Sprite3D <class_Sprite3D>` and
:ref:`AnimatedSprite3D <class_AnimatedSprite3D>`
can be used to create 2D games that take advantage of mixing with 3D
backgrounds, more realistic parallax, lighting/shadow effects, etc.
The disadvantage is, of course, that added complexity and reduced
performance in comparison to plain 2D, as well as the lack of reference
of working in pixels.
Environment
~~~~~~~~~~~
Besides editing a scene, it is often common to edit the environment.
Godot provides a :ref:`WorldEnvironment <class_WorldEnvironment>`
node that allows changing the background color, mode (as in, put a
skybox), and applying several types of built-in post-processing effects.
Environments can also be overridden in the Camera.
3D viewport
~~~~~~~~~~~
Editing 3D scenes is done in the 3D tab. This tab can be selected
manually, but it will be automatically enabled when a Spatial node is
selected.
.. image:: /img/tuto_3d3.png
Default 3D scene navigation controls are similar to Blender (aiming to
have some sort of consistency in the free software pipeline..), but
options are included to customize mouse buttons and behavior to be
similar to other tools in Editor Settings:
.. image:: /img/tuto_3d4.png
Coordinate system
-----------------
Godot uses the `metric <http://en.wikipedia.org/wiki/Metric_system>`__
system for everything. 3D Physics and other areas are tuned for this, so
attempting to use a different scale is usually a bad idea (unless you
know what you are doing).
When working with 3D assets, it's always best to work in the correct
scale (set your DCC to metric). Godot allows scaling post-import and,
while this works in most cases, in rare situations it may introduce
floating point precision issues (and thus, glitches or artifacts) in
delicate areas such as rendering or physics. So, make sure your artists
always work in the right scale!
The Y coordinate is used for "up", though for most objects that need
alignment (like lights, cameras, capsule collider, vehicle, etc.), the Z
axis is used as a "pointing towards" direction. This convention roughly
means that:
- **X** is sides
- **Y** is up/down
- **Z** is front/back
Space and manipulation gizmos
-----------------------------
Moving objects in the 3D view is done through the manipulator gizmos.
Each axis is represented by a color: Red, Green, Blue represent X,Y,Z
respectively. This convention applies to the grid and other gizmos too
(and also to the shader language, ordering of components for
Vector3,Color,etc.).
.. image:: /img/tuto_3d5.png
Some useful keybindings:
- To snap motion or rotation, press the "s" key while moving, scaling
or rotating.
- To center the view on the selected object, press the "f" key.
View menu
---------
The view options are controlled by the "[ view ]" menu. Pay attention to
this little menu inside the window because it is often overlooked!
.. image:: /img/tuto_3d6.png
Default lighting
----------------
The 3D view has by some default options on lighting:
- There is a directional light that makes objects visible while editing
turned on by default. It is no longer visible when running the game.
- There is subtle default environment light to avoid places not reached
by the light to remain visible. It is also no longer visible when
running the game (and when the default light is turned off).
These can be turned off by toggling the "Default Light" option:
.. image:: /img/tuto_3d8.png
Customizing this (and other default view options) is also possible via
the settings menu:
.. image:: /img/tuto_3d7.png
Which opens this window, allowing to customize ambient light color and
default light direction:
.. image:: /img/tuto_3d9.png
Cameras
-------
No matter how many objects are placed in 3D space, nothing will be
displayed unless a :ref:`Camera <class_Camera>` is
also added to the scene. Cameras can either work in orthogonal or
perspective projections:
.. image:: /img/tuto_3d10.png
Cameras are associated and only display to a parent or grand-parent
viewport. Since the root of the scene tree is a viewport, cameras will
display on it by default, but if sub-viewports (either as render target
or picture-in-picture) are desired, they need their own children cameras
to display.
.. image:: /img/tuto_3d11.png
When dealing with multiple cameras, the following rules are followed for
each viewport:
- If no cameras are present in the scene tree, the first one that
enters it will become the active camera. Further cameras entering the
scene will be ignored (unless they are set as *current*).
- If a camera has the "*current*" property set, it will be used
regardless of any other camera in the scene. If the property is set,
it will become active, replacing the previous camera.
- If an active camera leaves the scene tree, the first camera in
tree-order will take its place.
Lights
------
There is no limitation on the number of lights nor of types of lights in
Godot. As many as desired can be added (as long as performance allows). Shadow
maps are, however, limited. The more they are used, the less the quality
overall.
It is possible to use :ref:`doc_light_baking`, to avoid using large amount of
real-time lights and improve performance.

View File

@@ -0,0 +1,119 @@
.. _doc_materials:
Materials
=========
Introduction
------------
Materials can be applied to most visible 3D objects. Basically they
describe how light interacts with that object. There are many
types of materials, but the main ones are the
:ref:`FixedMaterial <class_FixedMaterial>` and the
:ref:`ShaderMaterial <class_ShaderMaterial>`.
Tutorials for each of them exist :ref:`doc_fixed_materials` and :ref:`doc_shader_materials`.
This tutorial is about the basic properties shared between them.
.. image:: /img/material_flags.png
Flags
-----
Materials, no matter which type they are, have an associated set of flags.
Their use will be explained in the following.
Visible
~~~~~~~
Toggles whether the material is visible. If unchecked, the object will
not be shown.
Double sided & inverted faces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Godot by default only shows geometry faces (triangles) when their front-side
faces the camera. If looking at the front-side of a face, its vertices
have to be oriented clockwise by definition. For closed objects, the
back-side of faces is never visible because they are hidden by other
faces. SO not drawing invisible triangles (whose vertices are oriented
counter-clockwise on the view plane) saves a lot of GPU power.
However, for flat or open objects, the back-side of faces might be visible
and needs to be drawn as well. The "double sided" flag makes sure that no matter the facing,
the triangle will always be drawn. It is also possible to invert this
check and draw only counter-clockwise looking faces, though it's not
very useful except for a few cases (like drawing outlines).
Unshaded
~~~~~~~~
Objects are always black unless light affects them, and their shading
changes according to the type and direction of lights. When this flag is
turned on, the diffuse color is displayed right the same as it appears
in the texture or parameter:
.. image:: /img/material_unshaded.png
On top
~~~~~~
When this flag is turned on, the object will be drawn after everything
else has been drawn and without a depth test. This is generally useful
for objects which shall never be hidden by other objects such as HUD effects
or gizmos.
Ligthmap on UV2
~~~~~~~~~~~~~~~
When using lightmapping (see the :ref:`doc_light_baking` tutorial), this option
determines that the lightmap should be accessed on the UV2 array instead
of regular UV.
Parameters
----------
Some parameters also exist for controlling drawing and blending:
Blend mode
~~~~~~~~~~
Objects are usually blended in Mix mode. Other blend modes (Add and Sub)
exist for special cases (usually particle effects, light rays, etc.) but
materials can be set to them:
.. image:: /img/fixed_material_blend.png
Line width
~~~~~~~~~~
When drawing lines, the size of them can be adjusted here per material.
Depth draw mode
~~~~~~~~~~~~~~~
This is a tricky but very useful setting. By default, opaque objects are
drawn using the depth buffer and translucent objects are not (but are
sorted by depth). This behavior can be changed here. The options are:
- **Always**: Draw objects with depth always, even those with alpha.
This often results in glitches like the one in the first image (which
is why it's not the default).
- **Opaque Only**: Draw objects with depth only when they are opaque,
and do not set depth for alpha. This is the default because it's fast,
but it's not the most correct setting. Objects with transparency that
self-intersect will always look wrong, especially those that mix
opaque and transparent areas, like grass, tree leaves, etc. Objects
with transparency also can't cast shadows, this is evident in the
second image.
- **Alpha Pre-Pass**: The same as above, but a depth pass is performed
for the opaque areas of objects with transparency. This makes objects
with transparency look much more correct. In the third image it is
evident how the leaves cast shadows between them and into the floor.
This setting is turned off by default because, while on PC this is
not very costly, mobile devices suffer a lot when this setting is
turned on, so use it with care.
- **Never**: Never use the depth buffer for this material. This is
mostly useful in combination with the "On Top" flag explained above.
.. image:: /img/material_depth_draw.png

View File

@@ -0,0 +1,90 @@
.. _doc_using_gridmaps:
Using gridmaps
~~~~~~~~~~~~~~
Introduction
------------
:ref:`Gridmaps <class_GridMap>` are a simple and fast way to create 3D
game levels. Think of it as a 3D version of the :ref:`TileMap<doc_using_tilemaps>`
node. Similarly, you start with a predefined library of 3D meshes that
can be put on a grid, just like if you were building a level with an
unlimited amount of Lego blocks.
Collisions can also be added to the meshes, just like you would do with
the tiles of a tilemap.
Creating a MeshLibrary
----------------------
To begin, you need a :ref:`class_MeshLibrary`, which is a collection
of meshes that can be used in the gridmap. Here are some meshes you can
use to set it up.
.. image:: /img/meshes.png
Open a new scene and create a root node (this is important, as without
the root node, it will not be able to generate the MeshLibrary!). Then,
create a :ref:`class_MeshInstance` node:
.. image:: /img/mesh_meshlib.png
If you don't need to apply physics to the building blocks, that's all
you need to do. In most cases though, you will need your block to
generate collisions, so let's see how to add them.
Collisions
----------
To assign a :ref:`class_CollisionShape` and :ref:`class_PhysicsBody`
to the meshes, the simplest way is to do it while creating the
MeshLibrary. Alternatively, you can also edit an existing MeshLibrary
from within the GridMap inspector, but only CollisionShapes can be
defined there and not PhysicsBody.
To give the meshes a CollisionShape, you simply add children nodes to
the MeshInstance node. You would typically add the desired PhysicsBody
and CollisionShape in this order:
.. image:: /img/collide_mesh_meshlib.png
You can adjust the order according to your needs.
Exporting the MeshLibrary
-------------------------
To export, go to ``Scene > Convert To.. > MeshLibrary..``, and save it
as a resource.
.. image:: /img/export_meshlib.png
You are now ready to use the GridMap node.
Using the MeshLibrary in a GridMap
----------------------------------
Create a new scene using any node as root, then add a Gridmap node.
Then, load the MeshLibrary that you just exported.
.. image:: /img/load_meshlib.png
Now, you can build your own level as you see best fit. Use left click
to add tiles and right click to remove them. You can adjust the floor
level when you need to put meshes at specific heights.
.. image:: /img/gridmap.png
As mentioned above, you can also define new CollisionShapes at this
stage by doing the following steps:
.. image:: /img/load_collisionshape.png
There you are!
Reminder
--------
- Be cautious before scaling meshes if you are not using uniform
meshes.
- There are many ways to make use of gridmaps, be creative!

View File

@@ -0,0 +1,355 @@
.. _doc_cutout_animation:
Cutout animation
================
What is it?
~~~~~~~~~~~
Cut-out is a technique of animating in 2D where pieces of paper (or
similar material) are cut in special shapes and laid one over the other.
The papers are animated and photographed, frame by frame using a stop
motion technique (more info
`here <http://en.wikipedia.org/wiki/Cutout_animation>`__).
With the advent of the digital age, this technique became possible using
computers, which resulted in an increased amount of animation TV shows
using digital Cut-out. Notable examples are `South
Park <http://en.wikipedia.org/wiki/South_Park>`__ or `Jake and the Never
Land
Pirates <http://en.wikipedia.org/wiki/Jake_and_the_Never_Land_Pirates>`__
.
In video games, this technique also become very popular. Examples of
this are `Paper
Mario <http://en.wikipedia.org/wiki/Super_Paper_Mario>`__ or `Rayman
Origins <http://en.wikipedia.org/wiki/Rayman_Origins>`__ .
Cutout in Godot
~~~~~~~~~~~~~~~
Godot provides a few tools for working with these kind of assets, but
its overall design makes it ideal for the workflow. The reason is that,
unlike other tools meant for this, Godot has the following advantages:
- **The animation system is fully integrated with the engine**: This
means, animations can control much more than just motion of objects,
such as textures, sprite sizes, pivots, opacity, color modulation,
etc. Everything can be animated and blended.
- **Mix with Traditional**: AnimatedSprite allows traditional animation
to be mixed, very useful for complex objects, such as shape of hands
and foot, changing facial expression, etc.
- **Custom Shaped Elements**: Can be created with
:ref:`Polygon2D <class_Polygon2D>`
allowing the mixing of UV animation, deformations, etc.
- **Particle Systems**: Can also be mixed with the traditional
animation hierarchy, useful for magic effects, jetpacks, etc.
- **Custom Colliders**: Set colliders and influence areas in different
parts of the skeletons, great for bosses, fighting games, etc.
- **Animation Tree**: Allows complex combinations and blendings of
several animations, the same way it works in 3D.
And much more!
Making of GBot!
~~~~~~~~~~~~~~~
For this tutorial, we will use as demo content the pieces of the
`GBot <https://www.youtube.com/watch?v=S13FrWuBMx4&list=UUckpus81gNin1aV8WSffRKw>`__
character, created by Andreas Esau.
.. image:: /img/tuto_cutout_walk.gif
Get your assets: :download:`gbot_resources.zip </files/gbot_resources.zip>`.
Setting up the rig
~~~~~~~~~~~~~~~~~~
Create an empty Node2D as root of the scene, we will work under it:
.. image:: /img/tuto_cutout1.png
OK, the first node of the model that we will create will be the hip.
Generally, both in 2D and 3D, the hip is the root of the skeleton. This
makes it easier to animate:
.. image:: /img/tuto_cutout2.png
Next will be the torso. The torso needs to be a child of the hip, so
create a child sprite and load the torso, later accommodate it properly:
.. image:: /img/tuto_cutout3.png
This looks good. Let's see if our hierarchy works as a skeleton by
rotating the torso:
.. image:: /img/tutovec_torso1.gif
Ouch, that doesn't look good! The rotation pivot is wrong, this means
it needs to be adjusted.
This small little cross in the middle of the
:ref:`Sprite <class_Sprite>` is
the rotation pivot:
.. image:: /img/tuto_cutout4.png
Adjusting the pivot
~~~~~~~~~~~~~~~~~~~
The pivot can be adjusted by changing the *offset* property in the
Sprite:
.. image:: /img/tuto_cutout5.png
However, there is a way to do it more *visually*. While hovering over the
desired pivot point, simply press the "v" key to move the pivot there for the
selected Sprite. Alternately, there is a tool in the tool bar that has a
similar function.
.. image:: /img/tutovec_torso2.gif
Now it looks good! Let's continue adding body pieces, starting by the
right arm. Make sure to put the sprites in hierarchy, so their rotations
and translations are relative to the parent:
.. image:: /img/tuto_cutout6.png
This seems easy, so continue with the left arm. The rest should be
simple! Or maybe not:
.. image:: /img/tuto_cutout7.png
Right. Remember your tutorials, Luke. In 2D, parent nodes appear below
children nodes. Well, this sucks. It seems Godot does not support cutout
rigs after all. Come back next year, maybe for 3.0.. no wait. Just
Kidding! It works just fine.
But how can this problem be solved? We want the left arm to appear behind
the hip and the torso. For this, we can move the nodes behind the hip
(note that you can bypass this by setting the Node2D Z property, but then you
won't learn about all this!):
.. image:: /img/tuto_cutout8.png
But then, we lose the hierarchy layout, which allows to control the
skeleton like.. a skeleton. Is there any hope?.. Of Course!
RemoteTransform2D node
~~~~~~~~~~~~~~~~~~~~~~
Godot provides a special node, :ref:`RemoteTransform2D <class_RemoteTransform2D>`.
This node will transform nodes that are sitting somewhere else in the
hierarchy, by applying the transform to the remote nodes.
This enables to have a visibility order independent from the
hierarchy.
Simply create two more nodes as children from torso, remote_arm_l and
remote_hand_l and link them to the actual sprites:
.. image:: /img/tuto_cutout9.png
Moving the remote transform nodes will move the sprites, allowing you to
easily animate and pose the character:
.. image:: /img/tutovec_torso4.gif
Completing the skeleton
~~~~~~~~~~~~~~~~~~~~~~~
Complete the skeleton by following the same steps for the rest of the
parts. The resulting scene should look similar to this:
.. image:: /img/tuto_cutout10.png
The resulting rig will be easy to animate. By selecting the nodes and
rotating them you can animate forward kinematics (FK) efficiently.
For simple objects and rigs this is fine, however the following problems
are common:
- Selecting sprites can become difficult for complex rigs, and the
scene tree ends being used due to the difficulty of clicking over the
proper sprite.
- Inverse Kinematics is often desired for extremities.
To solve these problems, Godot supports a simple method of skeletons.
Skeletons
~~~~~~~~~
Godot doesn't actually support *true* Skeketons, but it does feature a
helper to create "bones" between nodes. This is enough for most cases,
but the way it works is not completely obvious.
As an example, let's turn the right arm into a skeleton. To create
skeletons, a chain of nodes must be selected from top to bottom:
.. image:: /img/tuto_cutout11.png
Then, the option to create a skeleton is located at Edit > Make Bones:
.. image:: /img/tuto_cutout12.png
This will add bones covering the arm, but the result is not quite what
is expected.
.. image:: /img/tuto_cutout13.png
It looks like the bones are shifted up in the hierarchy. The hand
connects to the arm, and the arm to the body. So the question is:
- Why does the hand lack a bone?
- Why does the arm connect to the body?
This might seem strange at first, but will make sense later on. In
traditional skeleton systems, bones have a position, an orientation and
a length. In Godot, bones are mostly helpers so they connect the current
node with the parent. Because of this, **toggling a node as a bone will
just connect it to the parent**.
So, with this knowledge. Let's do the same again so we have an actual,
useful skeleton.
The first step is creating an endpoint node. Any kind of node will do,
but :ref:`Position2D <class_Position2D>` is preferred because it's
visible in the editor. The endpoint node will ensure that the last bone
has orientation.
.. image:: /img/tuto_cutout14.png
Now select the whole chain, from the endpoint to the arm and create
bones:
.. image:: /img/tuto_cutout15.png
The result resembles a skeleton a lot more, and now the arm and forearm
can be selected and animated.
Finally, create endpoints in all meaningful extremities and connect the
whole skeleton with bones up to the hip:
.. image:: /img/tuto_cutout16.png
Finally! the whole skeleton is rigged! On close look, it is noticeable
that there is a second set of endpoints in the hands. This will make
sense soon.
Now that a whole skeleton is rigged, the next step is setting up the IK
chains. IK chains allow for more natural control of extremities.
IK chains
~~~~~~~~~
IK chains are a powerful animation tool. Imagine you want to pose a character's foot in a specific position on the ground. Without IK chains, each motion of the foot would require rotating and positioning several other bones. This would be quite complex and lead to imprecise results.
What if we could move the foot and let the rest of the leg self-adjust?
This type of posing is called IK (Inverse Kinematic).
To create an IK chain, simply select a chain of bones from endpoint to
the base for the chain. For example, to create an IK chain for the right
leg, select the following:
.. image:: /img/tuto_cutout17.png
Then enable this chain for IK. Go to Edit > Make IK Chain.
.. image:: /img/tuto_cutout18.png
As a result, the base of the chain will turn *Yellow*.
.. image:: /img/tuto_cutout19.png
Once the IK chain is set-up, simply grab any of the bones in the
extremity, any child or grand-child of the base of the chain and try to
grab it and move it. Result will be pleasant, satisfaction warranted!
.. image:: /img/tutovec_torso5.gif
Animation
~~~~~~~~~
The following section will be a collection of tips for creating
animation for your rigs. If unsure about how the animation system in
Godot works, refresh it by checking again the :ref:`doc_animations`.
2D animation
------------
When doing animation in 2D, a helper will be present in the top menu.
This helper only appears when the animation editor window is opened:
.. image:: /img/tuto_cutout20.png
The key button will insert location/rotation/scale keyframes to the
selected objects or bones. This depends on the mask enabled. Green items
will insert keys while red ones will not, so modify the key insertion
mask to your preference.
Rest pose
~~~~~~~~~
These kind of rigs do not have a "rest" pose, so it's recommended to
create a reference rest pose in one of the animations.
Simply do the following steps:
1. Make sure the rig is in "rest" (not doing any specific pose).
2. Create a new animation, rename it to "rest".
3. Select all nodes (box selection should work fine).
4. Select "loc" and "rot" on the top menu.
5. Push the key button. Keys will be inserted for everything, creating
a default pose.
.. image:: /img/tuto_cutout21.png
Rotation
~~~~~~~~
Animating these models means only modifying the rotation of the nodes.
Location and scale are rarely used, with the only exception of moving
the entire rig from the hip (which is the root node).
As a result, when inserting keys, only the "rot" button needs to be
pressed most of the time:
.. image:: /img/tuto_cutout22.png
This will avoid the creation of extra animation tracks for the position
that will remain unused.
Keyframing IK
~~~~~~~~~~~~~
When editing IK chains, is is not necessary to select the whole chain to
add keyframes. Selecting the endpoint of the chain and inserting a
keyframe will automatically insert keyframes until the chain base too.
This makes the task of animating extremities much simpler.
Moving sprites above and behind others.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RemoteTransform2D works in most cases, but sometimes it is really
necessary to have a node above and below others during an animation. To
aid on this the "Behind Parent" property exists on any Node2D:
.. image:: /img/tuto_cutout23.png
Batch setting transition curves
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When creating really complex animations and inserting lots of keyframes,
editing the individual keyframe curves for each can become an endless
task. For this, the Animation Editor has a small menu where changing all
the curves is easy. Just select every single keyframe and (generally)
apply the "Out-In" transition curve to smooth the animation:
.. image:: /img/tuto_cutout24.png

View File

@@ -0,0 +1,80 @@
.. _doc_bbcode_in_richtextlabel:
BBCode in RichTextLabel
=======================
Introduction
------------
:ref:`class_RichTextLabel` allows to display complex text markup in a control.
It has a built-in API for generating the markup, but can also parse a BBCode.
Note that the BBCode tags can also be used to some extent in the
:ref:`XML source of the class reference <doc_updating_the_class_reference>`.
Setting up
----------
For RichTextLabel to work properly, it must be set up. This means loading
the intended fonts in the relevant properties:
.. image:: /img/rtl_setup.png
Reference
---------
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| Command | Tag | Description |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **bold** | ``[b]{text}[/b]`` | Makes {text} bold. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **italics** | ``[i]{text}[/i]`` | Makes {text} italics. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **underline** | ``[u]{text}[/u]`` | Makes {text} underline. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **code** | ``[code]{text}[/code]`` | Makes {text} monospace. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **center** | ``[center]{text}[/center]`` | Makes {text} centered. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **right** | ``[right]{text}[/right]`` | Makes {text} right-aligned. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **fill** | ``[fill]{text}[/fill]`` | Makes {text} fill width. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **indent** | ``[indent]{text}[/indent]`` | Increase indent level of {text}. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **url** | ``[url]{url}[/url]`` | Show {url} as such. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **url (ref)** | ``[url=<url>]{text}[/url]`` | Makes {text} reference <url>. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **image** | ``[img=<path>][/img]`` | Insert image at resource <path>. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **font** | ``[font=<path>]{text}[/font]`` | Use custom font at <path> for {text}. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
| **color** | ``[color=<code/name>]{text}[/color]`` | Change {text} color, use # format such as #ff00ff or name. |
+-----------------+--------------------------------------------+--------------------------------------------------------------+
Built-in color names
~~~~~~~~~~~~~~~~~~~~
List of valid color names for the [color=<name>] tag:
- aqua
- black
- blue
- fuchsia
- gray
- green
- lime
- maroon
- navy
- purple
- red
- silver
- teal
- white
- yellow
Hexadecimal color codes
~~~~~~~~~~~~~~~~~~~~
Any valid 6 digit hexadecimal code is supported. e.g: [color=#ffffff]white[/color]

View File

@@ -0,0 +1,143 @@
.. _doc_custom_gui_controls:
Custom GUI controls
===================
So many controls...
-------------------
Yet there are never enough. Creating your own custom controls that act
just the way you want them is an obsession of almost every GUI
programmer. Godot provides plenty of them, but they may not work exactly
the way you want. Before contacting the developers with a pull-request
to support diagonal scrollbars, at least it will be good to know how to
create these controls easily from script.
Drawing
-------
For drawing, it is recommended to check the :ref:`doc_custom_drawing_in_2d` tutorial.
The same applies. Some functions are worth mentioning due to their
usefulness when drawing, so they will be detailed next:
Checking control size
~~~~~~~~~~~~~~~~~~~~~
Unlike 2D nodes, "size" is very important with controls, as it helps to
organize them in proper layouts. For this, the
:ref:`Control.get_size() <class_Control_get_size>`
method is provided. Checking it during _draw() is vital to ensure
everything is kept in-bounds.
Checking focus
~~~~~~~~~~~~~~
Some controls (such as buttons or text editors) might provide input
focus for keyboard or joypad input. Examples of this are entering text
or pressing a button. This is controlled with the
:ref:`Control.set_focus_mode() <class_Control_set_focus_mode>`
function. When drawing, and if the control supports input focus, it is
always desired to show some sort of indicator (highight, box, etc) to
indicate that this is the currently focused control. To check for this
status, the :ref:`Control.has_focus() <class_Control_has_focus>`
exists. Example
::
func _draw():
if (has_focus()):
draw_selected()
else:
draw_normal()
Sizing
------
As mentioned before, size is very important to controls. This allows
them to lay out properly, when set into grids, containers, or anchored.
Controls most of the time provide a *minimum size* to help to properly
lay them out. For example, if controls are placed vertically on top of
each other using a :ref:`VBoxContainer <class_VBoxContainer>`,
the minimum size will make sure your custom control is not squished by
the other controls in the container.
To provide this callback, just override
:ref:`Control.get_minimum_size() <class_Control_get_minimum_size>`,
for example:
::
func get_minimum_size():
return Vector2(30,30)
Or alternatively, set it via function:
::
func _ready():
set_custom_minimum_size( Vector2(30,30) )
Input
-----
Controls provide a few helpers to make managing input events much easier
than regular nodes.
Input events
~~~~~~~~~~~~
There are a few tutorials about input before this one, but it's worth
mentioning that controls have a special input method that only works
when:
- The mouse pointer is over the control.
- The button was pressed over this control (control always
captures input until button is released)
- Control provides keyboard/joypad focus via
:ref:`Control.set_focus_mode() <class_Control_set_focus_mode>`.
This function is
:ref:`Control._input_event() <class_Control__input_event>`.
Simply override it in your control. No processing needs to be set.
::
extends Control
func _input_event(ev):
if (ev.type==InputEvent.MOUSE_BUTTON and ev.button_index==BUTTON_LEFT and ev.pressed):
print("Left mouse button was pressed!")
For more information about events themselves, check the :ref:`doc_inputevent`
tutorial.
Notifications
~~~~~~~~~~~~~
Controls also have many useful notifications for which no callback
exists, but can be checked with the _notification callback:
::
func _notification(what):
if (what==NOTIFICATION_MOUSE_ENTER):
pass # mouse entered the area of this control
elif (what==NOTIFICATION_MOUSE_EXIT):
pass # mouse exited the area of this control
elif (what==NOTIFICATION_FOCUS_ENTER):
pass # control gained focus
elif (what==NOTIFICATION_FOCUS_EXIT):
pass # control lost focus
elif (what==NOTIFICATION_THEME_CHANGED):
pass # theme used to draw the control changed
# update and redraw is recommended if using a theme
elif (what==NOTIFICATION_VISIBILITY_CHANGED):
pass # control became visible/invisible
# check new status with is_visible()
elif (what==NOTIFICATION_RESIZED):
pass # control changed size, check new size
# with get_size()
elif (what==NOTIFICATION_MODAL_CLOSED):
pass # for modal popups, notification
# that the popup was closed

View File

View File

@@ -0,0 +1,161 @@
.. _doc_gui_skinning:
GUI skinning
============
Oh beautiful GUI!
-----------------
This tutorial is about advanced skinning of an user interface. Most
games generally don't need this, as they end up just relying on
:ref:`Label <class_Label>`, :ref:`TextureFrame <class_TextureFrame>`,
:ref:`TextureButton <class_TextureButton>` and
:ref:`TextureProgress <class_TextureProgress>`.
However, many types of games often need complex user interfaces, like
MMOs, traditional RPGs, Simulators, Strategy, etc. These kind of
interfaces are also common in some games that include editors to create
content, or interfaces for network connectivity.
Godot user interface uses these kind of controls with the default theme,
but they can be skinned to resemble pretty much any kind of user
interface.
Theme
-----
The GUI is skinned through the :ref:`Theme <class_Theme>`
resource. Theme contains all the information required to change the
entire visual styling of all controls. Theme options are named, so it's
not obvious which name changes what (specialy from code), but several
tools are provided. The ultimate place to look at what each theme option
is for each control, which will always be more up to date than any
documentation is the file `scene/resources/default_theme/default_theme.cpp
<https://github.com/godotengine/godot/blob/master/scene/resources/default_theme/default_theme.cpp>`__.
The rest of this document will explain the different tools used to
customize the theme.
A Theme can be applied to any control in the scene. As a result, all
children and grand-children controls will use that same theme too
(unless another theme is specified further down the tree). If a value is
not found in a theme, it will be searched in themes higher up in the
hierarchy towards the root. If nothing was found, the default theme is
used. This system allows for flexible overriding of themes in complex
user interfaces.
Theme options
-------------
Each kind of option in a theme can be:
- **An integer constant**: A single numerical constant. Generally used
to define spacing between compoments or alignment.
- **A Color**: A single color, with or without transparency. Colors are
usually applied to fonts and icons.
- **A Texture**: A single image. Textures are not often used, but when
they are they represent handles to pick or icons in a complex control
(such as file dialog).
- **A Font**: Every control that uses text can be assigned the fonts
used to draw strings.
- **A StyleBox**: Stylebox is a resource that defines how to draw a
panel in varying sizes (more information on them later).
Every option is associated to:
- A name (the name of the option)
- A Control (the name of the control)
An example usage:
::
var t = Theme.new()
t.set_color("font_color","Label",Color(1.0,1.0,1.0))
var l = Label.new()
l.set_theme(t)
In the example above, a new theme is created. The "font_color" option
is changed and then applied to a label. As a result, the label (and all
children and grand children labels) will use that color.
It is possible to override those options without using the theme
directly and only for a specific control by using the override API in
:ref:`Control.add_color_override() <class_Control_add_color_override>`:
::
var l = Label.new()
l.add_color_override("font_color",Color(1.0,1.0,1.0))
In the inline help of Godot (in the script tab) you can check which theme options
are overrideable, or check the :ref:`Control <class_Control>` class reference.
Customizing a control
---------------------
If only a few controls need to be skinned, it is often not necessary to
create a new theme. Controls offer their theme options as special kinds
of properties. If checked, overriding will take place:
.. image:: /img/themecheck.png
As can be see in the image above, theme options have little check-boxes.
If checked, they can be used to override the value of the theme just for
that control.
Creating a theme
----------------
The simplest way to create a theme is to edit a theme resource. Create a
Theme from the resource menu, the editor will appear immediately.
Following to this, save it (to, as example, mytheme.thm):
.. image:: /img/themecheck.png
This will create an empty theme that can later be loaded and assigned to
controls.
Example: theming a button
--------------------------
Take some assets (:download:`skin_assets.zip </files/skin_assets.zip>`),
go to the "theme" menu and select "Add Class Item":
.. image:: /img/themeci.png
A menu will appear promting the type of control to create. Select
"Button":
.. image:: /img/themeci2.png
Immediately, all button theme options will appear in the property
editor, where they can be edited:
.. image:: /img/themeci3.png
Select the "normal" stylebox and create a new "StyleBoxTexture", then
edit it. A texture stylebox basically contains a texture and the size of
the margins that will not stretch when the texture is stretched. This is
called "3x3" stretching:
.. image:: /img/sb1.png
Repeat the steps and add the other assets. There is no hover or disabled
image in the example files, so use the same stylebox as in normal. Set
the supplied font as the button font and change the font color to black.
Soon, your button will look different and retro:
.. image:: /img/sb2.png
Save this theme to the .thm file. Go to the 2D editor and create a few
buttons:
.. image:: /img/skinbuttons1.png
Now, go to the root node of the scene and locate the "theme" property,
replace it by the theme that was just created. It should look like this:
.. image:: /img/skinbuttons2.png
Congratulations! You have created a reusable GUI Theme!

View File

@@ -0,0 +1,42 @@
.. _doc_size_and_anchors:
Size and anchors
----------------
If a game was to be always run in the same device and at the same
resolution, positioning controls would be a simple matter of setting the
position and size of each one of them. Unfortunately, it is rarely the
case.
Only TVs nowadays have a standard resolution and aspect ratio.
Everything else, from computer monitors to tablets, portable consoles
and mobile phones have different resolutions and aspect ratios.
There are several ways to handle this, but for now let's just imagine
that the screen resolution has changed and the controls need to be
re-positioned. Some will need to follow the bottom of the screen, others
the top of the screen, or maybe the right or left margins.
.. image:: /img/anchors.png
This is done by editing the *margin* properties of controls. Each
control has four margins: left, right, bottom and top. By default all of
them represent a distance in pixels relative to the top-left corner of
the parent control or (in case there is no parent control) the viewport.
.. image:: /img/margin.png
When horizontal (left,right) and/or vertical (top,bottom) anchors are
changed to END, the margin values become relative to the bottom-right
corner of the parent control or viewport.
.. image:: /img/marginend.png
Here the control is set to expand its bottom-right corner with that of
the parent, so when re-sizing the parent, the control will always cover
it, leaving a 20 pixel margin:
.. image:: /img/marginaround.png
Finally, there is also a ratio option, where 0 means left, 1 means right
and anything in between is interpolated.

View File

@@ -0,0 +1,158 @@
.. _doc_inputevent:
InputEvent
==========
What is it?
-----------
Managing input is usually complex, no matter the OS or platform. To ease
this a little, a special built-in type is provided, :ref:`InputEvent <class_InputEvent>`.
This datatype can be configured to contain several types of input
events. Input Events travel through the engine and can be received in
multiple locations, depending on the purpose.
How does it work?
-----------------
Every input event is originated from the user/player (though it's
possible to generate an InputEvent and feed them back to the engine,
which is useful for gestures). The OS object for each platform will read
events from the device, then feed them to MainLoop. As :ref:`SceneTree <class_SceneTree>`
is the default MainLoop implementation, events are fed to it. Godot
provides a function to get the current SceneTree object :
**get_tree()**.
But SceneTree does not know what to do with the event, so it will give
it to the viewports, starting by the "root" :ref:`Viewport <class_Viewport>` (the first
node of the scene tree). Viewport does quite a lot of stuff with the
received input, in order:
.. image:: /img/input_event_flow.png
1. First of all, the standard _input function
will be called in any node with input processing enabled (enable with
:ref:`Node.set_process_input() <class_Node_set_process_input>` and override
:ref:`Node._input() <class_Node__input>`). If any function consumes the event, it can
call :ref:`SceneTree.set_input_as_handled() <class_SceneTree_set_input_as_handled>`, and the event will
not spread any more. This ensures that you can filter all events of interest, even before the GUI.
For gameplay input, the _unhandled_input() is generally a better fit, because it allows the GUI to intercept the events.
2. Second, it will try to feed the input to the GUI, and see if any
control can receive it. If so, the :ref:`Control <class_Control>` will be called via the
virtual function :ref:`Control._input_event() <class_Control__input_event>` and the signal
"input_event" will be emitted (this function is re-implementable by
script by inheriting from it). If the control wants to "consume" the
event, it will call :ref:`Control.accept_event() <class_Control_accept_event>` and the event will
not spread any more.
3. If so far no one consumed the event, the unhandled input callback
will be called (enable with
:ref:`Node.set_process_unhandled_input() <class_Node_set_process_unhandled_input>` and override
:ref:`Node._unhandled_input() <class_Node__unhandled_input>`). If any function consumes the
event, it can call :ref:`SceneTree.set_input_as_handled() <class_SceneTree_set_input_as_handled>`, and the
event will not spread any more. The unhandled input callback is ideal for full-screen gameplay events, so they are not received when a GUI is active.
4. If no one wanted the event so far, and a :ref:`Camera <class_Camera>` is assigned
to the Viewport, a ray to the physics world (in the ray direction from
the click) will be cast. If this ray hits an object, it will call the
:ref:`CollisionObject._input_event() <class_CollisionObject__input_event>` function in the relevant
physics object (bodies receive this callback by default, but areas do
not. This can be configured through :ref:`Area <class_Area>` properties).
5. Finally, if the event was unhandled, it will be passed to the next
Viewport in the tree, otherwise it will be ignored.
Anatomy of an InputEvent
------------------------
:ref:`InputEvent <class_InputEvent>` is just a base built-in type, it does not represent
anything and only contains some basic information, such as event ID
(which is increased for each event), device index, etc.
InputEvent has a "type" member. By assigning it, it can become
different types of input event. Every type of InputEvent has different
properties, according to its role.
Example of changing event type.
::
# create event
var ev = InputEvent()
# set type index
ev.type = InputEvent.MOUSE_BUTTON
# button_index is only available for the above type
ev.button_index = BUTTON_LEFT
There are several types of InputEvent, described in the table below:
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| Event | Type Index | Description |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEvent <class_InputEvent>` | NONE | Empty Input Event. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventKey <class_InputEventKey>` | KEY | Contains a scancode and unicode value, |
| | | as well as modifiers. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventMouseButton <class_InputEventMouseButton>` | MOUSE_BUTTON | Contains click information, such as |
| | | button, modifiers, etc. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventMouseMotion <class_InputEventMouseMotion>` | MOUSE_MOTION | Contains motion information, such as |
| | | relative, absolute positions and speed. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventJoystickMotion <class_InputEventJoystickMotion>` | JOYSTICK_MOTION | Contains Joystick/Joypad analog axis |
| | | information. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventJoystickButton <class_InputEventJoystickButton>` | JOYSTICK_BUTTON | Contains Joystick/Joypad button |
| | | information. |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventScreenTouch <class_InputEventScreenTouch>` | SCREEN_TOUCH | Contains multi-touch press/release |
| | | information. (only available on mobile |
| | | devices) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventScreenDrag <class_InputEventScreenDrag>` | SCREEN_DRAG | Contains multi-touch drag information. |
| | | (only available on mobile devices) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
| :ref:`InputEventAction <class_InputEventAction>` | SCREEN_ACTION | Contains a generic action. These events |
| | | are often generated by the programmer |
| | | as feedback. (more on this below) |
+-------------------------------------------------------------------+--------------------+-----------------------------------------+
Actions
-------
An InputEvent may or may not represent a pre-defined action. Actions are
useful because they abstract the input device when programming the game
logic. This allows for:
- The same code to work on different devices with different inputs (e.g.,
keyboard on PC, Joypad on console).
- Input to be reconfigured at run-time.
Actions can be created from the Project Settings menu in the Actions
tab. Read :ref:`doc_simple_2d_game-input_actions_setup` for an
explanation on how the action editor works.
Any event has the methods :ref:`InputEvent.is_action() <class_InputEvent_is_action>`,
:ref:`InputEvent.is_pressed() <class_InputEvent_is_pressed>` and :ref:`InputEvent <class_InputEvent>`.
Alternatively, it may be desired to supply the game back with an action
from the game code (a good example of this is detecting gestures).
SceneTree (derived from MainLoop) has a method for this:
:ref:`MainLoop.input_event() <class_MainLoop_input_event>`. You would normally use it like this:
::
var ev = InputEvent()
ev.type = InputEvent.ACTION
# set as move_left, pressed
ev.set_as_action("move_left", true)
# feedback
get_tree().input_event(ev)
InputMap
--------
Customizing and re-mapping input from code is often desired. If your
whole workflow depends on actions, the :ref:`InputMap <class_InputMap>` singleton is
ideal for reassigning or creating different actions at run-time. This
singleton is not saved (must be modified manually) and its state is run
from the project settings (engine.cfg). So any dynamic system of this
type needs to store settings in the way the programmer best sees fit.

View File

@@ -0,0 +1,49 @@
.. _doc_mouse_and_input_coordinates:
Mouse and input coordinates
===========================
About
-----
The reason for this small tutorial is to clear up many common mistakes
about input coordinates, obtaining mouse position and screen resolution,
etc.
Hardware display coordinates
----------------------------
Using hardware coordinates makes sense in the case of writing complex
UIs meant to run on PC, such as editors, MMOs, tools, etc. Yet, it does
not make as much sense outside of that scope.
Viewport display coordinates
----------------------------
Godot uses viewports to display content, and viewports can be scaled by
several options (see :ref:`doc_multiple_resolutions` tutorial). Use, then, the
functions in nodes to obtain the mouse coordinates and viewport size,
for example:
::
func _input(ev):
# Mouse in viewport coordinates
if (ev.type==InputEvent.MOUSE_BUTTON):
print("Mouse Click/Unclick at: ",ev.pos)
elif (ev.type==InputEvent.MOUSE_MOTION):
print("Mouse Motion at: ",ev.pos)
# Print the size of the viewport
print("Viewport Resolution is: ",get_viewport_rect().size)
func _ready():
set_process_input(true)
Alternatively it's possible to ask the viewport for the mouse position:
::
get_viewport().get_mouse_pos()

View File

@@ -0,0 +1,122 @@
.. _doc_lighting:
Lighting
========
Introduction
------------
Lights emit light that mix with the materials and produces a visible
result. Light can come from several types of sources in a scene:
- From the Material itself, in the form of the emission color (though
it does not affect nearby objects unless baked).
- Light Nodes: Directional, Omni and Spot.
- Ambient Light in the
:ref:`Environment <class_Environment>`.
- Baked Light (read :ref:`doc_light_baking`).
The emission color is a material property. You can read more about it
in the :ref:`doc_fixed_materials` tutorial.
Light nodes
-----------
As mentioned before, there are three types of light nodes: Directional,
Omni and Spot. Each has different uses and will be described in
detail below, but first let's take a look at the common parameters for
lights:
.. image:: /img/light_params.png
Each one has a specific function:
- **Enabled**: Light is emitted only if this flag is set.
- **Bake Mode**: When using the light baker, the role of this light can
be defined in this enumerator. The role will be followed even if the
light is disabled, which allows to configure a light and then disable
it for baking.
- **Energy**: This value is a multiplier for the light, it's specially
useful for :ref:`doc_high_dynamic_range` and for Spot and Omni lights, because it can
create very bright spots near the emitter.
- **Diffuse and Specular**: These light values get multiplied by the
material light and diffuse colors. A white value does not mean
that light will be white, but that the material color will be kept.
- **Operator**: It is possible to make some lights negative for a
darkening effect.
- **Projector**: Lights can project a texture for the diffuse light
(currently only supported in Spot light).
Directional light
~~~~~~~~~~~~~~~~~
This is the most common type of light and represents a light source
very far away (such as the sun). It is also
the cheapest light to compute and should be used whenever possible
(although it's not the cheapest shadow-map to compute, but more on that
later).
Directional light models an infinite number of parallel light rays
covering the whole scene. The directional light node is represented by a big arrow, which
indicates the direction of the light rays. However, the position of the node
does not affect the lighting at all, and can be anywhere.
.. image:: /img/light_directional.png
Every face whose front-side is hit by the light rays is lit, the others stay dark.
Most light types
have specific parameters but directional lights are pretty simple in
nature so they don't.
Omni light
~~~~~~~~~~
Omni light is a point source that emits light spherically in all directions up to a given
radius (distance from the node's position). The radius is a parameter of the light and
can be controlled by the user. Just as in real life, the intensity of omni light
decreases with the distance and vanishes at the defined radius. Omni light sources
should be used to represent lamps or bulbs or any other light source that originates
approximately in a point.
.. image:: /img/light_omni.png
In reality, the attenuation of omni light is proportional to the squared distance
from the point source. This can be easily understood if you imagine a sphere around
the omni light with a certain radius. No matter how large the sphere is, the number
of rays passing through it is always the same. If the radius of the sphere is doubled,
the area of the sphere increases by four. In other words, the density of rays
(the number of rays per square area) decreases quadratically with the distance.
Inverse-quadratic attenuation curves are inconvenient for artists: they
never reach zero and have almost infinitely large values near the emitter.
So Godot simulates omni light with an artist-controlled exponential curve
instead.
.. image:: /img/light_attenuation.png
Spot light
~~~~~~~~~~
Spot lights are similar to omni lights, except they emit light only into a cone
(or "cutoff"). They are useful to simulate flashlights,
car lights, etc. This kind of light is also attenuated towards the
opposite direction it points to.
.. image:: /img/light_spot.png
Ambient light
-------------
Ambient light can be found in the properties of a WorldEnvironment
(remember only one of such can be instanced per scene). Ambient light
consists of a uniform light and energy. This light is applied the same
to every single pixel of the rendered scene, except to objects that used
baked light.
Baked light
-----------
Baked light stands for pre-computed ambient light. It can serve multiple
purposes, such as baking light emitters that are not going to be used in
real-time, and baking light bounces from real-time lights to add more
realism to a scene (see :ref:`doc_light_baking` tutorial for more information).

View File

@@ -0,0 +1,188 @@
.. _doc_shadow_mapping:
Shadow mapping
==============
Introduction
------------
Simply throwing a light is not enough to realistically illuminate a
scene. It should be, in theory, but given the way video hardware
works, parts of objects that should not be reached by light are lit
anyway.
Most people (including artists), see shadows as something projected by
light, as if they were created by the light itself by darkening places
that are hidden from the light source.
This is actually not correct and it's important to understand that
shadows are places where light simply does not reach. As a rule (and
without counting indirect light) if a light is turned off, the places
where shadow appear should remain the same. In other words, shadows
should not be seen as something "added" to the scene, but as an area
that "remains dark".
All light types in Godot can use shadow mapping, and all support several
different techniques that trade quality by performance. Shadow mapping
uses a texture storing the "depth view" of the light and checks against
it in real-time for each pixel it renders.
The bigger the resolution of the shadow map texture, the more detail the
shadow has, but more video memory and bandwidth consumed (which means
frame-rate goes down).
Shadows by light type
---------------------
Directional light shadows
~~~~~~~~~~~~~~~~~~~~~~~~~
Directional lights can affect a really big area. The bigger the scene,
the bigger the affected area. Given the shadow map resolution stays the
same, the same amount of shadow pixels cover a bigger area, resulting in
blocky shadows. Multiple techniques exist to deal with resolution
problems, but the most common one is PSSM (Parallel Split Shadow Maps):
.. image:: /img/shadow_directional.png
These techniques divide the view in 2 or 4 sections, and a shadow is
rendered for each. This way, close objects can use larger shadow while
further away objects will use one in less detail, but in proportion this
seems to make the shadow map size increase while it's actually kept the
same. Of course, this technique is not free, the more splits the more
the performance goes down. On mobile, it is generally inconvenient to
use more than 2 splits.
An alternative technique is PSM (Perspective Shadow Mapping). This
technique is much cheaper than PSSM (as cheap as orthogonal), but it
only really works for a few camera angles respect to the light. In other
words, PSM is only useful for games where the camera direction and light
direction are both fixed, and the light is not parallel to the camera
(which is when PSM completely breaks).
Omni light shadows
~~~~~~~~~~~~~~~~~~
Omnidirectional lights are also troublesome. How to represent 360 degrees
of light with a single texture? There are two alternatives, the first
one is to use DPSM (Dual Paraboloid Shadow Mapping). This technique is
fast, but it requires DISCARD to be used (which makes it not very usable
on mobile). DPSM can also look rather bad if the geometry is not
tessellated enough, so more vertices might be necessary if it doesn't
look tight. The second option is to simply not use a shadow map, and use
a shadow cubemap. This is faster, but requires six passes to render all
directions and is not supported on the current (GLES2) renderer.
.. image:: /img/shadow_omni.png
As few considerations when using DPSM shadow maps:
- Keep Slope-Scale on 0.
- Use a small value for Z-Offset, if this look wrong, make it smaller.
- ESM filtering can improve the look.
- The seams between the two halves of the shadow are generally
noticeable, so rotate the light to make them show less.
Spot light shadows
~~~~~~~~~~~~~~~~~~
Spot light shadows are generally the simpler, just needing a single
texture and no special techniques.
.. image:: /img/shadow_spot.png
Shadows parameters
------------------
The fact that shadows are actually a texture can generate several
problems. The most common is Z fighting (lines at the edge of the
objects that cast the shadows. There are two ways to fix this, the first
is to tweak the offset parameters, and the second is to use a filtered
shadow algorithm, which generally looks better and has not as many
glitches, but consumes more GPU time.
Adjusting z-offset
~~~~~~~~~~~~~~~~~~
So, you have decided to go with non-filtered shadows because they are
faster, you want a little more detail or maybe you just like the sexy
saw-like shadow outlines because they remind you of your favorite
previous-gen games. Truth is, this can be kind of be a pain, but most of the
time it can be adjusted to have nice results. There is no magic number and
whatever result you come up will be different from scene to scene, it
just takes a while of tweaking. Let's go step by step.
First step is to turn on the shadows, let's assume that both Z-Offset
and Z-Slope-Scale are at 0. You will be greeted by this:
.. image:: /img/shadow_offset_1.png
Holy crap, the shadow is all over the place and extremely glitchy! This
happens because the shadow is fighting with the same geometry that is
casting it. This is called "self-shadowing". To avoid this meaningless
fight, you realize you need to make peace between the shadow and the
geometry, so you push back the shadow a little by increasing the shadow
Z-Offset. This improves things a lot:
.. image:: /img/shadow_offset_2.png
But it's not quite perfect, self shadowing did not disappear completely.
So close to perfection but still not there.. so in a turn of greed you
increase the Z-Offset even more!
.. image:: /img/shadow_offset_3.png
And it gets rid of those self-shadowings! Hooray! Except something is
wrong.. oh, right. Being pushed back too much, the shadows start
disconnecting from their casters, which looks pretty awful. Ok, you go
back to the previous Z-offset.
This is when Z-Slope-Scale comes to save the day. This setting makes
shadow caster objects thinner, so the borders don't self-shadow:
.. image:: /img/shadow_offset_4.png
Aha! Finally something that looks acceptable. It's perfectly acceptable
and you can perfectly ship a game that looks like this (imagine you are
looking at Final Fantasy quality art btw, not this horrible attempt at 3D
modelling). There may be very tiny bits left of self shadowing that no
one cares about, so your inextinguishable greed kicks in again and you
raise the Z-Slope Scale again:
.. image:: /img/shadow_offset_5.png
Well, that was too much, shadows casted are way too thin and don't look
good anymore. Well, though luck, the previous setting was good anyway,
let's accept that perfection does not exist and move on to something
else.
Important!
~~~~~~~~~~
If you are using shadow maps with directional lights, make sure that
the *view distance* of the *camera* is set to an *optimal range*. This
means, if the distance between your camera and the visible end of the
scene is 100, then set the view distance to that value. If a greater
than necessary value is used, the shadow maps will lose detail as they
will try to cover a bigger area.
So, always make sure to use the optimal range!
Shadow filtering
~~~~~~~~~~~~~~~~
Raw shadows are blocky. Increasing their resolution just makes smaller
blocks, but they are still blocks.
Godot offers a few ways to filter them (shadow in the example is
low-resolution on purpose!):
.. image:: /img/shadow_filter_options.png
PCF5 and PCF13 are simple texture-space filtering. Will make the texture
a little more acceptable but still needs considerable resolution for it
to look good.
ESM is a more complex filter and has a few more tweaking parameters. ESM
uses shadow blurring (amount of blur passes and multiplier can be
adjusted).

View File

@@ -0,0 +1,502 @@
.. _doc_matrices_and_transforms:
Matrices and transforms
=======================
Introduction
------------
Before reading this tutorial, it is advised to read the previous one
about :ref:`doc_vector_math` as this one is a direct continuation.
This tutorial will be about *transformations* and will cover a little
about matrices (but not in-depth).
Transformations are most of the time applied as translation, rotation
and scale so they will be considered as priority here.
Oriented coordinate system (OCS)
--------------------------------
Imagine we have a spaceship somewhere in space. In Godot this is easy,
just move the ship somewhere and rotate it:
.. image:: /img/tutomat1.png
Ok, so in 2D this looks simple, a position and an angle for a rotation.
But remember, we are grown ups here and don't use angles (plus, angles
are not really even that useful when working in 3D).
We should realize that at some point, someone *designed* this
spaceship. Be it for 2D in a drawing such as Paint.net, Gimp,
Photoshop, etc. or in 3D through a 3D DCC tool such as Blender, Max,
Maya, etc.
When it was designed, it was not rotated. It was designed in its own
*coordinate system*.
.. image:: /img/tutomat2.png
This means that the tip of the ship has a coordinate, the fin has
another, etc. Be it in pixels (2D) or vertices (3D).
So, let's recall again that the ship was somewhere in space:
.. image:: /img/tutomat3.png
How did it get there? What moved it and rotated it from the place it was
designed to its current position? The answer is... a **transform**, the
ship was *transformed* from their original position to the new one. This
allows the ship to be displayed where it is.
But transform is too generic of a term to describe this process. To solve this
puzzle, we will superimpose the ship's original design position at their
current position:
.. image:: /img/tutomat4.png
So, we can see that the "design space" has been transformed too. How can
we best represent this transformation? Let's use 3 vectors for this (in
2D), a unit vector pointing towards X positive, a unit vector pointing
towards Y positive and a translation.
.. image:: /img/tutomat5.png
Let's call the 3 vectors "X", "Y" and "Origin", and let's also
superimpose them over the ship so it makes more sense:
.. image:: /img/tutomat6.png
Ok, this is nicer, but it still does not make sense. What do X,Y and
Origin have to do with how the ship got there?
Well, let's take the point from top tip of the ship as reference:
.. image:: /img/tutomat7.png
And let's apply the following operation to it (and to all the points in
the ship too, but we'll track the top tip as our reference point):
::
var new_pos = pos - origin
Doing this to the selected point will move it back to the center:
.. image:: /img/tutomat8.png
This was expected, but then let's do something more interesting. Use the
dot product of X and the point, and add it to the dot product of Y and
the point:
::
var final_pos = x.dot(new_pos) + y.dot(new_pos)
Then what we have is.. wait a minute, it's the ship in its design
position!
.. image:: /img/tutomat9.png
How did this black magic happen? The ship was lost in space, and now
it's back home!
It might seem strange, but it does have plenty of logic. Remember, as
we have seen in the :ref:`doc_vector_math`, what
happened is that the distance to X axis, and the distance to Y axis
were computed. Calculating distance in a direction or plane was one of
the uses for the dot product. This was enough to obtain back the
design coordinates for every point in the ship.
So, what he have been working with so far (with X, Y and Origin) is an
*Oriented Coordinate System\*. X an Y are the **Basis**, and \*Origin*
is the offset.
Basis
-----
We know what the Origin is. It's where the 0,0 (origin) of the design
coordinate system ended up after being transformed to a new position.
This is why it's called *Origin*, But in practice, it's just an offset
to the new position.
The Basis is more interesting. The basis is the direction of X and Y in the OCS
from the new, transformed location. It tells what has changed, in either 2D or
3D. The Origin (offset) and Basis (direction) communicate "Hey, the original X
and Y axes of your design are *right here*, pointing towards *these
directions*."
So, let's change the representation of the basis. Instead of 2 vectors,
let's use a *matrix*.
.. image:: /img/tutomat10.png
The vectors are up there in the matrix, horizontally. The next problem
now is that.. what is this matrix thing? Well, we'll assume you've never
heard of a matrix.
Transforms in Godot
-------------------
This tutorial will not explain matrix math (and their operations) in
depth, only its practical use. There is plenty of material for that,
which should be a lot simpler to understand after completing this
tutorial. We'll just explain how to use transforms.
Matrix32
--------
:ref:`Matrix32 <class_Matrix32>` is a 3x2 matrix. It has 3 Vector2 elements and
it's used for 2D. The "X" axis is the element 0, "Y" axis is the element 1 and
"Origin" is element 2. It's not divided in basis/origin for convenience, due to
its simplicity.
::
var m = Matrix32()
var x = m[0] # 'X'
var y = m[1] # 'Y'
var o = m[2] # 'Origin'
Most operations will be explained with this datatype (Matrix32), but the
same logic applies to 3D.
Identity
--------
By default, Matrix32 is created as an "identity" matrix. This means:
- 'X' Points right: Vector2(1,0)
- 'Y' Points up (or down in pixels): Vector2(0,1)
- 'Origin' is the origin Vector2(0,0)
.. image:: /img/tutomat11.png
It's easy to guess that an *identity* matrix is just a matrix that
aligns the transform to its parent coordinate system. It's an *OCS*
that hasn't been translated, rotated or scaled. All transform types in
Godot are created with *identity*.
Operations
----------
Rotation
--------
Rotating Matrix32 is done by using the "rotated" function:
::
var m = Matrix32()
m = m.rotated(PI/2) # rotate 90°
.. image:: /img/tutomat12.png
Translation
-----------
There are two ways to translate a Matrix32, the first one is just moving
the origin:
::
# Move 2 units to the right
var m = Matrix32()
m = m.rotated(PI/2) # rotate 90°
m[2]+=Vector2(2,0)
.. image:: /img/tutomat13.png
This will always work in global coordinates.
If instead, translation is desired in *local* coordinates of the
matrix (towards where the *basis* is oriented), there is the
:ref:`Matrix32.translated() <class_Matrix32_translated>`
method:
::
# Move 2 units towards where the basis is oriented
var m = Matrix32()
m = m.rotated(PI/2) # rotate 90°
m=m.translated( Vector2(2,0) )
.. image:: /img/tutomat14.png
Scale
-----
A matrix can be scaled too. Scaling will multiply the basis vectors by a
vector (X vector by x component of the scale, Y vector by y component of
the scale). It will leave the origin alone:
::
# Make the basis twice its size.
var m = Matrix32()
m = m.scaled( Vector2(2,2) )
.. image:: /img/tutomat15.png
These kind of operations in matrices are accumulative. It means every
one starts relative to the previous one. For those who have been living
on this planet long enough, a good reference of how transform works is
this:
.. image:: /img/tutomat16.png
A matrix is used similarly to a turtle. The turtle most likely had a
matrix inside (and you are likely learning this many years *after*
discovering Santa is not real).
Transform
---------
Transform is the act of switching between coordinate systems. To convert
a position (either 2D or 3D) from "designer" coordinate system to the
OCS, the "xform" method is used.
::
var new_pos = m.xform(pos)
And only for basis (no translation):
::
var new_pos = m.basis_xform(pos)
Post - multiplying is also valid:
::
var new_pos = m * pos
Inverse transform
-----------------
To do the opposite operation (what we did up there with the rocket), the
"xform_inv" method is used:
::
var new_pos = m.xform_inv(pos)
Only for Basis:
::
var new_pos = m.basis_xform_inv(pos)
Or pre-multiplication:
::
var new_pos = pos * m
Orthonormal matrices
--------------------
However, if the Matrix has been scaled (vectors are not unit length),
or the basis vectors are not orthogonal (90°), the inverse transform
will not work.
In other words, inverse transform is only valid in *orthonormal*
matrices. For this, these cases an affine inverse must be computed.
The transform, or inverse transform of an identity matrix will return
the position unchanged:
::
# Does nothing, pos is unchanged
pos = Matrix32().xform(pos)
Affine inverse
--------------
The affine inverse is a matrix that does the inverse operation of
another matrix, no matter if the matrix has scale or the axis vectors
are not orthogonal. The affine inverse is calculated with the
affine_inverse() method:
::
var mi = m.affine_inverse()
var pos = m.xform(pos)
pos = mi.xform(pos)
# pos is unchanged
If the matrix is orthonormal, then:
::
# if m is orthonormal, then
pos = mi.xform(pos)
# is the same is
pos = m.xform_inv(pos)
Matrix multiplication
---------------------
Matrices can be multiplied. Multiplication of two matrices "chains"
(concatenates) their transforms.
However, as per convention, multiplication takes place in reverse
order.
Example:
::
var m = more_transforms * some_transforms
To make it a little clearer, this:
::
pos = transform1.xform(pos)
pos = transform2.xform(pos)
Is the same as:
::
# note the inverse order
pos = (transform2 * transform1).xform(pos)
However, this is not the same:
::
# yields a different results
pos = (transform1 * transform2).xform(pos)
Because in matrix math, A + B is not the same as B + A.
Multiplication by inverse
-------------------------
Multiplying a matrix by its inverse, results in identity
::
# No matter what A is, B will be identity
B = A.affine_inverse() * A
Multiplication by identity
--------------------------
Multiplying a matrix by identity, will result in the unchanged matrix:
::
# B will be equal to A
B = A * Matrix32()
Matrix tips
-----------
When using a transform hierarchy, remember that matrix multiplication is
reversed! To obtain the global transform for a hierarchy, do:
::
var global_xform = parent_matrix * child_matrix
For 3 levels:
::
# due to reverse order, parenthesis are needed
var global_xform = gradparent_matrix + (parent_matrix + child_matrix)
To make a matrix relative to the parent, use the affine inverse (or
regular inverse for orthonormal matrices).
::
# transform B from a global matrix to one local to A
var B_local_to_A = A.affine_inverse() * B
Revert it just like the example above:
::
# transform back local B to global B
var B = A * B_local_to_A
OK, hopefully this should be enough! Let's complete the tutorial by
moving to 3D matrices.
Matrices & transforms in 3D
---------------------------
As mentioned before, for 3D, we deal with 3 :ref:`Vector3 <class_Vector3>`
vectors for the rotation matrix, and an extra one for the origin.
Matrix3
-------
Godot has a special type for a 3x3 matrix, named :ref:`Matrix3 <class_Matrix3>`.
It can be used to represent a 3D rotation and scale. Sub vectors can be
accessed as:
::
var m = Matrix3()
var x = m[0] # Vector3
var y = m[1] # Vector3
var z = m[2] # Vector3
Or, alternatively as:
::
var m = Matrix3()
var x = m.x # Vector3
var y = m.y # Vector3
var z = m.z # Vector3
Matrix3 is also initialized to Identity by default:
.. image:: /img/tutomat17.png
Rotation in 3D
--------------
Rotation in 3D is more complex than in 2D (translation and scale are the
same), because rotation is an implicit 2D operation. To rotate in 3D, an
*axis*, must be picked. Rotation, then, happens around this axis.
The axis for the rotation must be a *normal vector*. As in, a vector
that can point to any direction, but length must be one (1.0).
::
#rotate in Y axis
var m3 = Matrix3()
m3 = m3.rotated( Vector3(0,1,0), PI/2 )
Transform
---------
To add the final component to the mix, Godot provides the
:ref:`Transform <class_Transform>` type. Transform has two members:
- *basis* (of type :ref:`Matrix3 <class_Matrix3>`
- *origin* (of type :ref:`Vector3 <class_Vector3>`
Any 3D transform can be represented with Transform, and the separation
of basis and origin makes it easier to work translation and rotation
separately.
An example:
::
var t = Transform()
pos = t.xform(pos) # transform 3D position
pos = t.basis.xform(pos) # (only rotate)
pos = t.origin + pos (only translate)

View File

@@ -0,0 +1,897 @@
.. _doc_vector_math:
Vector math
===========
Introduction
~~~~~~~~~~~~
This small tutorial aims to be a short and practical introduction to
vector math, useful for 3D but also 2D games. Again, vector math is not
only useful for 3D but *also* 2D games. It is an amazing tool once you
get the grasp of it and makes programming of complex behaviors much
simpler.
It often happens that young programmers rely too much on the *incorrect*
math for solving a wide array of problems, for example using only
trigonometry instead of vector of math for 2D games.
This tutorial will focus on practical usage, with immediate application
to the art of game programming.
Coordinate systems (2D)
~~~~~~~~~~~~~~~~~~~~~~~
Typically, we define coordinates as an (x,y) pair, x representing the
horizontal offset and y the vertical one. This makes sense given the
screen is just a rectangle in two dimensions. As an example, here is a
position in 2D space:
.. image:: /img/tutovec1.png
A position can be anywhere in space. The position (0,0) has a name, it's
called the **origin**. Remember this term well because it has more
implicit uses later. The (0,0) of a n-dimensions coordinate system is
the **origin**.
In vector math, coordinates have two different uses, both equally
important. They are used to represent a *position* but also a *vector*.
The same position as before, when imagined as a vector, has a different
meaning.
.. image:: /img/tutovec2.png
When imagined as a vector, two properties can be inferred, the
**direction** and the **magnitude**. Every position in space can be a
vector, with the exception of the **origin**. This is because
coordinates (0,0) can't represent direction (magnitude 0).
.. image:: /img/tutovec2b.png
Direction
---------
Direction is simply towards where the vector points to. Imagine an arrow
that starts at the **origin** and goes towards a [STRIKEOUT:position].
The tip of the arrow is in the position, so it always points outwards,
away from the origin. Imagining vectors as arrows helps a lot.
.. image:: /img/tutovec3b.png
Magnitude
---------
Finally, the length of the vector is the distance from the origin to the
position. Obtaining the length from a vector is easy, just use the
`Pythagorean
Theorem <http://en.wikipedia.org/wiki/Pythagorean_theorem>`__.
::
var len = sqrt( x*x + y*y )
But... angles?
--------------
But why not using an *angle*? After all, we could also think of a vector
as an angle and a magnitude, instead of a direction and a magnitude.
Angles also are a more familiar concept.
To say truth, angles are not that useful in vector math, and most of the
time they are not dealt with directly. Maybe they work in 2D, but in 3D
a lot of what can usually be done with angles does not work anymore.
Still, using angles is still not an excuse, even for 2D. Most of what
takes a lot of work with angles in 2D, is still much more natural easier
to accomplish with vector math. In vector math, angles are useful only
as measure, but take little part in the math. So, give up the
trigonometry already, prepare to embrace vectors!
In any case, obtaining an angle from a vector is easy and can be
accomplished with trig... er, what was that? I mean, the
:ref:`atan2() <class_@GDScript_atan2>` function.
Vectors in Godot
~~~~~~~~~~~~~~~~
To make examples easier, it is worth explaining how vectors are
implemented in GDScript. GDscript has both
:ref:`Vector2 <class_Vector2>` and :ref:`Vector3 <class_Vector3>`,
for 2D and 3D math respectively. Godot uses Vector classes as both
position and direction. They also contain x and y (for 2D) and x, y and
z (for 3D) member variables.
::
# create a vector with coordinates (2,5)
var a = Vector2(2,5)
# create a vector and assign x and y manually
var b = Vector2()
b.x = 7
b.y = 8
When operating with vectors, it is not necessary to operate on the
members directly (in fact this is much slower). Vectors support regular
arithmetic operations:
::
# add a and b
var c = a + b
# will result in c vector, with value (9,13)
It is the same as doing:
::
var c = Vector2()
c.x = a.x + b.x
c.y = a.y + b.y
Except the former is way more efficient and readable.
Regular arithmetic operations such as addition, subtraction,
multiplication and division are supported.
Vector multiplication and division can also be mixed with single-digit
numbers, also named **scalars**.
::
# multiplication of vector by scalar
var c = a*2.0
# will result in c vector, with value (4,10)
Which is the same as doing
::
var c = Vector2()
c.x = a.x*2.0
c.y = a.y*2.0
Except, again, the former is way more efficient and readable.
Perpendicular vectors
~~~~~~~~~~~~~~~~~~~~~
Rotating a 2D vector 90° degrees to either side, left or right, is
really easy, just swap x and y, then negate either x or y (direction of
rotation depends on which is negated).
.. image:: /img/tutovec15.png
Example:
::
var v = Vector2(0,1)
# rotate right (clockwise)
var v_right = Vector2(v.y, -v.x)
# rotate left (counter-clockwise)
var v_left = Vector2(-v.y, v.x)
This is a handy trick that is often of use. It is impossible to do with
3D vectors, because there are an infinite amount of perpendicular
vectors.
Unit vectors
~~~~~~~~~~~~
Ok, so we know what a vector is. It has a **direction** and a
**magnitude**. We also know how to use them in Godot. The next step is
learning about **unit vectors**. Any vector with **magnitude** of length
1 is considered a **unit vector**. In 2D, imagine drawing a circle of
radius one. That circle contains all unit vectors in existence for 2
dimensions:
.. image:: /img/tutovec3.png
So, what is so special about unit vectors? Unit vectors are amazing. In
other words, unit vectors have **several, very useful properties**.
Can't wait to know more about the fantastic properties of unit vectors,
but one step at a time. So, how is a unit vector created from a regular
vector?
Normalization
-------------
Taking any vector and reducing its **magnitude** to 1.0 while keeping
its **direction** is called **normalization**. Normalization is
performed by dividing the x and y (and z in 3D) components of a vector
by its magnitude:
::
var a = Vector2(2,4)
var m = sqrt(a.x*a.x + a.y*a.y)
a.x /= m
a.y /= m
As you might have guessed, if the vector has magnitude 0 (meaning, it's
not a vector but the **origin** also called *null vector*), a division
by zero occurs and the universe goes through a second big bang, except
in reverse polarity and then back. As a result, humanity is safe but
Godot will print an error. Remember! Vector(0,0) can't be normalized!.
Of course, Vector2 and Vector3 already provide a method to do this:
::
a = a.normalized()
Dot product
~~~~~~~~~~~
OK, the **dot product** is the most important part of vector math.
Without the dot product, Quake would have never been made. This is the
most important section of the tutorial, so make sure to grasp it
properly. Most people trying to understand vector math give up here
because, despite how simple it is, they can't make head or tails from
it. Why? Here's why, it's because...
The dot product takes two vectors and returns a **scalar**:
::
var s = a.x*b.x + a.y*b.y
Yes, pretty much that. Multiply **x** from vector **a** by **x** from
vector **b**. Do the same with y and add it together. In 3D it's pretty
much the same:
::
var s = a.x*b.x + a.y*b.y + a.z*b.z
I know, it's totally meaningless! You can even do it with a built-in
function:
::
var s = a.dot(b)
The order of two vectors does *not* matter, ``a.dot(b)`` returns the
same value as ``b.dot(a)``.
This is where despair begins and books and tutorials show you this
formula:
.. image:: /img/tutovec4.png
And you realize it's time to give up making 3D games or complex 2D
games. How can something so simple be so complex? Someone else will have
to make the next Zelda or Call of Duty. Top down RPGs don't look so bad
after all. Yeah I hear someone did pretty will with one of those on
Steam...
So this is your moment, this is your time to shine. **DO NOT GIVE UP**!
At this point, this tutorial will take a sharp turn and focus on what
makes the dot product useful. This is, **why** it is useful. We will
focus one by one in the use cases for the dot product, with real-life
applications. No more formulas that don't make any sense. Formulas will
make sense *once you learn* what they are useful for.
Siding
------
The first useful and most important property of the dot product is to
check what side stuff is looking at. Let's imagine we have any two
vectors, **a** and **b**. Any **direction** or **magnitude** (neither
**origin**). Does not matter what they are, but let's imagine we compute
the dot product between them.
::
var s = a.dot(b)
The operation will return a single floating point number (but since we
are in vector world, we call them **scalar**, will keep using that term
from now on). This number will tell us the following:
- If the number is greater than zero, both are looking towards the same
direction (the angle between them is < 90° degrees).
- If the number is less than zero, both are looking towards opposite
direction (the angle between them is > 90° degrees).
- If the number is zero, vectors are shaped in L (the angle between
them *is* 90° degrees).
.. image:: /img/tutovec5.png
So let's think of a real use-case scenario. Imagine Snake is going
through a forest, and then there is an enemy nearby. How can we quickly
tell if the enemy has seen discovered Snake? In order to discover him,
the enemy must be able to *see* Snake. Let's say, then that:
- Snake is in position **A**.
- The enemy is in position **B**.
- The enemy is *facing* towards direction vector **F**.
.. image:: /img/tutovec6.png
So, let's create a new vector **BA** that goes from the guard (**B**) to
Snake (**A**), by subtracting the two:
::
var BA = A - B
.. image:: /img/tutovec7.png
Ideally, if the guard was looking straight towards snake, to make eye to
eye contact, it would do it in the same direction as vector BA.
If the dot product between **F** and **BA** is greater than 0, then
Snake will be discovered. This happens because we will be able to tell
that the guard is facing towards him:
::
if (BA.dot(F) > 0):
print("!")
Seems Snake is safe so far.
Siding with unit vectors
~~~~~~~~~~~~~~~~~~~~~~~~
Ok, so now we know that dot product between two vectors will let us know
if they are looking towards the same side, opposite sides or are just
perpendicular to each other.
This works the same with all vectors, no matter the magnitude so **unit
vectors** are not the exception. However, using the same property with
unit vectors yields an even more interesting result, as an extra
property is added:
- If both vectors are facing towards the exact same direction (parallel
to each other, angle between them is 0°), the resulting scalar is
**1**.
- If both vectors are facing towards the exact opposite direction
(parallel to each other, but angle between them is 180°), the
resulting scalar is **-1**.
This means that dot product between unit vectors is always between the
range of 1 and -1. So Again...
- If their angle is **0°** dot product is **1**.
- If their angle is **90°**, then dot product is **0**.
- If their angle is **180°**, then dot product is **-1**.
Uh.. this is oddly familiar... seen this before... where?
Let's take two unit vectors. The first one is pointing up, the second
too but we will rotate it all the way from up (0°) to down (180°
degrees)...
.. image:: /img/tutovec8.png
While plotting the resulting scalar!
.. image:: /img/tutovec9.png
Aha! It all makes sense now, this is a
`Cosine <http://mathworld.wolfram.com/Cosine.html>`__ function!
We can say that, then, as a rule...
The **dot product** between two **unit vectors** is the **cosine** of
the **angle** between those two vectors. So, to obtain the angle between
two vectors, we must do:
::
var angle_in_radians = acos( a.dot(b) )
What is this useful for? Well obtaining the angle directly is probably
not as useful, but just being able to tell the angle is useful for
reference. One example is in the `Kinematic
Character <https://github.com/godotengine/godot-demo-projects/blob/master/2d/kinematic_char/player.gd#L79>`__
demo, when the character moves in a certain direction then we hit an
object. How to tell if what we hit is the floor?
By comparing the normal of the collision point with a previously
computed angle.
The beauty of this is that the same code works exactly the same and
without modification in
`3D <https://github.com/godotengine/godot-demo-projects/blob/master/3d/kinematic_char/cubio.gd#L57>`__.
Vector math is, in a great deal, dimension-amount-independent, so adding
or removing an axis only adds very little complexity.
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:
.. image:: /img/tutovec10.png
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 Origin to (0,0)!).
It's as simple as it looks. The plane passes by the origin and the
surface of it is perpendicular to the unit vector (or *normal*). The
side towards 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**:
::
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:
.. image:: /img/tutovec11.png
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:
.. image:: /img/tutovec12.png
For 3D math, Godot provides a :ref:`Plane <class_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:
::
var point_in_plane = 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:
::
var distance = N.dot(point) - D
The same thing, using a built-in function:
::
var distance = plane.distance_to(point)
This will, again, return either a positive or negative distance.
Flipping the polarity of the plane is also very simple, just negate both
N and D. This will result in a plane in the same position, but with
inverted negative and positive half spaces:
::
N = -N
D = -D
Of course, Godot also implements this operator in :ref:`Plane <class_Plane>`,
so doing:
::
var inverted_plane = -plane
Will work as expected.
So, remember, a plane is just that and its main practical use is
calculating the distance to it. So, why is it useful to calculate the
distance from a point to a plane? It's extremely useful! Let's see some
simple 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 just calculate D from the dot product of
the normal and the 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:
::
# calculate vector from a to b
var dvec = (point_b - point_a).normalized()
# rotate 90 degrees
var normal = Vector2(dvec.y,-dev.x)
# or alternatively
# var normal = Vector2(-dvec.y,dev.x)
# depending the desired side of the normal
The rest is the same as the previous example, either point_a or
point_b will work since they are in the same plane:
::
var N = normal
var D = normal.dot(point_a)
# this works the same
# var D = normal.dot(point_b)
Doing the same in 3D is a little more complex and will be explained
further down.
Some examples of planes
-----------------------
Here is a simple example of what planes are useful for. Imagine you have
a `convex <http://www.mathsisfun.com/definitions/convex.html>`__
polygon. For example, a rectangle, a trapezoid, a triangle, or just any
polygon where faces that don't 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.
.. image:: /img/tutovec13.png
Code should be something like this:
::
var inside = true
for p in planes:
# check if distance to plane is positive
if (N.dot(point) - D > 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.
The idea is really simple! 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:
.. image:: /img/tutovec14.png
Code should be something like this:
::
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!")
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).
Cross product
-------------
Quite a lot can be done with the dot product! But the party would not be
complete without the cross product. Remember back at the beginning of
this tutorial? Specifically how to obtain a perpendicular (rotated 90
degrees) vector by swapping x and y, then negating either of them for
right (clockwise) or left (counter-clockwise) rotation? That ended up
being useful for calculating a 2D plane normal from two points.
As mentioned before, no such thing exists in 3D because a 3D vector has
infinite perpendicular vectors. It would also not make sense to obtain a
3D plane from 2 points, as 3 points are needed instead.
To aid in this kind stuff, the brightest minds of humanity's top
mathematicians brought us the **cross product**.
The cross product takes two vectors and returns another vector. The
returned third vector is always perpendicular to the first two. The
source vectors, of course, must not be the same, and must not be
parallel or opposite, else the resulting vector will be (0,0,0):
.. image:: /img/tutovec16.png
The formula for the cross product is:
::
var c = Vector3()
c.x = (a.y * b.z) - (a.z * b.y)
c.y = (a.z * b.x) - (a.x * b.z)
c.z = (a.x * b.y) - (a.y * b.x)
This can be simplified, in Godot, to:
::
var c = a.cross(b)
However, unlike the dot product, doing ``a.cross(b)`` and ``b.cross(a)``
will yield different results. Specifically, the returned vector will be
negated in the second case. As you might have realized, this coincides
with creating perpendicular vectors in 2D. In 3D, there are also two
possible perpendicular vectors to a pair of 2D vectors.
Also, the resulting cross product of two unit vectors is *not* a unit
vector. Result will need to be renormalized.
Area of a triangle
~~~~~~~~~~~~~~~~~~
Cross product can be used to obtain the surface area of a triangle in
3D. Given a triangle consisting of 3 points, **A**, **B** and **C**:
.. image:: /img/tutovec17.png
Take any of them as a pivot and compute the adjacent vectors to the
other two points. As example, we will use B as a pivot:
::
var BA = A - B
var BC = C - B
.. image:: /img/tutovec18.png
Compute the cross product between **BA** and **BC** to obtain the
perpendicular vector **P**:
::
var P = BA.cross(BC)
.. image:: /img/tutovec19.png
The length (magnitude) of **P** is the surface area of the parallelogram
built by the two vectors **BA** and **BC**, therefore the surface area
of the triangle is half of it.
::
var area = P.length()/2
Plane of the triangle
~~~~~~~~~~~~~~~~~~~~~
With **P** computed from the previous step, normalize it to get the
normal of the plane.
::
var N = P.normalized()
And obtain the distance by doing the dot product of P with any of the 3
points of the **ABC** triangle:
::
var D = P.dot(A)
Fantastic! You computed the plane from a triangle!
Here's some useful info (that you can find in Godot source code anyway).
Computing a plane from a triangle can result in 2 planes, so a sort of
convention needs to be set. This usually depends (in video games and 3D
visualization) to use the front-facing side of the triangle.
In Godot, front-facing triangles are those that, when looking at the
camera, are in clockwise order. Triangles that look Counter-clockwise
when looking at the camera are not drawn (this helps to draw less, so
the back-part of the objects is not drawn).
To make it a little clearer, in the image below, the triangle **ABC**
appears clock-wise when looked at from the *Front Camera*, but to the
*Rear Camera* it appears counter-clockwise so it will not be drawn.
.. image:: /img/tutovec20.png
Normals of triangles often are sided towards the direction they can be
viewed from, so in this case, the normal of triangle ABC would point
towards the front camera:
.. image:: /img/tutovec21.png
So, to obtain N, the correct formula is:
::
# clockwise normal from triangle formula
var N = (A-C).cross(A-B).normalized()
# for counter-clockwise:
# var N = (A-B).cross(A-C).normalized()
var D = N.dot(A)
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 a really cool algorithm to understand
anyway, because 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:
.. image:: /img/tutovec22.png
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
.. image:: /img/tutovec23.png
So the final algorithm is something like:
::
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)
if (d > max_A):
max_A = d
if (d < min_A):
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)
if (d > max_B):
max_B = d
if (d < min_B):
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!")
This was all! Hope it was helpful, and please give feedback and let know
if something in this tutorial is not clear! You should be now ready for
the next challenge... :ref:`doc_matrices_and_transforms`!

View File

@@ -0,0 +1,299 @@
.. _doc_background_loading:
Background loading
==================
When switching the main scene of your game (for example going to a new
level), you might want to show a loading screen with some indication
that progress is being made. The main load method
(``ResourceLoader::load`` or just ``load`` from gdscript) blocks your
thread while the resource is being loaded, so It's not good. This
document discusses the ``ResourceInteractiveLoader`` class for smoother
load screens.
ResourceInteractiveLoader
-------------------------
The ``ResourceInteractiveLoader`` class allows you to load a resource in
stages. Every time the method ``poll`` is called, a new stage is loaded,
and control is returned to the caller. Each stage is generally a
sub-resource that is loaded by the main resource. For example, if you're
loading a scene that loads 10 images, each image will be one stage.
Usage
-----
Usage is generally as follows
Obtaining a ResourceInteractiveLoader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(String p_path);
This method will give you a ResourceInteractiveLoader that you will use
to manage the load operation.
Polling
~~~~~~~
::
Error ResourceInteractiveLoader::poll();
Use this method to advance the progress of the load. Each call to
``poll`` will load the next stage of your resource. Keep in mind that
each stage is one entire "atomic" resource, such as an image, or a mesh,
so it will take several frames to load.
Returns ``OK`` on no errors, ``ERR_FILE_EOF`` when loading is finished.
Any other return value means there was an error and loading has stopped.
Load progress (optional)
~~~~~~~~~~~~~~~~~~~~~~~~
To query the progress of the load, use the following methods:
::
int ResourceInteractiveLoader::get_stage_count() const;
int ResourceInteractiveLoader::get_stage() const;
``get_stage_count`` returns the total number of stages to load.
``get_stage`` returns the current stage being loaded.
Forcing completion (optional)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
::
Error ResourceInteractiveLoader::wait();
Use this method if you need to load the entire resource in the current
frame, without any more steps.
Obtaining the resource
~~~~~~~~~~~~~~~~~~~~~~
::
Ref<Resource> ResourceInteractiveLoader::get_resource();
If everything goes well, use this method to retrieve your loaded
resource.
Example
-------
This example demostrates how to load a new scene. Consider it in the
context of the :ref:`doc_singletons_autoload` example.
First we setup some variables and initialize the ``current_scene``
with the main scene of the game:
::
var loader
var wait_frames
var time_max = 100 # msec
var current_scene
func _ready():
var root = get_tree().get_root()
current_scene = root.get_child(root.get_child_count() -1)
The function ``goto_scene`` is called from the game when the scene
needs to be switched. It requests an interactive loader, and calls
``set_progress(true)`` to start polling the loader in the ``_progress``
callback. It also starts a "loading" animation, which can show a
progress bar or loading screen, etc.
::
func goto_scene(path): # game requests to switch to this scene
loader = ResourceLoader.load_interactive(path)
if loader == null: # check for errors
show_error()
return
set_process(true)
current_scene.queue_free() # get rid of the old scene
# start your "loading..." animation
get_node("animation").play("loading")
wait_frames = 1
``_process`` is where the loader is polled. ``poll`` is called, and then
we deal with the return value from that call. ``OK`` means keep polling,
``ERR_FILE_EOF`` means load is done, anything else means there was an
error. Also note we skip one frame (via ``wait_frames``, set on the
``goto_scene`` function) to allow the loading screen to show up.
Note how use use ``OS.get_ticks_msec`` to control how long we block the
thread. Some stages might load really fast, which means we might be able
to cram more than one call to ``poll`` in one frame, some might take way
more than your value for ``time_max``, so keep in mind we won't have
precise control over the timings.
::
func _process(time):
if loader == null:
# no need to process anymore
set_process(false)
return
if wait_frames > 0: # wait for frames to let the "loading" animation to show up
wait_frames -= 1
return
var t = OS.get_ticks_msec()
while OS.get_ticks_msec() < t + time_max: # use "time_max" to control how much time we block this thread
# poll your loader
var err = loader.poll()
if err == ERR_FILE_EOF: # load finished
var resource = loader.get_resource()
loader = null
set_new_scene(resource)
break
elif err == OK:
update_progress()
else: # error during loading
show_error()
loader = null
break
Some extra helper functions. ``update_progress`` updates a progress bar,
or can also update a paused animation (the animation represents the
entire load process from beginning to end). ``set_new_scene`` puts the
newly loaded scene on the tree. Because it's a scene being loaded,
``instance()`` needs to be called on the resource obtained from the
loader.
::
func update_progress():
var progress = float(loader.get_stage()) / loader.get_stage_count()
# update your progress bar?
get_node("progress").set_progress(progress)
# or update a progress animation?
var len = get_node("animation").get_current_animation_length()
# call this on a paused animation. use "true" as the second parameter to force the animation to update
get_node("animation").seek(progress * len, true)
func set_new_scene(scene_resource):
current_scene = scene_resource.instance()
get_node("/root").add_child(current_scene)
Using multiple threads
----------------------
ResourceInteractiveLoader can be used from multiple threads. A couple of
things to keep in mind if you attempt it:
Use a Semaphore
~~~~~~~~~~~~~~~
While your thread waits for the main thread to request a new resource,
use a Semaphore to sleep (instead of a busy loop or anything similar).
Not blocking main thread during the polling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you have a mutex to allow calls from the main thread to your loader
class, don't lock it while you call ``poll`` on the loader. When a
resource is finished loading, it might require some resources from the
low level APIs (VisualServer, etc), which might need to lock the main
thread to acquire them. This might cause a deadlock if the main thread
is waiting for your mutex while your thread is waiting to load a
resource.
Example class
-------------
You can find an example class for loading resources in threads here:
:download:`resource_queue.gd </files/resource_queue.gd>`. Usage is as follows:
::
func start()
Call after you instance the class to start the thread.
::
func queue_resource(path, p_in_front = false)
Queue a resource. Use optional parameter "p_in_front" to put it in
front of the queue.
::
func cancel_resource(path)
Remove a resource from the queue, discarding any loading done.
::
func is_ready(path)
Returns true if a resource is done loading and ready to be retrieved.
::
func get_progress(path)
Get the progress of a resource. Returns -1 on error (for example if the
resource is not on the queue), or a number between 0.0 and 1.0 with the
progress of the load. Use mostly for cosmetic purposes (updating
progress bars, etc), use ``is_ready`` to find out if a resource is
actually ready.
::
func get_resource(path)
Returns the fully loaded resource, or null on error. If the resource is
not done loading (``is_ready`` returns false), it will block your thread
and finish the load. If the resource is not on the queue, it will call
``ResourceLoader::load`` to load it normally and return it.
Example:
~~~~~~~~
::
# initialize
queue = preload("res://resource_queue.gd").new()
queue.start()
# suppose your game starts with a 10 second custscene, during which the user can't interact with the game.
# For that time we know they won't use the pause menu, so we can queue it to load during the cutscene:
queue.queue_resource("res://pause_menu.xml")
start_curscene()
# later when the user presses the pause button for the first time:
pause_menu = queue.get_resource("res://pause_menu.xml").instance()
pause_menu.show()
# when you need a new scene:
queue.queue_resource("res://level_1.xml", true) # use "true" as the second parameter to put it at the front
# of the queue, pausing the load of any other resource
# to check progress
if queue.is_ready("res://level_1.xml"):
show_new_level(queue.get_resource("res://level_1.xml"))
else:
update_progress(queue.get_process("res://level_1.xml"))
# when the user walks away from the trigger zone in your Metroidvania game:
queue.cancel_resource("res://zone_2.xml")
**Note**: this code in its current form is not tested in real world
scenarios. Ask punto on IRC (#godotengine on irc.freenode.net) for help.

View File

@@ -0,0 +1,504 @@
.. _doc_binary_serialization_api:
Binary serialization API
========================
Introduction
------------
Godot has a simple serialization API based on Variant. It's used for
converting data types to an array of bytes efficiently. This API is used
in the functions ``get_var`` and ``store_var`` of :ref:`class_File`
as well as the packet APIs for :ref:`class_PacketPeer`. This format
is not used for binary scenes and resources.
Packet specification
--------------------
The packet is designed to be always padded to 4 bytes. All values are
little endian encoded. All packets have a 4 byte header representing an
integer, specifying the type of data:
+--------+--------------------------+
| Type | Value |
+========+==========================+
| 0 | null |
+--------+--------------------------+
| 1 | bool |
+--------+--------------------------+
| 2 | integer |
+--------+--------------------------+
| 3 | float |
+--------+--------------------------+
| 4 | string |
+--------+--------------------------+
| 5 | vector2 |
+--------+--------------------------+
| 6 | rect2 |
+--------+--------------------------+
| 7 | vector3 |
+--------+--------------------------+
| 8 | matrix32 |
+--------+--------------------------+
| 9 | plane |
+--------+--------------------------+
| 10 | quaternion |
+--------+--------------------------+
| 11 | aabb (rect3) |
+--------+--------------------------+
| 12 | matrix3x3 |
+--------+--------------------------+
| 13 | transform (matrix 4x3) |
+--------+--------------------------+
| 14 | color |
+--------+--------------------------+
| 15 | image |
+--------+--------------------------+
| 16 | node path |
+--------+--------------------------+
| 17 | rid (unsupported) |
+--------+--------------------------+
| 18 | object (unsupported) |
+--------+--------------------------+
| 19 | input event |
+--------+--------------------------+
| 20 | dictionary |
+--------+--------------------------+
| 21 | array |
+--------+--------------------------+
| 22 | ByteArray |
+--------+--------------------------+
| 23 | IntArray |
+--------+--------------------------+
| 24 | FloatArray |
+--------+--------------------------+
| 25 | StringArray |
+--------+--------------------------+
| 26 | Vector2Array |
+--------+--------------------------+
| 27 | Vector3Array |
+--------+--------------------------+
| 28 | ColorArray |
+--------+--------------------------+
Following this is the actual packet contents, which varies for each type
of packet:
0: null
~~~~~~~
1: bool
~~~~~~~
+----------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+===========================+
| 4 | 4 | Integer | 0 for False, 1 for True |
+----------+-------+-----------+---------------------------+
2: integer
~~~~~~~~~~
+----------+-------+-----------+--------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+==========================+
| 4 | 4 | Integer | Signed, 32-Bit Integer |
+----------+-------+-----------+--------------------------+
3: float
~~~~~~~~
+----------+-------+---------+-------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+=========================+
| 4 | 4 | Float | IEE 754 32-Bits Float |
+----------+-------+---------+-------------------------+
4: string
~~~~~~~~~
+----------+-------+-----------+----------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+============================+
| 4 | 4 | Integer | String Length (in Bytes) |
+----------+-------+-----------+----------------------------+
| 8 | X | Bytes | UTF-8 Encoded String |
+----------+-------+-----------+----------------------------+
This field is padded to 4 bytes.
5: vector2
~~~~~~~~~~
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
| 4 | 4 | Float | X Coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y Coordinate |
+----------+-------+---------+----------------+
6: rect2
~~~~~~~~
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
| 4 | 4 | Float | X Coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y Coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | X Size |
+----------+-------+---------+----------------+
| 16 | 4 | Float | Y Size |
+----------+-------+---------+----------------+
7: vector3
~~~~~~~~~~
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
| 4 | 4 | Float | X Coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y Coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | Z Coordinate |
+----------+-------+---------+----------------+
8: matrix32
~~~~~~~~~~~
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
| 4 | 4 | Float | [0][0] |
+----------+-------+---------+---------------+
| 8 | 4 | Float | [0][1] |
+----------+-------+---------+---------------+
| 12 | 4 | Float | [1][0] |
+----------+-------+---------+---------------+
| 16 | 4 | Float | [1][1] |
+----------+-------+---------+---------------+
| 20 | 4 | Float | [2][0] |
+----------+-------+---------+---------------+
| 24 | 4 | Float | [2][1] |
+----------+-------+---------+---------------+
9: plane
~~~~~~~~
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
| 4 | 4 | Float | Normal X |
+----------+-------+---------+---------------+
| 8 | 4 | Float | Normal Y |
+----------+-------+---------+---------------+
| 12 | 4 | Float | Normal Z |
+----------+-------+---------+---------------+
| 16 | 4 | Float | Distance |
+----------+-------+---------+---------------+
10: quaternion
~~~~~~~~~~~~~~
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
| 4 | 4 | Float | Imaginary X |
+----------+-------+---------+---------------+
| 8 | 4 | Float | Imaginary Y |
+----------+-------+---------+---------------+
| 12 | 4 | Float | Imaginary Z |
+----------+-------+---------+---------------+
| 16 | 4 | Float | Real W |
+----------+-------+---------+---------------+
11: aabb (rect3)
~~~~~~~~~~~~~~~~
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
| 4 | 4 | Float | X Coordinate |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Y Coordinate |
+----------+-------+---------+----------------+
| 12 | 4 | Float | Z Coordinate |
+----------+-------+---------+----------------+
| 16 | 4 | Float | X Size |
+----------+-------+---------+----------------+
| 20 | 4 | Float | Y Size |
+----------+-------+---------+----------------+
| 24 | 4 | Float | Z Size |
+----------+-------+---------+----------------+
12: matrix3x3
~~~~~~~~~~~~~
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
| 4 | 4 | Float | [0][0] |
+----------+-------+---------+---------------+
| 8 | 4 | Float | [0][1] |
+----------+-------+---------+---------------+
| 12 | 4 | Float | [0][2] |
+----------+-------+---------+---------------+
| 16 | 4 | Float | [1][0] |
+----------+-------+---------+---------------+
| 20 | 4 | Float | [1][1] |
+----------+-------+---------+---------------+
| 24 | 4 | Float | [1][2] |
+----------+-------+---------+---------------+
| 28 | 4 | Float | [2][0] |
+----------+-------+---------+---------------+
| 32 | 4 | Float | [2][1] |
+----------+-------+---------+---------------+
| 36 | 4 | Float | [2][2] |
+----------+-------+---------+---------------+
13: transform (matrix 4x3)
~~~~~~~~~~~~~~~~~~~~~~~~~~
+----------+-------+---------+---------------+
| Offset | Len | Type | Description |
+==========+=======+=========+===============+
| 4 | 4 | Float | [0][0] |
+----------+-------+---------+---------------+
| 8 | 4 | Float | [0][1] |
+----------+-------+---------+---------------+
| 12 | 4 | Float | [0][2] |
+----------+-------+---------+---------------+
| 16 | 4 | Float | [1][0] |
+----------+-------+---------+---------------+
| 20 | 4 | Float | [1][1] |
+----------+-------+---------+---------------+
| 24 | 4 | Float | [1][2] |
+----------+-------+---------+---------------+
| 28 | 4 | Float | [2][0] |
+----------+-------+---------+---------------+
| 32 | 4 | Float | [2][1] |
+----------+-------+---------+---------------+
| 36 | 4 | Float | [2][2] |
+----------+-------+---------+---------------+
| 40 | 4 | Float | [3][0] |
+----------+-------+---------+---------------+
| 44 | 4 | Float | [3][1] |
+----------+-------+---------+---------------+
| 48 | 4 | Float | [3][2] |
+----------+-------+---------+---------------+
14: color
~~~~~~~~~
+----------+-------+---------+----------------+
| Offset | Len | Type | Description |
+==========+=======+=========+================+
| 4 | 4 | Float | Red (0..1) |
+----------+-------+---------+----------------+
| 8 | 4 | Float | Green (0..1) |
+----------+-------+---------+----------------+
| 12 | 4 | Float | Blue (0..1) |
+----------+-------+---------+----------------+
| 16 | 4 | Float | Alpha (0..1) |
+----------+-------+---------+----------------+
15: image
~~~~~~~~~
+---------------------+-------+-----------+--------------------------------------------------+
| Offset | Len | Type | Description |
+=====================+=======+===========+==================================================+
| 4 | 4 | Integer | Format (see FORMAT\_\* in "Image":class_image |
+---------------------+-------+-----------+--------------------------------------------------+
| 8 | 4 | Integer | Mip-Maps (0 means no mip-maps). |
+---------------------+-------+-----------+--------------------------------------------------+
| 12 | 4 | Integer | Width (Pixels) |
+---------------------+-------+-----------+--------------------------------------------------+
| 16 | 4 | Integer | Height (Pixels) |
+---------------------+-------+-----------+--------------------------------------------------+
| 20 | 4 | Integer | Data Length |
+---------------------+-------+-----------+--------------------------------------------------+
| 24..24+DataLength | 1 | Byte | Image Data |
+---------------------+-------+-----------+--------------------------------------------------+
This field is padded to 4 bytes.
16: node path
~~~~~~~~~~~~~
+----------+-------+-----------+-----------------------------------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=========================================================================================+
| 4 | 4 | Integer | String Length, or New Format (val&0x80000000!=0 and NameCount=val&0x7FFFFFFF) |
+----------+-------+-----------+-----------------------------------------------------------------------------------------+
For old format:
^^^^^^^^^^^^^^^
+----------+-------+---------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+=========+========================+
| 8 | X | Bytes | UTF-8 Encoded String |
+----------+-------+---------+------------------------+
Padded to 4 bytes.
For new format:
^^^^^^^^^^^^^^^
+----------+-------+-----------+-------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================+
| 4 | 4 | Integer | Sub-Name Count |
+----------+-------+-----------+-------------------------------------+
| 8 | 4 | Integer | Flags (absolute: val&1 != 0 ) |
+----------+-------+-----------+-------------------------------------+
For each Name and Sub-Name
+----------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+========================+
| X+0 | 4 | Integer | String Length |
+----------+-------+-----------+------------------------+
| X+4 | X | Bytes | UTF-8 Encoded String |
+----------+-------+-----------+------------------------+
Every name string is padded to 4 bytes.
17: rid (unsupported)
~~~~~~~~~~~~~~~~~~~~~
18: object (unsupported)
~~~~~~~~~~~~~~~~~~~~~~~~
19: input event
~~~~~~~~~~~~~~~
20: dictionary
~~~~~~~~~~~~~~
+----------+-------+-----------+---------------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================================================+
| 4 | 4 | Integer | val&0x7FFFFFFF = elements, val&0x80000000 = shared (bool) |
+----------+-------+-----------+---------------------------------------------------------------------+
Then what follows is, for amount of "elements", pairs of key and value,
one after the other, using this same format.
21: array
~~~~~~~~~
+----------+-------+-----------+---------------------------------------------------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+=====================================================================+
| 4 | 4 | Integer | val&0x7FFFFFFF = elements, val&0x80000000 = shared (bool) |
+----------+-------+-----------+---------------------------------------------------------------------+
Then what follows is, for amount of "elements", values one after the
other, using this same format.
22: :ref:`class_ByteArray`
~~~~~~~~~~~~~~
+---------------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+===============+=======+===========+========================+
| 4 | 4 | Integer | Array Length (Bytes) |
+---------------+-------+-----------+------------------------+
| 8..8+length | 1 | Byte | Byte (0..255) |
+---------------+-------+-----------+------------------------+
The array data is padded to 4 bytes.
23: :ref:`class_IntArray`
~~~~~~~~~~~~~
+------------------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==================+=======+===========+===========================+
| 4 | 4 | Integer | Array Length (Integers) |
+------------------+-------+-----------+---------------------------+
| 8..8+length\*4 | 4 | Integer | 32 Bits Signed Integer |
+------------------+-------+-----------+---------------------------+
24: :ref:`class_FloatArray`
~~~~~~~~~~~~~~~
+------------------+-------+-----------+---------------------------+
| Offset | Len | Type | Description |
+==================+=======+===========+===========================+
| 4 | 4 |Integer | Array Length (Floats) |
+------------------+-------+-----------+---------------------------+
| 8..8+length\*4 | 4 |Integer | 32 Bits IEE 754 Float |
+------------------+-------+-----------+---------------------------+
25: :ref:`class_StringArray`
~~~~~~~~~~~~~~~~
+----------+-------+-----------+--------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+==========================+
| 4 | 4 | Integer | Array Length (Strings) |
+----------+-------+-----------+--------------------------+
For each String:
+----------+-------+-----------+------------------------+
| Offset | Len | Type | Description |
+==========+=======+===========+========================+
| X+0 | 4 | Integer | String Length |
+----------+-------+-----------+------------------------+
| X+4 | X | Bytes | UTF-8 Encoded String |
+----------+-------+-----------+------------------------+
Every string is is padded to 4 bytes.
26: :ref:`class_Vector2Array`
~~~~~~~~~~~~~~~~~
+-------------------+-------+-----------+----------------+
| Offset | Len | Type | Description |
+===================+=======+===========+================+
| 4 | 4 | Integer | Array Length |
+-------------------+-------+-----------+----------------+
| 8..8+length\*8 | 4 | Float | X Coordinate |
+-------------------+-------+-----------+----------------+
| 8..12+length\*8 | 4 | Float | Y Coordinate |
+-------------------+-------+-----------+----------------+
27: :ref:`class_Vector3Array`
~~~~~~~~~~~~~~~~~
+--------------------+-------+-----------+----------------+
| Offset | Len | Type | Description |
+====================+=======+===========+================+
| 4 | 4 | Integer | Array Length |
+--------------------+-------+-----------+----------------+
| 8..8+length\*12 | 4 | Float | X Coordinate |
+--------------------+-------+-----------+----------------+
| 8..12+length\*12 | 4 | Float | Y Coordinate |
+--------------------+-------+-----------+----------------+
| 8..16+length\*12 | 4 | Float | Z Coordinate |
+--------------------+-------+-----------+----------------+
28: :ref:`class_ColorArray`
~~~~~~~~~~~~~~~
+--------------------+-------+-----------+----------------+
| Offset | Len | Type | Description |
+====================+=======+===========+================+
| 4 | 4 | Integer | Array Length |
+--------------------+-------+-----------+----------------+
| 8..8+length\*16 | 4 | Float | Red (0..1) |
+--------------------+-------+-----------+----------------+
| 8..12+length\*16 | 4 | Float | Green (0..1) |
+--------------------+-------+-----------+----------------+
| 8..16+length\*16 | 4 | Float | Blue (0..1) |
+--------------------+-------+-----------+----------------+
| 8..20+length\*16 | 4 | Float | Alpha (0..1) |
+--------------------+-------+-----------+----------------+

View File

@@ -0,0 +1,39 @@
.. _doc_data_paths:
Data paths
==========
Path separators
---------------
For the sake of supporting as many platforms as possible, Godot only
accepts unix style path separators (``/``). These work everywhere,
including Windows.
A path like: ``C:\Projects`` will become ``C:/Projects``.
Resource path
-------------
As mentioned before. Godot considers that a project exists at any
given folder that contains an "engine.cfg" text file, even if such
file is empty.
Accessing project files can be done by opening any path with ``res://``
as a base. For example, a texture located in the root of the project
folder may be opened from the following path: ``res://sometexture.png``.
Userdata path (persistent data)
-------------------------------
While the project is running, it is a very common scenario that the
resource path will be read-only, due to it being inside a package,
self contained executable, or system wide install location.
Storing persistent files in such scenarios should be done by using the
``user://`` prefix, for example: ``user://gamesave.txt``.
In some devices (for example, mobile ad consoles) this path is unique
for the app. Under desktop operating systems, the engine uses the
typical ~/.Name (check the project name under the settings) in OSX and
Linux, and APPDATA/Name for Windows.

View File

@@ -0,0 +1,59 @@
.. _doc_encrypting_save_games:
Encrypting save games
=====================
Why?
----
Because the world today is not the world of yesterday. A capitalist
oligarchy runs the world and forces us to consume in order to keep the
gears of this rotten society on track. As such, the biggest market for
video game consumption today is the mobile one. It is a market of poor
souls forced to compulsively consume digital content in order to forget
the misery of their every day life, commute, or just any other brief
free moment they have that they are not using to produce goods or
services for the ruling class. These individuals need to keep focusing
on their video games (because not doing so will produce them a
tremendous existential angst), so they go as far as spending money on
them to extend their experience, and their preferred way of doing so is
through in-app purchases and virtual currency.
But, imagine if someone was to find a way to edit the saved games and
assign the items and currency without effort? This would be terrible,
because it would help players consume the content much faster, and as
such run out of it sooner than expected. If this happens they will have
nothing that avoids them to think, and the tremendous agony of realizing
their own irrelevance would again take over their life.
No, we definitely do not want this to happen, so let's see how to
encrypt savegames and protect the world order.
How?
----
The class :ref:`File <class_File>` is simple to use, just open a
location and read/write data (integers, strings and variants). To create
an encrypted file, a passphrase must be provided, like this:
::
var f = File.new()
var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, "mypass")
f.store_var(game_state)
f.close()
This will make the file unreadable to users, but will still not avoid
them to share savefiles. To solve this, using the device unique id or
some unique user identifier is needed, for example:
::
var f = File.new()
var err = f.open_encrypted_with_pass("user://savedata.bin", File.WRITE, OS.get_unique_ID())
f.store_var(game_state)
f.close()
Note that ``OS.get_unique_ID()`` only works on iOS and Android.
This is all! Thanks for your cooperation, citizen.

View File

@@ -0,0 +1,37 @@
.. _doc_handling_quit_requests:
Handling quit requests
======================
Quitting
--------
Most platforms have the option to request the application to quit. On
desktops, this is usually done with the "x" icon on the window titlebar.
On Android, the back button is used to quit when on the main screen (and
to go back otherwise).
Handling the notification
-------------------------
The :ref:`MainLoop <class_MainLoop>`
has a special notification that is sent to all nodes when quit is
requested: MainLoop.NOTIFICATION_WM_QUIT.
Handling it is done as follows (on any node):
::
func _notification(what):
if (what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST):
get_tree().quit() # default behavior
When developing mobile apps, quitting is not desired unless the user is
on the main screen, so the behavior can be changed.
It is important to note that by default, Godot apps have the built-in
behavior to quit when quit is requested, this can be changed:
::
get_tree().set_auto_accept_quit(false)

View File

@@ -0,0 +1,107 @@
.. _doc_internationalizing_games:
Internationalizing games
========================
Introduction
------------
Sería excelente que el mundo hablara solo un idioma. Unfortunately for
us developers, that is not the case. While not generally a big
requirement when developing indie or niche games, it is also very common
that games going into a more massive market require localization.
Godot offers many tools to make this process more straightforward, so
this tutorial is more like a collection of tips and tricks.
Localization is usually done by specific studios hired for the job and,
despite the huge amount of software and file formats available for this,
the most common way to do localization to this day is still with
spreadsheets. The process of creating the spreadsheets and importing
them is already covered in the :ref:`doc_importing_translations` tutorial, so this
one could be seen more like a follow up to that one.
Configuring the imported translation
------------------------------------
The translations can get updated and re-imported when they change, but
they still have to be added to the project. This is done in Scene
> Project Settings > Localization:
.. image:: /img/localization_dialog.png
This dialog allows to add or remove translations project-wide.
Localizing resources
--------------------
It is also possible to instruct Godot to open alternative versions of
assets (resources) depending on the current language. For this the
"Remaps" tab exists:
.. image:: /img/localization_remaps.png
Select the resource to be remapped, and the alternatives for each
locale.
Converting keys to text
-----------------------
Some controls such as :ref:`Button <class_Button>`, :ref:`Label <class_Label>`,
etc. will automatically fetch a translation each time they are set a key
instead of a text. For example, if a label is assigned
"MAIN_SCREEN_GREETING1" and a key to different languages exists in the
translations, this will be automatically converted. This process is done
upon load though, so if the project in question has a dialog that allows
changing the language in the settings, the scenes (or at least the
settings scene) will have to be re-loaded for new text to have effect.
For code, the :ref:`Object.tr() <class_Object_tr>`
function can be used. This will just look-up the text into the
translations and convert it if found:
::
level.set_text(tr("LEVEL_5_NAME"))
status.set_text(tr("GAME_STATUS_" + str(status_index)))
Making controls resizeable
--------------------------
The same text in different languages can vary greatly in length. For
this, make sure to read the tutorial on :ref:`doc_size_and_anchors`, as having
dynamically adjusted control sizes may help.
:ref:`Container <class_Container>` can be very useful, as well as the multiple options in
:ref:`Label <class_Label>` for text wrapping.
TranslationServer
-----------------
Godot has a server for handling the low level translation management
called the :ref:`TranslationServer <class_TranslationServer>`.
Translations can be added or removed during run-time, and the current
language be changed too.
Command line
------------
Language can be tested when running Godot from command line. For
example, to test a game in french, the following arguments can be
supplied:
::
c:\MyGame> godot -lang fr
Translating the project name
----------------------------
The project name becomes the app name when exporting to different
operating systems and platforms. To specify the project name in more
than one language, create a new setting application/name in the project
settings dialog and append the locale identifier to it. For example:
.. image:: /img/localized_name.png
As always, If you don't know the code of a language or zone, :ref:`check the
list <doc_locales>`.

View File

@@ -0,0 +1,317 @@
.. _doc_locales:
Locales
=======
This is the list of supported locales and variants in the engine. It's
based on the Unix standard locale strings:
+--------------+------------------------------------+
| Locale | Language and Variant |
+==============+====================================+
| ar | Arabic |
+--------------+------------------------------------+
| ar_AE | Arabic (United Arab Emirates) |
+--------------+------------------------------------+
| ar_BH | Arabic (Bahrain) |
+--------------+------------------------------------+
| ar_DZ | Arabic (Algeria) |
+--------------+------------------------------------+
| ar_EG | Arabic (Egypt) |
+--------------+------------------------------------+
| ar_IQ | Arabic (Iraq) |
+--------------+------------------------------------+
| ar_JO | Arabic (Jordan) |
+--------------+------------------------------------+
| ar_KW | Arabic (Kuwait) |
+--------------+------------------------------------+
| ar_LB | Arabic (Lebanon) |
+--------------+------------------------------------+
| ar_LY | Arabic (Libya) |
+--------------+------------------------------------+
| ar_MA | Arabic (Morocco) |
+--------------+------------------------------------+
| ar_OM | Arabic (Oman) |
+--------------+------------------------------------+
| ar_QA | Arabic (Qatar) |
+--------------+------------------------------------+
| ar_SA | Arabic (Saudi Arabia) |
+--------------+------------------------------------+
| ar_SD | Arabic (Sudan) |
+--------------+------------------------------------+
| ar_SY | Arabic (Syria) |
+--------------+------------------------------------+
| ar_TN | Arabic (Tunisia) |
+--------------+------------------------------------+
| ar_YE | Arabic (Yemen) |
+--------------+------------------------------------+
| be | Belarusian |
+--------------+------------------------------------+
| be_BY | Belarusian (Belarus) |
+--------------+------------------------------------+
| bg | Bulgarian |
+--------------+------------------------------------+
| bg_BG | Bulgarian (Bulgaria) |
+--------------+------------------------------------+
| ca | Catalan |
+--------------+------------------------------------+
| ca_ES | Catalan (Spain) |
+--------------+------------------------------------+
| cs | Czech |
+--------------+------------------------------------+
| cs_CZ | Czech (Czech Republic) |
+--------------+------------------------------------+
| da | Danish |
+--------------+------------------------------------+
| da_DK | Danish (Denmark) |
+--------------+------------------------------------+
| de | German |
+--------------+------------------------------------+
| de_AT | German (Austria) |
+--------------+------------------------------------+
| de_CH | German (Switzerland) |
+--------------+------------------------------------+
| de_DE | German (Germany) |
+--------------+------------------------------------+
| de_LU | German (Luxembourg) |
+--------------+------------------------------------+
| el | Greek |
+--------------+------------------------------------+
| el_CY | Greek (Cyprus) |
+--------------+------------------------------------+
| el_GR | Greek (Greece) |
+--------------+------------------------------------+
| en | English |
+--------------+------------------------------------+
| en_AU | English (Australia) |
+--------------+------------------------------------+
| en_CA | English (Canada) |
+--------------+------------------------------------+
| en_GB | English (United Kingdom) |
+--------------+------------------------------------+
| en_IE | English (Ireland) |
+--------------+------------------------------------+
| en_IN | English (India) |
+--------------+------------------------------------+
| en_MT | English (Malta) |
+--------------+------------------------------------+
| en_NZ | English (New Zealand) |
+--------------+------------------------------------+
| en_PH | English (Philippines) |
+--------------+------------------------------------+
| en_SG | English (Singapore) |
+--------------+------------------------------------+
| en_US | English (United States) |
+--------------+------------------------------------+
| en_ZA | English (South Africa) |
+--------------+------------------------------------+
| es | Spanish |
+--------------+------------------------------------+
| es_AR | Spanish (Argentina) |
+--------------+------------------------------------+
| es_BO | Spanish (Bolivia) |
+--------------+------------------------------------+
| es_CL | Spanish (Chile) |
+--------------+------------------------------------+
| es_CO | Spanish (Colombia) |
+--------------+------------------------------------+
| es_CR | Spanish (Costa Rica) |
+--------------+------------------------------------+
| es_DO | Spanish (Dominican Republic) |
+--------------+------------------------------------+
| es_EC | Spanish (Ecuador) |
+--------------+------------------------------------+
| es_ES | Spanish (Spain) |
+--------------+------------------------------------+
| es_GT | Spanish (Guatemala) |
+--------------+------------------------------------+
| es_HN | Spanish (Honduras) |
+--------------+------------------------------------+
| es_MX | Spanish (Mexico) |
+--------------+------------------------------------+
| es_NI | Spanish (Nicaragua) |
+--------------+------------------------------------+
| es_PA | Spanish (Panama) |
+--------------+------------------------------------+
| es_PE | Spanish (Peru) |
+--------------+------------------------------------+
| es_PR | Spanish (Puerto Rico) |
+--------------+------------------------------------+
| es_PY | Spanish (Paraguay) |
+--------------+------------------------------------+
| es_SV | Spanish (El Salvador) |
+--------------+------------------------------------+
| es_US | Spanish (United States) |
+--------------+------------------------------------+
| es_UY | Spanish (Uruguay) |
+--------------+------------------------------------+
| es_VE | Spanish (Venezuela) |
+--------------+------------------------------------+
| et | Estonian |
+--------------+------------------------------------+
| et_EE | Estonian (Estonia) |
+--------------+------------------------------------+
| fi | Finnish |
+--------------+------------------------------------+
| fi_FI | Finnish (Finland) |
+--------------+------------------------------------+
| fr | French |
+--------------+------------------------------------+
| fr_BE | French (Belgium) |
+--------------+------------------------------------+
| fr_CA | French (Canada) |
+--------------+------------------------------------+
| fr_CH | French (Switzerland) |
+--------------+------------------------------------+
| fr_FR | French (France) |
+--------------+------------------------------------+
| fr_LU | French (Luxembourg) |
+--------------+------------------------------------+
| ga | Irish |
+--------------+------------------------------------+
| ga_IE | Irish (Ireland) |
+--------------+------------------------------------+
| hi | Hindi (India) |
+--------------+------------------------------------+
| hi_IN | Hindi (India) |
+--------------+------------------------------------+
| hr | Croatian |
+--------------+------------------------------------+
| hr_HR | Croatian (Croatia) |
+--------------+------------------------------------+
| hu | Hungarian |
+--------------+------------------------------------+
| hu_HU | Hungarian (Hungary) |
+--------------+------------------------------------+
| in | Indonesian |
+--------------+------------------------------------+
| in_ID | Indonesian (Indonesia) |
+--------------+------------------------------------+
| is | Icelandic |
+--------------+------------------------------------+
| is_IS | Icelandic (Iceland) |
+--------------+------------------------------------+
| it | Italian |
+--------------+------------------------------------+
| it_CH | Italian (Switzerland) |
+--------------+------------------------------------+
| it_IT | Italian (Italy) |
+--------------+------------------------------------+
| iw | Hebrew |
+--------------+------------------------------------+
| iw_IL | Hebrew (Israel) |
+--------------+------------------------------------+
| ja | Japanese |
+--------------+------------------------------------+
| ja_JP | Japanese (Japan) |
+--------------+------------------------------------+
| ja_JP_JP | Japanese (Japan,JP) |
+--------------+------------------------------------+
| ko | Korean |
+--------------+------------------------------------+
| ko_KR | Korean (South Korea) |
+--------------+------------------------------------+
| lt | Lithuanian |
+--------------+------------------------------------+
| lt_LT | Lithuanian (Lithuania) |
+--------------+------------------------------------+
| lv | Latvian |
+--------------+------------------------------------+
| lv_LV | Latvian (Latvia) |
+--------------+------------------------------------+
| mk | Macedonian |
+--------------+------------------------------------+
| mk_MK | Macedonian (Macedonia) |
+--------------+------------------------------------+
| ms | Malay |
+--------------+------------------------------------+
| ms_MY | Malay (Malaysia) |
+--------------+------------------------------------+
| mt | Maltese |
+--------------+------------------------------------+
| mt_MT | Maltese (Malta) |
+--------------+------------------------------------+
| nl | Dutch |
+--------------+------------------------------------+
| nl_BE | Dutch (Belgium) |
+--------------+------------------------------------+
| nl_NL | Dutch (Netherlands) |
+--------------+------------------------------------+
| no | Norwegian |
+--------------+------------------------------------+
| no_NO | Norwegian (Norway) |
+--------------+------------------------------------+
| no_NO_NY | Norwegian (Norway,Nynorsk) |
+--------------+------------------------------------+
| pl | Polish |
+--------------+------------------------------------+
| pl_PL | Polish (Poland) |
+--------------+------------------------------------+
| pt | Portuguese |
+--------------+------------------------------------+
| pt_BR | Portuguese (Brazil) |
+--------------+------------------------------------+
| pt_PT | Portuguese (Portugal) |
+--------------+------------------------------------+
| ro | Romanian |
+--------------+------------------------------------+
| ro_RO | Romanian (Romania) |
+--------------+------------------------------------+
| ru | Russian |
+--------------+------------------------------------+
| ru_RU | Russian (Russia) |
+--------------+------------------------------------+
| sk | Slovak |
+--------------+------------------------------------+
| sk_SK | Slovak (Slovakia) |
+--------------+------------------------------------+
| sl | Slovenian |
+--------------+------------------------------------+
| sl_SI | Slovenian (Slovenia) |
+--------------+------------------------------------+
| sq | Albanian |
+--------------+------------------------------------+
| sq_AL | Albanian (Albania) |
+--------------+------------------------------------+
| sr | Serbian |
+--------------+------------------------------------+
| sr_BA | Serbian (Bosnia and Herzegovina) |
+--------------+------------------------------------+
| sr_CS | Serbian (Serbia and Montenegro) |
+--------------+------------------------------------+
| sr_ME | Serbian (Montenegro) |
+--------------+------------------------------------+
| sr_RS | Serbian (Serbia) |
+--------------+------------------------------------+
| sv | Swedish |
+--------------+------------------------------------+
| sv_SE | Swedish (Sweden) |
+--------------+------------------------------------+
| th | Thai |
+--------------+------------------------------------+
| th_TH | Thai (Thailand) |
+--------------+------------------------------------+
| th_TH_TH | Thai (Thailand,TH) |
+--------------+------------------------------------+
| tr | Turkish |
+--------------+------------------------------------+
| tr_TR | Turkish (Turkey) |
+--------------+------------------------------------+
| uk | Ukrainian |
+--------------+------------------------------------+
| uk_UA | Ukrainian (Ukraine) |
+--------------+------------------------------------+
| vi | Vietnamese |
+--------------+------------------------------------+
| vi_VN | Vietnamese (Vietnam) |
+--------------+------------------------------------+
| zh | Chinese |
+--------------+------------------------------------+
| zh_CN | Chinese (China) |
+--------------+------------------------------------+
| zh_HK | Chinese (Hong Kong) |
+--------------+------------------------------------+
| zh_SG | Chinese (Singapore) |
+--------------+------------------------------------+
| zh_TW | Chinese (Taiwan) |
+--------------+------------------------------------+

View File

@@ -0,0 +1,96 @@
.. _doc_pausing_games:
Pausing games
=============
Pause?
------
In most games it is desirable to, at some point, interrupt the
game to do something else, such as taking a break or changing options.
However this is not as simple as it seems. The game might be stopped,
but it might be desirable that some menus and animations continue
working.
Implementing a fine-grained control for what can be paused (and what can
not) is a lot of work, so a simple framework for pausing is provided in
Godot.
How pausing works
-----------------
To set pause mode, the pause state must be set. This is done by calling
:ref:`SceneTree.set_pause() <class_SceneTree_set_pause>`
with a "true" argument:
::
get_tree().set_pause(true)
Doing so will have the following behavior:
- 2D and 3D physics will be stopped.
- _process and _fixed_process will not be called anymore in nodes.
- _input and _input_event will not be called anymore either.
This effectively stops the whole game. Calling this function from a
script, by default, will result in an unrecoverable state (nothing will
work anymore!).
White-listing nodes
-------------------
Before enabling pause, make sure that nodes that must keep working
during pause are white-listed. This is done by editing the "Pause Mode"
property in a node:
.. image:: /img/pausemode.png
By default all nodes have this property in the "Inherit" state. This
means, that they will only process (or not) depending on what this same
property is set on the parent node. If the parent is set to "Inherit" ,
then the grandparent will be checked and so on. Ultimately, if a state
can't be found in any of the grandparents, the pause state in SceneTree
is used. This means that, by default, when the game is paused every node
will be paused.
So the three possible states for a node are:
- **Inherit**: Process depending on the state of the parent,
grandparent, etc. The first parent that has a non-Inherit state.
- **Stop**: Stop the node no matter what (and children in Inherit
mode). When paused this node will not process.
- **Process**: Process the node no matter what (and children in Inherit
mode). Paused or not this node will process.
Example
-------
An example of this is creating a popup or panel with controls inside,
and set its pause mode to "Process" then just hide it:
.. image:: /img/pause_popup.png
Just by setting the root of the pause popup to "Process", all children
and grandchildren will inherit that state. This way, this branch of the
scene tree will continue working when paused.
Finally, make it so when a pause button is pressed (any button will do),
enable the pause and show the pause screen.
::
func _on_pause_button_pressed():
get_tree().set_pause(true)
get_node("pause_popup").show()
To remove the pause, just do the opposite when the pause screen is
closed:
::
func _on_pause_popup_close_pressed():
get_node("pause_popup").hide()
get_tree().set_pause(false)
And that should be all!

View File

@@ -0,0 +1,155 @@
.. _doc_saving_games:
Saving games
============
Introduction
------------
Save games can be complicated. It can be desired to store more
information than the current level or number of stars earned on a level.
More advanced save games may need to store additional information about
an arbitrary number of objects. This will allow the save function to
scale as the game grows more complex.
Identify persistent objects
---------------------------
First we should identify what objects we want to keep between game
sessions and what information we want to keep from those objects. For
this tutorial, we will use groups to mark and handle objects to be saved
but other methods are certainly possible.
We will start by adding objects we wish to save to the "Persist" group.
As in the :ref:`doc_scripting_continued` tutorial, we can do this through
the GUI or through script. Let's add the relevant nodes using the GUI:
.. image:: /img/groups.png
Once this is done when we need to save the game we can get all objects
to save them and then tell them all to save with this script:
::
var savenodes = get_tree().get_nodes_in_group("Persist")
for i in savenodes:
# Now we can call our save function on each node.
Serializing
-----------
The next step is to serialize the data. This makes it much easier to
read and store to disk. In this case, we're assuming each member of
group Persist is an instanced node and thus has a path. GDScript
has helper functions for this, such as :ref:`Dictionary.to_json()
<class_Dictionary_to_json>` and :ref:`Dictionary.parse_json()
<class_Dictionary_parse_json>`, so we will use a dictionary. Our node needs to
contain a save function that returns this data. The save function will look
like this:
::
func save():
var savedict = {
filename=get_filename(),
parent=get_parent().get_path(),
posx=get_pos().x, #Vector2 is not supported by json
posy=get_pos().y,
attack=attack,
defense=defense,
currenthealth=currenthealth,
maxhealth=maxhealth,
damage=damage,
regen=regen,
experience=experience,
TNL=TNL,
level=level,
AttackGrowth=AttackGrowth,
DefenseGrowth=DefenseGrowth,
HealthGrowth=HealthGrowth,
isalive=isalive,
last_attack=last_attack
}
return savedict
This gives us a dictionary with the style
``{ "variable_name":that_variables_value }`` which will be useful when
loading.
Saving and reading data
-----------------------
As covered in the :ref:`doc_filesystem` tutorial, we'll need to open a file
and write to it and then later read from it. Now that we have a way to
call our groups and get their relevant data, let's use to_json() to
convert it into an easily stored string and store them in a file. Doing
it this way ensures that each line is its own object so we have an easy
way to pull the data out of the file as well.
::
# Note: This can be called from anywhere inside the tree. This function is path independent.
# Go through everything in the persist category and ask them to return a dict of relevant variables
func save_game():
var savegame = File.new()
savegame.open("user://savegame.save", File.WRITE)
var savenodes = get_tree().get_nodes_in_group("Persist")
for i in savenodes:
var nodedata = i.save()
savegame.store_line(nodedata.to_json())
savegame.close()
Game saved! Loading is fairly simple as well. For that we'll read each
line, use parse_json() to read it back to a dict, and then iterate over
the dict to read our values. But we'll need to first create the object
and we can use the filename and parent values to achieve that. Here is our
load function:
::
# Note: This can be called from anywhere inside the tree. This function is path independent.
func load_game():
var savegame = File.new()
if !savegame.file_exists("user://savegame.save"):
return #Error! We don't have a save to load
# We need to revert the game state so we're not cloning objects during loading. This will vary wildly depending on the needs of a project, so take care with this step.
# For our example, we will accomplish this by deleting savable objects.
var savenodes = get_tree().get_nodes_in_group("Persist")
for i in savenodes:
i.queue_free()
# Load the file line by line and process that dictionary to restore the object it represents
var currentline = {} # dict.parse_json() requires a declared dict.
savegame.open("user://savegame.save", File.READ)
while (!savegame.eof_reached()):
currentline.parse_json(savegame.get_line())
# First we need to create the object and add it to the tree and set its position.
var newobject = load(currentline["filename"]).instance()
get_node(currentline["parent"]).add_child(newobject)
newobject.set_pos(Vector2(currentline["posx"],currentline["posy"]))
# Now we set the remaining variables.
for i in currentline.keys():
if (i == "filename" or i == "parent" or i == "posx" or i == "posy"):
continue
newobject.set(i, currentline[i])
savegame.close()
And now we can save and load an arbitrary number of objects laid out
almost anywhere across the scene tree! Each object can store different
data depending on what it needs to save.
Some notes
----------
We may have glossed over a step, but setting the game state to one fit
to start loading data can be very complicated. This step will need to be
heavily customized based on the needs of an individual project.
This implementation assumes no Persist objects are children of other
Persist objects. Doing so would create invalid paths. If this is one of
the needs of a project this needs to be considered. Saving objects in
stages (parent objects first) so they are available when child objects
are loaded will make sure they're available for the add_child() call.
There will also need to be some way to link children to parents as the
nodepath will likely be invalid.

View File

@@ -0,0 +1,100 @@
.. _doc_http_client_class:
HTTP client class
=================
Here's an example of using the :ref:`HTTPClient <class_HTTPClient>`
class. It's just a script, so it can be run by executing:
::
c:\godot> godot -s http_test.gd
It will connect and fetch a website.
::
extends SceneTree
# HTTPClient demo
# This simple class can do HTTP requests, it will not block but it needs to be polled
func _init():
var err=0
var http = HTTPClient.new() # Create the Client
var err = http.connect("www.php.net",80) # Connect to host/port
assert(err==OK) # Make sure connection was OK
# Wait until resolved and connected
while( http.get_status()==HTTPClient.STATUS_CONNECTING or http.get_status()==HTTPClient.STATUS_RESOLVING):
http.poll()
print("Connecting..")
OS.delay_msec(500)
assert( http.get_status() == HTTPClient.STATUS_CONNECTED ) # Could not connect
# Some headers
var headers=[
"User-Agent: Pirulo/1.0 (Godot)",
"Accept: */*"
]
err = http.request(HTTPClient.METHOD_GET,"/ChangeLog-5.php",headers) # Request a page from the site (this one was chunked..)
assert( err == OK ) # Make sure all is OK
while (http.get_status() == HTTPClient.STATUS_REQUESTING):
# Keep polling until the request is going on
http.poll()
print("Requesting..")
OS.delay_msec(500)
assert( http.get_status() == HTTPClient.STATUS_BODY or http.get_status() == HTTPClient.STATUS_CONNECTED ) # Make sure request finished well.
print("response? ",http.has_response()) # Site might not have a response.
if (http.has_response()):
# If there is a response..
var headers = http.get_response_headers_as_dictionary() # Get response headers
print("code: ",http.get_response_code()) # Show response code
print("**headers:\\n",headers) # Show headers
# Getting the HTTP Body
if (http.is_response_chunked()):
# Does it use chunks?
print("Response is Chunked!")
else:
# Or just plain Content-Length
var bl = http.get_response_body_length()
print("Response Length: ",bl)
# This method works for both anyway
var rb = RawArray() # Array that will hold the data
while(http.get_status()==HTTPClient.STATUS_BODY):
# While there is body left to be read
http.poll()
var chunk = http.read_response_body_chunk() # Get a chunk
if (chunk.size()==0):
# Got nothing, wait for buffers to fill a bit
OS.delay_usec(1000)
else:
rb = rb + chunk # Append to read buffer
# Done!
print("bytes got: ",rb.size())
var text = rb.get_string_from_ascii()
print("Text: ",text)
quit()

View File

@@ -0,0 +1,72 @@
.. _doc_ssl_certificates:
SSL certificates
================
Introduction
------------
It is often desired to use SSL connections for communications to avoid
"man in the middle" attacks. Godot has a connection wrapper,
:ref:`StreamPeerSSL <class_StreamPeerSSL>`,
which can take a regular connection and add security around it. The
:ref:`HTTPClient <class_HTTPClient>`
class also supports HTTPS by using this same wrapper.
For SSL to work, certificates need to be provided. A .crt file must be
specified in the project settings:
.. image:: /img/ssl_certs.png
This file should contain any number of public certificates in
http://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail format.
Of course, remember to add .crt as filter so the exporter recognizes
this when exporting your project.
.. image:: /img/add_crt.png
There are two ways to obtain certificates:
Approach 1: self signed cert
----------------------------
The first approach is the simplest, just generate a private and public
key pair, and put the public pair in the .crt file (again, in PEM
format). The private key should go to your server.
OpenSSL has `some
documentation <https://www.openssl.org/docs/HOWTO/keys.txt>`__ about
this. This approach also **does not require domain validation** nor
requires you to spend a considerable amount of money in purchasing
certificates from a CA.
Approach 2: CA cert
-------------------
The second approach consists of using a certificate authority (CA)
such as Verisign, Geotrust, etc. This is a more cumbersome process,
but it's more "official" and ensures your identity is clearly
represented.
Unless you are working with large companies or corporations, or need
to connect to someone else's servers (i.e., connecting to Google or some
other REST API provider via HTTPS) this method is not as useful.
Also, when using a CA issued cert, **you must enable domain
validation**, to ensure the domain you are connecting to is the one
intended, otherwise any website can issue any certificate in the same CA
and it will work.
If you are using Linux, you can use the supplied certs file, generally
located in:
::
/etc/ssl/certs/ca-certificates.crt
This file allows HTTPS connections to virtually any website (i.e.,
Google, Microsoft, etc.).
Or just pick any of the more specific certificates there if you are
connecting to a specific one.

View File

@@ -0,0 +1,249 @@
.. _doc_kinematic_character_2d:
Kinematic Character (2D)
========================
Introduction
~~~~~~~~~~~~
Yes, the name sounds strange. "Kinematic Character". What is that?
The reason is that when physics engines came out, they were called
"Dynamics" engines (because they dealt mainly with collision
responses). Many attempts were made to create a character controller
using the dynamics engines but it wasn't as easy as it seems. Godot
has one of the best implementations of dynamic character controller
you can find (as it can be seen in the 2d/platformer demo), but using
it requieres a considerable level of skill and understanding of
physics engines (or a lot of patience with trial and error).
Some physics engines such as Havok seem to swear by dynamic character
controllers as the best alternative, while others (PhysX) would rather
promote the Kinematic one.
So, what is really the difference?:
- A **dynamic character controller** uses a rigid body with infinite
inertial tensor. Basically, it's a rigid body that can't rotate.
Physics engines always let objects collide, then solve their
collisions all together. This makes dynamic character controllers
able to interact with other physics objects seamlessly (as seen in
the platformer demo), however these interactions are not always
predictable. Collisions also can take more than one frame to be
solved, so a few collisions may seem to displace a tiny bit. Those
problems can be fixed, but require a certain amount of skill.
- A **kinematic character controller** is assumed to always begin in a
non-colliding state, and will always move to a non colliding state.
If it starts in a colliding state, it will try to free itself (like
rigid bodies do) but this is the exception, not the rule. This makes
their control and motion a lot more predictable and easier to
program. However, as a downside, they can't directly interact with
other physics objects (unless done by hand in code).
This short tutorial will focus on the kinematic character controller.
Basically, the oldschool way of handling collisions (which is not
necessarily simpler under the hood, but well hidden and presented as a
nice and simple API).
Fixed process
~~~~~~~~~~~~~
To manage the logic of a kinematic body or character, it is always
advised to use fixed process, which is called the same amount of times
per second, always. This makes physics and motion calculation work in a
more predictable way than using regular process, which might have spikes
or lose precision if the frame rate is too high or too low.
::
extends KinematicBody2D
func _fixed_process(delta):
pass
func _ready():
set_fixed_process(true)
Scene setup
~~~~~~~~~~~
To have something to test, here's the scene (from the tilemap tutorial):
:download:`kbscene.zip </files/kbscene.zip>`. We'll be creating a new scene
for the character. Use the robot sprite and create a scene like this:
.. image:: /img/kbscene.png
Let's add a circular collision shape to the collision body, create a new
CircleShape2D in the shape property of CollisionShape2D. Set the radius
to 30:
.. image:: /img/kbradius.png
**Note: As mentioned before in the physics tutorial, the physics engine
can't handle scale on most types of shapes (only collision polygons,
planes and segments work), so always change the parameters (such as
radius) of the shape instead of scaling it. The same is also true for
the kinematic/rigid/static bodies themselves, as their scale affect the
shape scale.**
Now create a script for the character, the one used as an example
above should work as a base.
Finally, instance that character scene in the tilemap, and make the
map scene the main one, so it runs when pressing play.
.. image:: /img/kbinstance.png
Moving the Kinematic character
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Go back to the character scene, and open the script, the magic begins
now! Kinematic body will do nothing by default, but it has a really
useful function called :ref:`KinematicBody2D.move() <class_KinematicBody2D_move>`.
This function takes a :ref:`Vector2 <class_Vector2>` as
an argument, and tries to apply that motion to the kinematic body. If a
collision happens, it stops right at the moment of the collision.
So, let's move our sprite downwards until it hits the floor:
::
extends KinematicBody2D
func _fixed_process(delta):
move( Vector2(0,1) ) #move down 1 pixel per physics frame
func _ready():
set_fixed_process(true)
The result is that the character will move, but stop right when
hitting the floor. Pretty cool, huh?
The next step will be adding gravity to the mix, this way it behaves a
little more like an actual game character:
::
extends KinematicBody2D
const GRAVITY = 200.0
var velocity = Vector2()
func _fixed_process(delta):
velocity.y += delta * GRAVITY
var motion = velocity * delta
move( motion )
func _ready():
set_fixed_process(true)
Now the character falls smoothly. Let's make it walk to the sides, left
and right when touching the directional keys. Remember that the values
being used (for speed at least) is pixels/second.
This adds simple walking support by pressing left and right:
::
extends KinematicBody2D
const GRAVITY = 200.0
const WALK_SPEED = 200
var velocity = Vector2()
func _fixed_process(delta):
velocity.y += delta * GRAVITY
if (Input.is_action_pressed("ui_left")):
velocity.x = -WALK_SPEED
elif (Input.is_action_pressed("ui_right")):
velocity.x = WALK_SPEED
else:
velocity.x = 0
var motion = velocity * delta
move(motion)
func _ready():
set_fixed_process(true)
And give it a try.
Problem?
~~~~~~~~
And... it doesn't work very well. If you go to the left against a wall,
it gets stuck unless you release the arrow key. Once it is on the floor,
it also gets stuck and it won't walk. What is going on??
The answer is, what it seems like it should be simple, it isn't that
simple in reality. If the motion can't be completed, the character will
stop moving. It's as simple as that. This diagram should illustrate
better what is going on:
.. image:: /img/motion_diagram.png
Basically, the desired motion vector will never complete because it hits
the floor and the wall too early in the motion trajectory and that makes
it stop there. Remember that even though the character is on the floor,
the gravity is always turning the motion vector downwards.
Solution!
~~~~~~~~~
The solution? This situation is solved by "sliding" by the collision
normal. KinematicBody2D provides two useful functions:
- :ref:`KinematicBody2D.is_colliding() <class_KinematicBody2D_is_colliding>`
- :ref:`KinematicBody2D.get_collision_normal() <class_KinematicBody2D_get_collision_normal>`
So what we want to do is this:
.. image:: /img/motion_reflect.png
When colliding, the function ``move()`` returns the "remainder" of the
motion vector. That means, if the motion vector is 40 pixels, but
collision happened at 10 pixels, the same vector but 30 pixels long is
returned.
The correct way to solve the motion is, then, to slide by the normal
this way:
::
func _fixed_process(delta):
velocity.y += delta * GRAVITY
if (Input.is_action_pressed("ui_left")):
velocity.x = - WALK_SPEED
elif (Input.is_action_pressed("ui_right")):
velocity.x = WALK_SPEED
else:
velocity.x = 0
var motion = velocity * delta
motion = move(motion)
if (is_colliding()):
var n = get_collision_normal()
motion = n.slide(motion)
velocity = n.slide(velocity)
move(motion)
func _ready():
set_fixed_process(true)
Note that not only the motion has been modified but also the velocity.
This makes sense as it helps keep the new direction too.
The normal can also be used to detect that the character is on floor, by
checking the angle. If the normal points up (or at least, within a
certain threshold), the character can be determined to be there.
A more complete demo can be found in the demo zip distributed with the
engine, or in the
https://github.com/godotengine/godot-demo-projects/tree/master/2d/kinematic_char.

View File

@@ -0,0 +1,441 @@
.. _doc_physics_introduction:
Physics introduction
====================
Our world is made of tangible matter. In our world, a piano can't go
through a wall when going into a house. It needs to use the door. Video
games are often like the the real world and Pac-Man can't go through the
walls of his maze (although he can teleport from the left to the right
side of the screen and back).
Anyway, moving sprites around is nice but one day they have to collide
properly, so let's get to the point.
Shapes
------
The base collidable object in Godot's 2D world is a
:ref:`Shape2D <class_Shape2D>`.
There are many types of shapes, all of them inherit this base class:
- :ref:`CircleShape2D <class_CircleShape2D>`
- :ref:`RectangleShape2D <class_RectangleShape2D>`
- :ref:`CapsuleShape2D <class_CapsuleShape2D>`
- :ref:`ConvexPolygonShape2D <class_ConvexPolygonShape2D>`
- :ref:`ConcavePolygonShape2D <class_ConcavePolygonShape2D>`
- etc. (there are others check the class list).
Shapes are of type
:ref:`Resource <class_Resource>`,
but they can be created via code easily. For example:
::
# Create a circle
var c = CircleShape2D.new()
c.set_radius(20)
# Create a box
var b = RectangleShape2D.new()
b.set_extents(Vector2(20,10))
The main use for shapes is checking collision/intersection and getting
resolution information. Shapes are mostly convex, (except the
concavepolygon one, which is just a list of segments to check collision
against). This collision check is done easily with the built-in
functions like:
::
# Check if there is a collision between two shapes, each with a transform
if b.collide(b_xform, a, a_xform):
print("OMG Collision!")
Godot will return correct collision and collision info from the
different calls to the Shape2D api. Collision between all shapes and
transforms can be done this way, or even obtaining contact information,
motion casting, etc.
Transforming shapes
~~~~~~~~~~~~~~~~~~~
As seen before in the collide functions, 2D shapes in Godot can be
transformed by using a regular :ref:`Matrix32 <class_Matrix32>`
transform, meaning the functions can check for collisions while the
shapes are scaled, moved and
rotated. The only limitation to this is that shapes with curved sections
(such as circle and capsule) can only be scaled uniformly. This means
that circle or capsule shapes scaled in the form of an ellipse **will
not work properly**. This is a limitation on the collision algorithm
used (SAT), so make sure that your circle and capsule shapes are always
scaled uniformly!
.. image:: /img/shape_rules.png
When problems begin
-------------------
Even though this sounds good, reality is that collision detection alone
is usually not enough in most scenarios. Many problems start arising as
long as the development of the game is in progress:
Too many combinations!
~~~~~~~~~~~~~~~~~~~~~~
Games have several dozens, hundreds, thousands! of objects that can
collide and be collided. The typical approach is to test everything
against everything in two for loops like this:
::
for i in colliders:
for j in colliders:
if (i.collides(j)):
do_collision_code()
But this scales really bad. Let's imagine there are only 100 objects in
the game. This means that 100\*100=10000 collisions will need to be
tested each frame. This is a lot!
Visual aid
~~~~~~~~~~
Most of the time, creating a shape via code is not enough. We need to
visually place it over a sprite, draw a collision polygon, etc. It is
obvious that we need nodes to create the proper collision shapes in a
scene.
Collision resolution
~~~~~~~~~~~~~~~~~~~~
Imagine we solved the collision issue, we can tell easily and quickly
which shapes overlap. If many of them are dynamic objects that move
around, or move according to newtonian physics, solving a collision of
multiple objects can be really difficult code-wise.
Introducing... Godot's physics engine!
--------------------------------------
To solve all these problems, Godot has a physics and collision engine
that is well integrated into the scene system, yet it allows different
levels and layers of functionality. The built-in physics engine can be
used for:
- Simple Collision Detection: See :ref:`Shape2D <class_Shape2D>`
API.
- Scene Kinematics: Handle shapes, collisions, broadphase, etc as
nodes. See :ref:`Area2D <class_Area2D>`.
- Scene Physics: Rigid bodies and constraints as nodes. See
:ref:`RigidBody2D <class_RigidBody2D>`, and the joint nodes.
Units of measure
~~~~~~~~~~~~~~~~
It is often a problem when integrating a 2D physics engine to a game
that such engines are optimized to work using meters as unit of measure.
Godot uses a built-in custom 2D physics engine that is designed to
function properly in pixels, so all units and default values used for
stabilization are tuned for this, making development more
straightforward.
CollisionObject2D
-----------------
:ref:`CollisionObject2D <class_CollisionObject2D>`
is the (virtual) base node for everything that can be collided in 2D.
Area2D, StaticBody2D, KinematicBody2D and RigidBody2D all inherit from
it. This node contains a list of shapes (Shape2D) and a relative
transform. This means that all collisionable objects in Godot can use
multiple shapes at different transforms (offset/scale/rotation). Just
remember that, as mentioned before, **non-uniform scale will not work
for circle and capsule shapes**.
.. image:: /img/collision_inheritance.png
A CollisionObject2D comes in different flavors: StaticBody2D, RigidBody2D,
KinematicBody2D and Area2D. However, before we dig into them, let's have
a look how to define the shape of a collision object.
There are two special nodes for that.
CollisionShape2D
~~~~~~~~~~~~~~~~
This node is a helper node, which must be created as a direct child of a
CollisionObject2D-derived node: :ref:`Area2D <class_Area2D>`,
:ref:`StaticBody2D <class_StaticBody2D>`, :ref:`KinematicBody2D <class_KinematicBody2D>`,
:ref:`RigidBody2D <class_RigidBody2D>`.
The purpose of a CollisionShape2D instance is to add collision shapes to
its parent class. Multiple children of type CollisionShape2D can be added to a
CollisionObject2D-derived object with the effect that the parent will
simply get more collision shapes. When a CollisionShape2D is edited (or added, moved,
deleted) the list of shapes in the parent node is updated.
At run time, though, this node does not exist and it can't be accessed with
``get_node()``. This is because it is a helper node only for editing the collision shapes.
To access the shapes created at runtime, use the CollisionObject2D API directly.
As an example, here's the scene from the platformer, containing an
Area2D (named 'coin') having two children: a CollisionShape2D (named 'collision')
and a sprite (called 'sprite'):
.. image:: /img/area2dcoin.png
CollisionPolygon2D
~~~~~~~~~~~~~~~~~~
This one is similar to CollisionShape2D, except that instead of
assigning a shape, a polygon can be edited (drawn by the user) to
determine the shape. The polygon can be convex or concave, it doesn't
matter.
Here is another scene involving a CollisionPolygon2D: A StaticBody2D has
been added as a child of a sprite so that the collision object moves together
with the sprite. In turn, the CollisionPolygon is a child of StaticBody2D, meaning it
adds collision shapes to it.
.. image:: /img/spritewithcollision.png
The CollisionPolygon2D will decompose the user-defined polygon into conves shapes
convex shapes (shapes can only be convex, remember?) before adding them to
the CollisionObject2D. The following image shows such a decomposition:
.. image:: /img/decomposed.png
Triggers
~~~~~~~~
A CollisionShape2D or CollisionPolygon2D can be set as a trigger by setting
the boolean flag with the same name. When
used in a RigidBody2D or KinematicBody2D, "trigger" shapes take part
in collision detection but are unaffected by physics (they don't block
movement etc).
Defining a collision shape as a trigger is mostly useful in two situations:
- Collisions for a specific shape shall be disabled.
- An Area2D shall send ``body_enter`` and ``body_exit`` signals when the
trigger shape enters it (useful in several situations).
StaticBody2D
~~~~~~~~~~~~
The simplest node in the physics engine is the :ref:`StaticBody2D <class_StaticBody2D>`.
This node takes part in collision detection. However, it does not move or rotate
after a collision, so physics do not influence them. The node is static.
Other nodes can collide against it and will be influenced accordingly.
The platformer example uses StaticBody2D objects for the floors and walls.
These are the static parts of a level and shall stay right where they
are even if the player jumps onto them.
KinematicBody2D
~~~~~~~~~~~~~~~
Similar to StaticBody2D, objects of type :ref:`KinematicBody2D <class_KinematicBody2D>`
are not affected by physics (although they take part in collision detection, of course).
However, KinematicBody2D are not static but can be moved via code or an animation.
They have two main uses:
- **Simulated Motion**: When these bodies are moved manually, either
from code or from an :ref:`AnimationPlayer <class_AnimationPlayer>`
(with process mode set to fixed!), the physics will automatically
compute an estimate of their linear and angular velocity. This makes
them very useful for moving platforms or other
AnimationPlayer-controlled objects (like a door, a bridge that opens,
etc). As an example, the 2d/platformer demo uses them for moving
platforms.
- **Kinematic Characters**: KinematicBody2D also has an API for moving
objects (the ``move()`` function) while performing collision tests. This
makes them really useful to implement characters that collide against
a world, but that don't require advanced physics. There is a tutorial
about it :ref:`doc_kinematic_character_2d`.
RigidBody2D
~~~~~~~~~~~
This type of body simulates Newtonian physics. It has mass, friction,
bounce, and the (0,0) coordinates simulate the center of mass. When real
physics are needed, :ref:`RigidBody2D <class_RigidBody2D>`
is the node to use. The motion of this body is affected by gravity
and/or other bodies.
Rigid bodies are usually active all the time, but when they end up in
resting position and don't move for a while, they are put to sleep until
something else wakes them up. This saves an enormous amount of CPU.
RigidBody2D nodes update their transform constantly, as it is generated
by the simulation from a position, linear velocity and angular velocity.
As a result, [STRIKEOUT:this node can't be scaled]. Scaling the children
nodes should work fine though.
A RigidBody2D has a ``Mode`` flag to change its behavior (something
which is very common in games). It can behave like a rigid body,
a character (a rigid body without the ability to rotate so that it is
always upright), a kinematic body or a static body. This flag can be
changed dynamically according to the current situation. For example,
an enemy frozen by an ice beam becomes a static body.
The best way to interact with a RigidBody2D is during the force
integration callback by overriding the function
::
func _integrate_forces(state):
[use state to change the object]
The "state" parameter is of type :ref:`Physics2DDirectBodyState <class_Physics2DDirectBodyState>`.
Please do not use the state object outside the callback as it will
result in an error.
During the evaluation of the aforementioned function, the physics engine
synchronizes state with the scene and allows full modification of the
object's parameters. Since physics may run in its own thread, parameter
changes outside that callback will not take place until the next frame.
Contact reporting
-----------------
In general, RigidBody2D will not keep track of the contacts, because
this can require a huge amount of memory if thousands of rigid bodies
are in the scene. To get contacts reported, simply increase the amount
of the "contacts reported" property from zero to a meaningful value
(depending on how many you are expecting to get). The contacts can be
later obtained via the
:ref:`Physics2DDirectBodyState.get_contact_count() <class_Physics2DDirectBodyState_get_contact_count>`
and related functions.
Contact monitoring via signals is also available (signals similar to the
ones in Area2D, described below) via a boolean property.
Area2D
~~~~~~
Areas in Godot physics have three main roles:
1. Override the space parameters for objects entering them (ie.
gravity, gravity direction, gravity type, density, etc).
2. Monitor when rigid or kinematic bodies enter or exit the area.
3. Monitor other areas (this is the simplest way to get overlap test)
The second function is the most common. For it to work, the "monitoring"
property must be enabled (it is by default). There are two types of
signals emitted by this node:
::
# Simple, high level notification
body_enter(body:PhysicsBody2D)
body_exit(body:PhysicsBody2D)
area_enter(area:Area2D)
area_exit(body:Area2D)
# Low level shape-based notification
# Notifies which shape specifically in both the body and area are in contact
body_enter_shape(body_id:int,body:PhysicsBody2D,body_shape_index:int,area_shape_index:idx)
body_exit_shape(body_id:int,body:PhysicsBody2D,body_shape_index:int,area_shape_index:idx)
area_enter_shape(area_id:int,area:Area2D,area_shape_index:int,self_shape_index:idx)
area_exit_shape(area_id:int,area:Area2D,area_shape_index:int,self_shape_index:idx)
By default, areas also receive mouse/touchscreen input, providing a
lower-level way than controls to implement this kind of input in a game.
Bodies support this but it's disabled by default.
In case of overlap, who receives collision information?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Remember that not every combination of two bodies can "report" contacts.
Static bodies are passive and will not report contacts when hit.
Kinematic Bodies will report contacts but only against Rigid/Character
bodies. Area2D will report overlap (not detailed contacts) with bodies
and with other areas. The following table should make it more visual:
+-------------------+-------------+-----------------+-----------------+---------------+--------+
| **Type** | *RigidBody* | *CharacterBody* | *KinematicBody* | *StaticBody* | *Area* |
+===================+=============+=================+=================+===============+========+
| **RigidBody** | Both | Both | Both | Rigidbody | Area |
+-------------------+-------------+-----------------+-----------------+---------------+--------+
| **CharacterBody** | Both | Both | Both | CharacterBody | Area |
+-------------------+-------------+-----------------+-----------------+---------------+--------+
| **KinematicBody** | Both | Both | None | None | Area |
+-------------------+-------------+-----------------+-----------------+---------------+--------+
| **StaticBody** | RigidBody | CharacterBody | None | None | None |
+-------------------+-------------+-----------------+-----------------+---------------+--------+
| **Area** | Area | Area | Area | None | Both |
+-------------------+-------------+-----------------+-----------------+---------------+--------+
Physics global variables
------------------------
A few global variables can be tweaked in the project settings for
adjusting how 2D physics works:
.. image:: /img/physics2d_options.png
Leaving them alone is best (except for the gravity, that needs to be
adjusted in most games), but there is one specific parameter that might
need tweaking which is the "cell_size". Godot 2D physics engine used by
default a space hashing algorithm that divides space in cells to compute
close collision pairs more efficiently.
If a game uses several colliders that are really small and occupy a
small portion of the screen, it might be necessary to shrink that value
(always to a power of 2) to improve efficiency. Likewise if a game uses
few large colliders that span a huge map (of several screens of size),
increasing that value a bit might help save resources.
Fixed process callback
----------------------
The physics engine may spawn multiple threads to improve performance, so
it can use up to a full frame to process physics. Because of this, when
accessing physics variables such as position, linear velocity, etc. they
might not be representative of what is going on in the current frame.
To solve this, Godot has a fixed process callback, which is like process
but it's called once per physics frame (by default 60 times per second).
During this time, the physics engine is in *synchronization* state and
can be accessed directly and without delays.
To enable a fixed process callback, use the ``set_fixed_process()``
function, example:
::
extends KinematicBody2D
func _fixed_process(delta):
move(direction * delta)
func _ready():
set_fixed_process(true)
Casting rays and motion queries
-------------------------------
It is very often desired to "explore" the world around from our code.
Throwing rays is the most common way to do it. The simplest way to do
this is by using the RayCast2D node, which will throw a ray every frame
and record the intersection.
At the moment there isn't a high level API for this, so the physics
server must be used directly. For this, the
:ref:`Physics2DDirectspaceState <class_Physics2DDirectspaceState>`
class must be used. To obtain it, the following steps must be taken:
1. It must be used inside the ``_fixed_process()`` callback, or at
``_integrate_forces()``
2. The 2D RIDs for the space and physics server must be obtained.
The following code should work:
::
func _fixed_process(delta):
var space = get_world_2d().get_space()
var space_state = Physics2DServer.space_get_direct_state(space)
Enjoy doing space queries!

View File

@@ -0,0 +1,169 @@
.. _doc_ray-casting:
Ray-casting
===========
Introduction
------------
One of the most common tasks in game development is casting a ray (or
custom shaped object) and checking what it hits. This enables complex
behaviors, AI, etc. to take place. This tutorial will explain how to
do this in 2D and 3D.
Godot stores all the low level game information in servers, while the
scene is just a frontend. As such, ray casting is generally a
lower-level task. For simple raycasts, node such as
:ref:`RayCast <class_RayCast>` and :ref:`RayCast2D <class_RayCast2D>`
will work, as they will return every frame what the result of a raycast
is.
Many times, though, ray-casting needs to be a more interactive process
so a way to do this by code must exist.
Space
-----
In the physics world, Godot stores all the low level collision and
physics information in a *space*. The current 2d space (for 2D Physics)
can be obtained by calling
:ref:`CanvasItem.get_world_2d().get_space() <class_CanvasItem_get_world_2d>`.
For 3D, it's :ref:`Spatial.get_world().get_space() <class_Spatial_get_world>`.
The resulting space :ref:`RID <class_RID>` can be used in
:ref:`PhysicsServer <class_PhysicsServer>` and
:ref:`Physics2DServer <class_Physics2DServer>` respectively for 3D and 2D.
Accessing space
--------------
Godot physics runs by default in the same thread as game logic, but may
be set to run on a separate thread to work more efficiently. Due to
this, the only time accessing space is safe is during the
:ref:`Node._fixed_process() <class_Node__fixed_process>`
callback. Accessing it from outside this function may result in an error
due to space being *locked*.
To perform queries into physics space, the
:ref:`Physics2DDirectSpaceState <class_Physics2DDirectSpaceState>`
and :ref:`PhysicsDirectSpaceState <class_PhysicsDirectSpaceState>`
must be used.
In code, for 2D spacestate, this code must be used:
::
func _fixed_process(delta):
var space_rid = get_world_2d().get_space()
var space_state = Physics2DServer.space_get_direct_state(space_rid)
Of course, there is a simpler shortcut:
::
func _fixed_process(delta):
var space_state = get_world_2d().get_direct_space_state()
For 3D:
::
func _fixed_process(delta):
var space_state = get_world().get_direct_space_state()
Raycast query
-------------
For performing a 2D raycast query, the method
:ref:`Physics2DDirectSpaceState.intersect_ray() <class_Physics2DDirectSpaceState_intersect_ray>`
must be used, for example:
::
func _fixed_process(delta):
var space_state = get_world().get_direct_space_state()
# use global coordinates, not local to node
var result = space_state.intersect_ray( Vector2(0,0), Vector2(50,100) )
Result is a dictionary. If the ray didn't hit anything, the dictionary will
be empty. If it did hit something it will contain collision information:
::
if (not result.empty()):
print("Hit at point: ",result.position)
The collision result dictionary, when something hit, has this format:
::
{
position:Vector2 # point in world space for collision
normal:Vector2 # normal in world space for collision
collider:Object # Object collided or null (if unassociated)
collider_id:ObjectID # Object it collided against
rid:RID # RID it collided against
shape:int # shape index of collider
metadata:Variant() # metadata of collider
}
# in case of 3D, Vector3 is returned.
Collision exceptions
--------------------
It is a very common case to attempt casting a ray from a character or
another game scene to try to infer properties of the world around it.
The problem with this is that the same character has a collider, so the
ray can never leave the origin (it will keep hitting its own collider),
as evidenced in the following image.
.. image:: /img/raycast_falsepositive.png
To avoid self-intersection, the intersect_ray() function can take an
optional third parameter which is an array of exceptions. This is an
example of how to use it from a KinematicBody2D or any other
collisionobject based node:
::
extends KinematicBody2D
func _fixed_process(delta):
var space_state = get_world().get_direct_space_state()
var result = space_state.intersect_ray( get_global_pos(), enemy_pos, [ self ] )
The extra argument is a list of exceptions, can be objects or RIDs.
3D ray casting from screen
--------------------------
Casting a ray from screen to 3D physics space is useful for object
picking. There is not much of a need to do this because
:ref:`CollisionObject <class_CollisionObject>`
has an "input_event" signal that will let you know when it was clicked,
but in case there is any desire to do it manually, here's how.
To cast a ray from the screen, the :ref:`Camera <class_Camera>` node
is needed. Camera can be in two projection modes, perspective and
orthogonal. Because of this, both the ray origin and direction must be
obtained. (origin changes in orthogonal, while direction changes in
perspective):
.. image:: /img/raycast_projection.png
To obtain it using a camera, the following code can be used:
::
const ray_length = 1000
func _input(ev):
if ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1:
var camera = get_node("camera")
var from = camera.project_ray_origin(ev.pos)
var to = from + camera.project_ray_normal(ev.pos) * ray_length
Of course, remember that during ``_input()``, space may be locked, so save
your query for ``_fixed_process()``.

View File

@@ -0,0 +1,124 @@
.. _doc_android_in_app_purchases:
Android in-app purchases
========================
.. highlight:: shell
Godot engine has integrated GooglePaymentsV3 module with which we can implement in-app purchases in our game.
The Godot engine demo project repository has an android-iap example project. It includes a gdscript interface for android IAP.
Check the repository here https://github.com/godotengine/godot-demo-projects
Find the iap.gd script in
::
godot-demo-projects/misc/android_iap
Add it to the Autoload list and name it as IAP so that we can reference it anywhere in the game.
Getting the product details
---------------------------
When starting our game, we will need to get the item details from Google such as the product price, description and localized price string etc.
::
#First listen to the sku details update callback
IAP.connect("sku_details_complete",self,"sku_details_complete")
#Then ask google the details for these items
IAP.sku_details_query(["pid1","pid2"]) #pid1 and pid2 are our product ids entered in Googleplay dashboard
#This will be called when sku details are retrieved successfully
func sku_details_complete():
print(IAP.sku_details) #This will print the details as JSON format, refer the format in iap.gd
print(IAP.sku_details["pid1"].price) #print formatted localized price
We can use the IAP details to display the title, price and/or description on our shop scene.
Check if user purchased an item
-------------------------------
When starting our game, we can check if the user has purchased any product. YOU SHOULD DO THIS ONLY AFTER 2/3 SECONDS AFTER YOUR GAME IS LOADED. If we do this as the first thing when the game is launched, IAP might not be initialized and our game will crash on start.
::
#Add a listener first
IAP.connect("has_purchased",self,"iap_has_purchased")
IAP.request_purchased() #Ask Google for all purchased items
#This will call for each and every user purchased products
func iap_has_purchased(item_name):
print(item_name) #print the name of purchased items
Google IAP policy says the game should restore the user's purchases if the user replaces his phone or reinstall the same app. We can use the above code to do check what products the user has purchased and we can make our game respond accordingly.
Simple Purchase
---------------
We can put this purchase logic on a product's buy button.
::
#First listen for purchase_success callback
IAP.connect("purchase_success",self,"purchase_success_callback")
#Then call purchase like this
IAP.purchase("pid1") #replace pid1 with your product id
IAP.purchase("pid2") #replace pid2 with your another product id
#This function will be called when the purchase is a success
func purchase_success_callback(item):
print(item + " has purchased")
We can also implement other signals for the purchase flow and improve the user experience as you needed.
``purchase_fail`` - When the purchase is failed due to any reason
``purchase_cancel`` - When the user cancels the purchase
``purchase_owned`` - When the user already bought the product earlier
Consumables and Non-Consumables
-------------------------------
There are two types of products - consumables and non-consumables.
**Consumables** are purchased and used, for eg: healing potions which can be purchased again and again.
**Non-consumables** are one time purchases, for eg: Level packs.
Google doesn't have this separation in their dashboard. If our product is a consumable, and if a user has purchased it, it will not be available for purchase until it is consumed. So we should call the consume method for our consumables and don't call consume for your non-consumables.
::
IAP.connnect("consume_success",self,"on_consume_success")
IAP.consume("pid")
func on_consume_success(item):
print(item + " consumed")
If our game has only consumables, we don't have to do this. We can set it to consume the item automatically after a purchase.
::
IAP.set_auto_consume(true)
If our game has only non-consumables, we can
::
IAP.set_auto_consume(false)
We should set the auto consume value only once when the game starts.
Testing
-------
If we add a gmail id as a tester in Google dashboard, that tester can purchase items and he will not be charged. Another way to test IAP is using redeem codes generated by us for our game because the purchase flow is the same.
Third way of testing is in development side. If we put the product ids as shown below, we will get a static fixed response according to the product id. This is a quick way of testing things before going to the dashboard.
- android.test.purchased
- android.test.canceled
- android.test.refunded
- android.test.item_unavailable

View File

@@ -0,0 +1,427 @@
.. _doc_services_for_ios:
Services for iOS
================
At the moment, there are 2 iOS APIs partially implemented, GameCenter
and Storekit. Both use the same model of asynchronous calls explained
below.
Asynchronous methods
--------------------
When requesting an asynchronous operation, the method will look like
this:
::
Error purchase(Variant p_params);
The parameter will usually be a Dictionary, with the information
necessary to make the request, and the call will have 2 phases. First,
the method will immediately return an Error value. If the Error is not
'OK', the call operation is completed, with an error probably caused
locally (no internet connection, API incorrectly configured, etc). If
the error value is 'OK', a response event will be produced and added to
the 'pending events' queue. Example:
.. code:: python
func on_purchase_pressed():
var result = InAppStore.purchase( { "product_id": "my_product" } )
if result == OK:
animation.play("busy") # show the "waiting for response" animation
else:
show_error()
# put this on a 1 second timer or something
func check_events():
while InAppStore.get_pending_event_count() > 0:
var event = InAppStore.pop_pending_event()
if event.type == "purchase":
if event.result == "ok":
show_success(event.product_id)
else:
show_error()
Remember that when a call returns OK, the API will *always* produce an
event through the pending_event interface, even if it's an error, or a
network timeout, etc. You should be able to, for example, safely block
the interface waiting for a reply from the server. If any of the APIs
don't behave this way it should be treated as a bug.
The pending event interface consists of 2 methods:
- ``get_pending_event_count()``
Returns the number of pending events on the queue.
- ``Variant pop_pending_event()``
Pops the first event from the queue and returns it.
Store Kit
---------
Implemented in platform/iphone/in_app_store.mm
The Store Kit API is accessible through the "InAppStore" singleton (will
always be available from gdscript). It is initialized automatically. It
has 2 methods for purchasing:
- ``Error purchase(Variant p_params);``
- ``Error request_product_info(Variant p_params);``
and the pending_event interface
::
int get_pending_event_count();
Variant pop_pending_event();
purchase
~~~~~~~~
Purchases a product id through the Store Kit API.
Parameters
^^^^^^^^^^
Takes a Dictionary as a parameter, with one field, ``product_id``, a
string with your product id. Example:
::
var result = InAppStore.purchase( { "product_id": "my_product" } )
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "purchase",
"result": "error",
"product_id": "the product id requested"
}
On success:
::
{
"type": "purchase",
"result": "ok",
"product_id": "the product id requested"
}
request_product_info
~~~~~~~~~~~~~~~~~~~~
Requests the product info on a list of product IDs.
Parameters
^^^^^^^^^^
Takes a Dictionary as a parameter, with one field, ``product_ids``, a
string array with a list of product ids. Example:
::
var result = InAppStore.request_product_info( { "product_ids": ["my_product1", "my_product2"] } )
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
::
{
"type": "product_info",
"result": "ok",
"invalid_ids": [ list of requested ids that were invalid ],
"ids": [ list of ids that were valid ],
"titles": [ list of valid product titles (corresponds with list of valid ids) ],
"descriptions": [ list of valid product descriptions ] ,
"prices": [ list of valid product prices ],
"localized_prices": [ list of valid product localized prices ],
}
Game Center
-----------
Implemented in platform/iphone/game_center.mm
The Game Center API is available through the "GameCenter" singleton. It
has 6 methods:
- ``Error post_score(Variant p_score);``
- ``Erroraward_achievement(Variant p_params);``
- ``Error reset_achievements();``
- ``Error request_achievements();``
- ``Error request_achievement_descriptions();``
- ``Error show_game_center(Variant p_params);``
plus the standard pending event interface.
post_score
~~~~~~~~~~
Posts a score to a Game Center leaderboard.
Parameters
^^^^^^^^^^
Takes a Dictionary as a parameter, with 2 fields:
- ``score`` a float number
- ``category`` a string with the category name
Example:
::
var result = GameCenter.post_score( { "value": 100, "category": "my_leaderboard", } )
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "post_score",
"result": "error",
"error_code": the value from NSError::code,
"error_description": the value from NSError::localizedDescription,
}
On success:
::
{
"type": "post_score",
"result": "ok",
}
award_achievement
~~~~~~~~~~~~~~~~~
Modifies the progress of a Game Center achievement.
Parameters
^^^^^^^^^^
Takes a Dictionary as a parameter, with 3 fields:
- ``name`` (string) the achievement name
- ``progress`` (float) the achievement progress from 0.0 to 100.0
(passed to ``GKAchievement::percentComplete``)
- ``show_completion_banner`` (bool) whether Game Center should display
an achievement banner at the top of the screen
Example:
::
var result = award_achievement( { "name": "hard_mode_completed", "progress": 6.1 } )
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "award_achievement",
"result": "error",
"error_code": the error code taken from NSError::code,
}
On success:
::
{
"type": "award_achievement",
"result": "ok",
}
reset_achievements
~~~~~~~~~~~~~~~~~~
Clears all Game Center achievements. The function takes no parameters.
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "reset_achievements",
"result": "error",
"error_code": the value from NSError::code
}
On success:
::
{
"type": "reset_achievements",
"result": "ok",
}
request_achievements
~~~~~~~~~~~~~~~~~~~~
Request all the Game Center achievements the player has made progress
on. The function takes no parameters.
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "achievements",
"result": "error",
"error_code": the value from NSError::code
}
On success:
::
{
"type": "achievements",
"result": "ok",
"names": [ list of the name of each achievement ],
"progress": [ list of the progress made on each achievement ]
}
request_achievement_descriptions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Request the descriptions of all existing Game Center achievements
regardless of progress. The function takes no parameters.
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On error:
::
{
"type": "achievement_descriptions",
"result": "error",
"error_code": the value from NSError::code
}
On success:
::
{
"type": "achievement_descriptions",
"result": "ok",
"names": [ list of the name of each achievement ],
"titles": [ list of the title of each achievement ]
"unachieved_descriptions": [ list of the description of each achievement when it is unachieved ]
"achieved_descriptions": [ list of the description of each achievement when it is achieved ]
"maximum_points": [ list of the points earned by completing each achievement ]
"hidden": [ list of booleans indicating whether each achievement is initially visible ]
"replayable": [ list of booleans indicating whether each achievement can be earned more than once ]
}
show_game_center
~~~~~~~~~~~~~~~~
Displays the built in Game Center overlay showing leaderboards,
achievements, and challenges.
Parameters
^^^^^^^^^^
Takes a Dictionary as a parameter, with 2 fields:
- ``view`` (string) (optional) the name of the view to present. Accepts
"default", "leaderboards", "achievements", or "challenges". Defaults
to "default".
- ``leaderboard_name`` (string) (optional) the name of the leaderboard
to present. Only used when "view" is "leaderboards" (or "default" is
configured to show leaderboards). If not specified, Game Center will
display the aggregate leaderboard.
Examples:
::
var result = show_game_center( { "view": "leaderboards", "leaderboard_name": "best_time_leaderboard" } )
var result = show_game_center( { "view": "achievements" } )
Response event
^^^^^^^^^^^^^^
The response event will be a dictionary with the following fields:
On close:
::
{
"type": "show_game_center",
"result": "ok",
}
Multi-platform games
--------------------
When working on a multi-platform game, you won't always have the
"GameCenter" singleton available (for example when running on PC or
Android). Because the gdscript compiler looks up the singletons at
compile time, you can't just query the singletons to see and use what
you need inside a conditional block, you need to also define them as
valid identifiers (local variable or class member). This is an example
of how to work around this in a class:
.. code:: python
var GameCenter = null # define it as a class member
func post_score(p_score):
if GameCenter == null:
return
GameCenter.post_score( { "value": p_score, "category": "my_leaderboard" } )
func check_events():
while GameCenter.get_pending_event_count() > 0:
# do something with events here
pass
func _ready():
# check if the singleton exists
if Globals.has_singleton("GameCenter"):
GameCenter = Globals.get_singleton("GameCenter")
# connect your timer here to the "check_events" function

View File

@@ -0,0 +1,109 @@
.. _doc_screen-reading_shaders:
Screen-reading shaders
======================
Introduction
~~~~~~~~~~~~
Very often it is desired to make a shader that reads from the same
screen it's writing to. 3D APIs such as OpenGL or DirectX make this very
difficult because of internal hardware limitations. GPUs are extremely
parallel, so reading and writing causes all sort of cache and coherency
problems. As a result, not even the most modern hardware supports this
properly.
The workaround is to make a copy of the screen, or a part of the screen,
to a back-buffer and then read from it while drawing. Godot provides a
few tools that makes this process easy!
TexScreen shader instruction
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Godot :ref:`doc_shading_language` has a special instruction, "texscreen", it takes as
parameter the UV of the screen and returns a vec3 RGB with the color. A
special built-in varying: SCREEN_UV can be used to obtain the UV for
the current fragment. As a result, this simple 2D fragment shader:
::
COLOR=vec4( texscreen(SCREEN_UV), 1.0 );
results in an invisible object, because it just shows what lies behind.
The same shader using the visual editor looks like this:
.. image:: /img/texscreen_visual_shader.png
TexScreen example
~~~~~~~~~~~~~~~~~
Texscreen instruction can be used for a lot of things. There is a
special demo for *Screen Space Shaders*, that you can download to see
and learn. One example is a simple shader to adjust brightness, contrast
and saturation:
::
uniform float brightness = 1.0;
uniform float contrast = 1.0;
uniform float saturation = 1.0;
vec3 c = texscreen(SCREEN_UV);
c.rgb = mix(vec3(0.0), c.rgb, brightness);
c.rgb = mix(vec3(0.5), c.rgb, contrast);
c.rgb = mix(vec3(dot(vec3(1.0), c.rgb)*0.33333), c.rgb, saturation);
COLOR.rgb = c;
Behind the scenes
~~~~~~~~~~~~~~~~~
While this seems magical, it's not. The Texscreen instruction, when
first found in a node that is about to be drawn, does a full-screen
copy to a back-buffer. Subsequent nodes that use texscreen() in
shaders will not have the screen copied for them, because this ends up
being very inefficient.
As a result, if shaders that use texscreen() overlap, the second one
will not use the result of the first one, resulting in unexpected
visuals:
.. image:: /img/texscreen_demo1.png
In the above image, the second sphere (top right) is using the same
source for texscreen() as the first one below, so the first one
"disappears", or is not visible.
To correct this, a
:ref:`BackBufferCopy <class_BackBufferCopy>`
node can be instanced between both spheres. BackBufferCopy can work by
either specifying a screen region or the whole screen:
.. image:: /img/texscreen_bbc.png
With correct back-buffer copying, the two spheres blend correctly:
.. image:: /img/texscreen_demo2.png
Back-buffer logic
~~~~~~~~~~~~~~~~~
So, to make it clearer, here's how the backbuffer copying logic works in
Godot:
- If a node uses the texscreen(), the entire screen is copied to the
back buffer before drawing that node. This only happens the first
time, subsequent nodes do not trigger this.
- If a BackBufferCopy node was processed before the situation in the
point above (even if texscreen() was not used), this behavior
described in the point above does not happen. In other words,
automatic copying of the entire screen only happens if texscreen() is
used in a node for the first time and no BackBufferCopy node (not
disabled) was found before in tree-order.
- BackBufferCopy can copy either the entire screen or a region. If set
to only a region (not the whole screen) and your shader uses pixels
not in the region copied, the result of that read is undefined
(most likely garbage from previous frames). In other words, it's
possible to use BackBufferCopy to copy back a region of the screen
and then use texscreen() on a different region. Avoid this behavior!

View File

@@ -0,0 +1,64 @@
.. _doc_shader_materials:
Shader materials
================
Introduction
------------
For the most common cases, :ref:`doc_fixed_materials` are enough to create the
desired textures or look and feel. Shader materials are a step beyond
that, adding a huge amount of flexibility. With them, it is possible to:
- Create procedural textures.
- Create complex texture blendings.
- Create animated materials, or materials that change with time.
- Create refractive effects or other advanced effects.
- Create special lighting shaders for more exotic materials.
- Animate vertices, like tree leaves or grass.
- And much more!
Traditionally, most engines will ask you to learn GLSL, HLSL or CG,
which are pretty complex for the skillset of most artists. Godot uses a
simplified version of a shader language that will detect errors as you
type, so you can see your edited shaders in real-time. Additionally, it
is possible to edit shaders using a visual, node-based graph editor.
Creating a ShaderMaterial
-------------------------
Create a new ShaderMaterial in some object of your choice. Go to the
"Shader" property, then create a new "MaterialShader" (use
"MaterialShaderGraph" for access to the visual graph editor):
.. image:: /img/shader_material_create.png
Edit the newly created shader, and the shader editor will open:
.. image:: /img/shader_material_editor.png
There are three code tabs open, the first is for the vertex shader, the
second for the fragment and the third for the lighting. The shader
language is documented in :ref:`doc_shading_language` so a small example will be
presented next.
Create a very simple fragment shader that writes a color:
::
uniform color col;
DIFFUSE = col.rgb;
Code changes take place in real-time. If the code is modified, it will
be instantly recompiled and the object will be updated. If a typo is
made, the editor will notify of the compilation failure:
.. image:: /img/shader_material_typo.png
Finally, go back and edit the material, and the exported uniform will be
instantly visible:
.. image:: /img/shader_material_col.png
This allows to very quickly create custom, complex materials for every
type of object.

View File

@@ -0,0 +1,518 @@
.. _doc_shading_language:
Shading language
================
Introduction
------------
Godot uses a simplified shader language (almost a subset of GLSL).
Shaders can be used for:
- Materials
- Post-Processing
- 2D
and are divided in *Vertex*, *Fragment* and *Light* sections.
Language
--------
Typing
~~~~~~
The language is statically type and supports only a few operations.
Arrays, classes, structures, etc are not supported. Several built-in
datatypes are provided:
Data types
~~~~~~~~~~
+-------------------+--------------------------------------------------------------+
| DataType | Description |
+===================+==============================================================+
| *void* | Void |
+-------------------+--------------------------------------------------------------+
| *bool* | boolean (true or false) |
+-------------------+--------------------------------------------------------------+
| *float* | floating point |
+-------------------+--------------------------------------------------------------+
| *vec2* | 2-component vector, float subindices (x,y or r,g ) |
+-------------------+--------------------------------------------------------------+
| *vec3* | 3-component vector, float subindices (x,y,z or r,g,b ) |
+-------------------+--------------------------------------------------------------+
| *vec4*, *color* | 4-component vector, float subindices (x,y,z,w or r,g,b,a ) |
+-------------------+--------------------------------------------------------------+
| *mat2* | 2x2 matrix, vec3 subindices (x,y) |
+-------------------+--------------------------------------------------------------+
| *mat3* | 3x3 matrix, vec3 subindices (x,y,z) |
+-------------------+--------------------------------------------------------------+
| *mat4* | 4x4 matrix, vec4 subindices (x,y,z,w) |
+-------------------+--------------------------------------------------------------+
| *texture* | texture sampler, can only be used as uniform |
+-------------------+--------------------------------------------------------------+
| *cubemap* | cubemap sampler, can only be used as uniform |
+-------------------+--------------------------------------------------------------+
Syntax
~~~~~~
The syntax is similar to C, with statements ending with ``;`` and comments
as ``//`` and ``/* */``. Example:
::
float a = 3;
vec3 b;
b.x = a;
Swizzling
~~~~~~~~~
It is possible to use swizzling to reassigning subindices or groups of
subindices, in order:
::
vec3 a = vec3(1,2,3);
vec3 b = a.zyx; // b will contain vec3(3,2,1)
vec2 c = a.xy; // c will contain vec2(1,2)
vec4 d = a.xyzz; // d will contain vec4(1,2,3,3)
Constructors
~~~~~~~~~~~~
Constructors take the regular amount of elements, but can also accept
less if the element has more subindices, for example:
::
vec3 a = vec3(1,vec2(2,3));
vec3 b = vec3(a);
vec3 c = vec3(vec2(2,3),1);
vec4 d = vec4(a,5);
mat3 m = mat3(a,b,c);
Conditionals
~~~~~~~~~~~~
For now, only the ``if`` conditional is supported. Example:
::
if (a < b) {
c = b;
}
Uniforms
~~~~~~~~
A variable can be declared as uniform. In this case, its value will
come from outside the shader (it will be the responsibility of the
material or whatever using the shader to provide it).
::
uniform vec3 direction;
uniform color tint;
vec3 result = tint.rgb * direction;
Functions
~~~~~~~~~
Simple support for functions is provided. Functions can't access
uniforms or other shader variables.
::
vec3 addtwo(vec3 a, vec3 b) {
return a+b;
}
vec3 c = addtwo(vec3(1,1,1), vec3(2,2,2));
Built-in functions
------------------
Several built-in functions are provided for convenience, listed as
follows:
+-----------------------------------------------------------------------+---------------------------------------------+
| Function | Description |
+=======================================================================+=============================================+
| float *sin* ( float ) | Sine |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *cos* ( float ) | Cosine |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *tan* ( float ) | Tangent |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *asin* ( float ) | arc-Sine |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *acos* ( float ) | arc-Cosine |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *atan* ( float ) | arc-Tangent |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *pow* ( vec\_type, float ) | Power |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *pow* ( vec\_type, vec\_type ) | Power (Vec. Exponent) |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *exp* ( vec\_type ) | Base-e Exponential |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *log* ( vec\_type ) | Natural Logarithm |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *sqrt* ( vec\_type ) | Square Root |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *abs* ( vec\_type ) | Absolute |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *sign* ( vec\_type ) | Sign |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *floor* ( vec\_type ) | Floor |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *trunc* ( vec\_type ) | Trunc |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *ceil* ( vec\_type ) | Ceiling |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *fract* ( vec\_type ) | Fractional |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *mod* ( vec\_type,vec\_type ) | Remainder |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *min* ( vec\_type,vec\_type ) | Minimum |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *min* ( vec\_type,vec\_type ) | Maximum |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *clamp* ( vec\_type value,vec\_type min, vec\_type max ) | Clamp to Min-Max |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *mix* ( vec\_type a,vec\_type b, float c ) | Linear Interpolate |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *mix* ( vec\_type a,vec\_type b, vec\_type c ) | Linear Interpolate (Vector Coef.) |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *step* ( vec\_type a,vec\_type b) | \` a[i] < b[i] ? 0.0 : 1.0\` |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *smoothstep* ( vec\_type a,vec\_type b,vec\_type c) | |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *length* ( vec\_type ) | Vector Length |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *distance* ( vec\_type, vec\_type ) | Distance between vector. |
+-----------------------------------------------------------------------+---------------------------------------------+
| float *dot* ( vec\_type, vec\_type ) | Dot Product |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec3 *cross* ( vec3, vec3 ) | Cross Product |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec\_type *normalize* ( vec\_type ) | Normalize to unit length |
+-----------------------------------------------------------------------+---------------------------------------------+
| vec3 *reflect* ( vec3, vec3 ) | Reflect |
+-----------------------------------------------------------------------+---------------------------------------------+
| color *tex* ( texture, vec2 ) | Read from a texture in normalized coords |
+-----------------------------------------------------------------------+---------------------------------------------+
| color *texcube* ( texture, vec3 ) | Read from a cubemap |
+-----------------------------------------------------------------------+---------------------------------------------+
| color *texscreen* ( vec2 ) | Read from screen (generates a copy) |
+-----------------------------------------------------------------------+---------------------------------------------+
Built-in variables
------------------
Depending on the shader type, several built-in variables are available,
listed as follows:
Material (3D) - VertexShader
~~~~~~~~~~~~~~~~~~~~~~~
+------------------------------------+-------------------------------------------+
| Variable | Description |
+====================================+===========================================+
| const vec3 *SRC\_VERTEX* | Model-Space Vertex |
+------------------------------------+-------------------------------------------+
| const vec3 *SRC\_NORMAL* | Model-Space Normal |
+------------------------------------+-------------------------------------------+
| const vec3 *SRC\_TANGENT* | Model-Space Tangent |
+------------------------------------+-------------------------------------------+
| const float *SRC\_BINORMALF* | Direction to Compute Binormal |
+------------------------------------+-------------------------------------------+
| vec3 *VERTEX* | View-Space Vertex |
+------------------------------------+-------------------------------------------+
| vec3 *NORMAL* | View-Space Normal |
+------------------------------------+-------------------------------------------+
| vec3 *TANGENT* | View-Space Tangent |
+------------------------------------+-------------------------------------------+
| vec3 *BINORMAL* | View-Space Binormal |
+------------------------------------+-------------------------------------------+
| vec2 *UV* | UV |
+------------------------------------+-------------------------------------------+
| vec2 *UV2* | UV2 |
+------------------------------------+-------------------------------------------+
| color *COLOR* | Vertex Color |
+------------------------------------+-------------------------------------------+
| out vec4 *VAR1* | Varying 1 Output |
+------------------------------------+-------------------------------------------+
| out vec4 *VAR2* | Varying 2 Output |
+------------------------------------+-------------------------------------------+
| out float *SPEC\_EXP* | Specular Exponent (for Vertex Lighting) |
+------------------------------------+-------------------------------------------+
| out float *POINT\_SIZE* | Point Size (for points) |
+------------------------------------+-------------------------------------------+
| const mat4 *WORLD\_MATRIX* | Object World Matrix |
+------------------------------------+-------------------------------------------+
| const mat4 *INV\_CAMERA\_MATRIX* | Inverse Camera Matrix |
+------------------------------------+-------------------------------------------+
| const mat4 *PROJECTION\_MATRIX* | Projection Matrix |
+------------------------------------+-------------------------------------------+
| const mat4 *MODELVIEW\_MATRIX* | (InvCamera \* Projection) |
+------------------------------------+-------------------------------------------+
| const float *INSTANCE\_ID* | Instance ID (for multimesh) |
+------------------------------------+-------------------------------------------+
| const float *TIME* | Time (in seconds) |
+------------------------------------+-------------------------------------------+
Material (3D) - FragmentShader
~~~~~~~~~~~~~~~~~~~~~~~~~
+----------------------------------+----------------------------------------------------------------------------------+
| Variable | Description |
+==================================+==================================================================================+
| const vec3 *VERTEX* | View-Space vertex |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec4 *POSITION* | View-Space Position |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec3 *NORMAL* | View-Space Normal |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec3 *TANGENT* | View-Space Tangent |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec3 *BINORMAL* | View-Space Binormal |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec3 *NORMALMAP* | Alternative to NORMAL, use for normal texture output. |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec3 *NORMALMAP\_DEPTH* | Complementary to the above, allows changing depth of normalmap. |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec2 *UV* | UV |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec2 *UV2* | UV2 |
+----------------------------------+----------------------------------------------------------------------------------+
| const color *COLOR* | Vertex Color |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec4 *VAR1* | Varying 1 |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec4 *VAR2* | Varying 2 |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec2 *SCREEN\_UV* | Screen Texture Coordinate (for using with texscreen) |
+----------------------------------+----------------------------------------------------------------------------------+
| const float *TIME* | Time (in seconds) |
+----------------------------------+----------------------------------------------------------------------------------+
| const vec2 *POINT\_COORD* | UV for point, when drawing point sprites. |
+----------------------------------+----------------------------------------------------------------------------------+
| out vec3 *DIFFUSE* | Diffuse Color |
+----------------------------------+----------------------------------------------------------------------------------+
| out vec4 *DIFFUSE\_ALPHA* | Diffuse Color with Alpha (using this sends geometry to alpha pipeline) |
+----------------------------------+----------------------------------------------------------------------------------+
| out vec3 *SPECULAR* | Specular Color |
+----------------------------------+----------------------------------------------------------------------------------+
| out vec3 *EMISSION* | Emission Color |
+----------------------------------+----------------------------------------------------------------------------------+
| out float *SPEC\_EXP* | Specular Exponent (Fragment Version) |
+----------------------------------+----------------------------------------------------------------------------------+
| out float *GLOW* | Glow |
+----------------------------------+----------------------------------------------------------------------------------+
| out mat4 *INV\_CAMERA\_MATRIX* | Inverse camera matrix, can be used to obtain world coords (see example below). |
+----------------------------------+----------------------------------------------------------------------------------+
Material (3D) - LightShader
~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------+-------------------------------+
| Variable | Description |
+================================+===============================+
| const vec3 *NORMAL* | View-Space normal |
+--------------------------------+-------------------------------+
| const vec3 *LIGHT\_DIR* | View-Space Light Direction |
+--------------------------------+-------------------------------+
| const vec3 *EYE\_VEC* | View-Space Eye-Point Vector |
+--------------------------------+-------------------------------+
| const vec3 *DIFFUSE* | Material Diffuse Color |
+--------------------------------+-------------------------------+
| const vec3 *LIGHT\_DIFFUSE* | Light Diffuse Color |
+--------------------------------+-------------------------------+
| const vec3 *SPECULAR* | Material Specular Color |
+--------------------------------+-------------------------------+
| const vec3 *LIGHT\_SPECULAR* | Light Specular Color |
+--------------------------------+-------------------------------+
| const float *SPECULAR\_EXP* | Specular Exponent |
+--------------------------------+-------------------------------+
| const vec1 *SHADE\_PARAM* | Generic Shade Parameter |
+--------------------------------+-------------------------------+
| const vec2 *POINT\_COORD* | Current UV for Point Sprite |
+--------------------------------+-------------------------------+
| out vec2 *LIGHT* | Resulting Light |
+--------------------------------+-------------------------------+
| const float *TIME* | Time (in seconds) |
+--------------------------------+-------------------------------+
CanvasItem (2D) - VertexShader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-----------------------------------+--------------------------------------------------------------------------------------------+
| Variable | Description |
+===================================+============================================================================================+
| const vec2 *SRC\_VERTEX* | CanvasItem space vertex. |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| vec2 *UV* | UV |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| out vec2 *VERTEX* | Output LocalSpace vertex. |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| out vec2 *WORLD\_VERTEX* | Output WorldSpace vertex. (use this or the one above) |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| color *COLOR* | Vertex Color |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| out vec4 *VAR1* | Varying 1 Output |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| out vec4 *VAR2* | Varying 2 Output |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| out float *POINT\_SIZE* | Point Size (for points) |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| const mat4 *WORLD\_MATRIX* | Object World Matrix |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| const mat4 *EXTRA\_MATRIX* | Extra (user supplied) matrix via CanvasItem.draw\_set\_transform(). Identity by default. |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| const mat4 *PROJECTION\_MATRIX* | Projection Matrix (model coords to screen). |
+-----------------------------------+--------------------------------------------------------------------------------------------+
| const float *TIME* | Time (in seconds) |
+-----------------------------------+--------------------------------------------------------------------------------------------+
CanvasItem (2D) - FragmentShader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------------------------------+------------------------------------------------------------------------------+
| Variable | Description |
+=====================================+==============================================================================+
| const vec4 *SRC\_COLOR* | Vertex color |
+-------------------------------------+------------------------------------------------------------------------------+
| const vec4 *POSITION* | Screen Position |
+-------------------------------------+------------------------------------------------------------------------------+
| vec2 *UV* | UV |
+-------------------------------------+------------------------------------------------------------------------------+
| out color *COLOR* | Output Color |
+-------------------------------------+------------------------------------------------------------------------------+
| out vec3 *NORMAL* | Optional Normal (used for 2D Lighting) |
+-------------------------------------+------------------------------------------------------------------------------+
| out vec3 *NORMALMAP* | Optional Normal in standard normalmap format (flipped y and Z from 0 to 1) |
+-------------------------------------+------------------------------------------------------------------------------+
| out float *NORMALMAP\_DEPTH* | Depth option for above normalmap output, default value is 1.0 |
+-------------------------------------+------------------------------------------------------------------------------+
| const texture *TEXTURE* | Current texture in use for CanvasItem |
+-------------------------------------+------------------------------------------------------------------------------+
| const vec2 *TEXTURE\_PIXEL\_SIZE* | Pixel size for current 2D texture |
+-------------------------------------+------------------------------------------------------------------------------+
| in vec4 *VAR1* | Varying 1 Output |
+-------------------------------------+------------------------------------------------------------------------------+
| in vec4 *VAR2* | Varying 2 Output |
+-------------------------------------+------------------------------------------------------------------------------+
| const vec2 *SCREEN\_UV* | Screen Texture Coordinate (for using with texscreen) |
+-------------------------------------+------------------------------------------------------------------------------+
| const vec2 *POINT\_COORD* | Current UV for Point Sprite |
+-------------------------------------+------------------------------------------------------------------------------+
| const float *TIME* | Time (in seconds) |
+-------------------------------------+------------------------------------------------------------------------------+
CanvasItem (2D) - LightShader
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------------------------------+-------------------------------------------------------------------------------+
| Variable | Description |
+=====================================+===============================================================================+
| const vec4 *POSITION* | Screen Position |
+-------------------------------------+-------------------------------------------------------------------------------+
| in vec3 *NORMAL* | Input Normal |
+-------------------------------------+-------------------------------------------------------------------------------+
| in vec2 *UV* | UV |
+-------------------------------------+-------------------------------------------------------------------------------+
| in color *COLOR* | Input Color |
+-------------------------------------+-------------------------------------------------------------------------------+
| const texture *TEXTURE* | Current texture in use for CanvasItem |
+-------------------------------------+-------------------------------------------------------------------------------+
| const vec2 *TEXTURE\_PIXEL\_SIZE* | Pixel size for current 2D texture |
+-------------------------------------+-------------------------------------------------------------------------------+
| in vec4 *VAR1* | Varying 1 Output |
+-------------------------------------+-------------------------------------------------------------------------------+
| in vec4 *VAR2* | Varying 2 Output |
+-------------------------------------+-------------------------------------------------------------------------------+
| const vec2 *SCREEN\_UV* | Screen Texture Coordinate (for using with texscreen) |
+-------------------------------------+-------------------------------------------------------------------------------+
| const vec2 *POINT\_COORD* | Current UV for Point Sprite |
+-------------------------------------+-------------------------------------------------------------------------------+
| const float *TIME* | Time (in seconds) |
+-------------------------------------+-------------------------------------------------------------------------------+
| vec2 *LIGHT\_VEC* | Vector from light to fragment, can be modified to alter shadow computation. |
+-------------------------------------+-------------------------------------------------------------------------------+
| const float *LIGHT\_HEIGHT* | Height of Light |
+-------------------------------------+-------------------------------------------------------------------------------+
| const color *LIGHT\_COLOR* | Color of Light |
+-------------------------------------+-------------------------------------------------------------------------------+
| const color *LIGHT\_SHADOW\_COLOR* | Color of Light shadow |
+-------------------------------------+-------------------------------------------------------------------------------+
| vec2 *LIGHT\_UV* | UV for light image |
+-------------------------------------+-------------------------------------------------------------------------------+
| color *SHADOW* | Light shadow color override |
+-------------------------------------+-------------------------------------------------------------------------------+
| out vec4 *LIGHT* | Light Output (shader is ignored if this is not used) |
+-------------------------------------+-------------------------------------------------------------------------------+
Examples
--------
Material that reads a texture, a color and multiples them, fragment
program:
::
uniform color modulate;
uniform texture source;
DIFFUSE = modulate.rgb * tex(source, UV).rgb;
Material that glows from red to white:
::
DIFFUSE = vec3(1,0,0) + vec3(1,1,1) * mod(TIME, 1.0);
Standard Blinn Lighting Shader
::
float NdotL = max(0.0, dot(NORMAL, LIGHT_DIR));
vec3 half_vec = normalize(LIGHT_DIR + EYE_VEC);
float eye_light = max(dot(NORMAL, half_vec), 0.0);
LIGHT = LIGHT_DIFFUSE + DIFFUSE + NdotL;
if (NdotL > 0.0) {
LIGHT += LIGHT_SPECULAR + SPECULAR + pow(eye_light, SPECULAR_EXP);
};
Obtaining world-space normal and position in material fragment program:
::
// Use reverse multiply because INV_CAMERA_MATRIX is world2cam
vec4 invcamx = INV_CAMERA_MATRIX.x;
vec4 invcamy = INV_CAMERA_MATRIX.y;
vec4 invcamz = INV_CAMERA_MATRIX.z;
vec4 invcamw = INV_CAMERA_MATRIX.w;
mat3 invcam = mat3(invcamx.xyz, invcamy.xyz, invcamz.xyz);
vec3 world_normal = NORMAL * invcam;
vec3 world_pos = (VERTEX - invcamw.xyz) * invcam;
Notes
-----
- **Do not** use DIFFUSE_ALPHA unless you really intend to use
transparency. Transparent materials must be sorted by depth and slow
down the rendering pipeline. For opaque materials, just use DIFFUSE.
- **Do not** use DISCARD unless you really need it. Discard makes
rendering slower, specially on mobile devices.
- TIME may reset after a while (may last an hour or so), it's meant
for effects that vary over time.
- In general, every built-in variable not used results in less shader
code generated, so writing a single giant shader with a lot of code
and optional scenarios is often not a good idea.

View File

@@ -0,0 +1,90 @@
.. _doc_multiple_resolutions:
Multiple resolutions
====================
Base resolution
---------------
A base screen resolution for the project can be specified in the project
settings.
.. image:: /img/screenres.png
However, what it does is not completely obvious. When running on PC, the
engine will attempt to set this resolution (or use something smaller if
it fails). On mobile, consoles or devices with a fixed resolution or
full screen rendering, this resolution will be ignored and the native
resolution will be used instead. To compensate for this, Godot offers
many ways to control how the screen will resize and stretch to different
screen sizes.
Resizing
--------
There are several types of devices, with several types of screens, which
in turn have different pixel density and resolutions. Handling all of
them can be a lot of work, so Godot tries to make the developer's life a
little easier. The :ref:`Viewport <class_Viewport>`
node has several functions to handle resizing, and the root node of the
scene tree is always a viewport (scenes loaded are instanced as a child
of it, and it can always be accessed by calling
``get_tree().get_root()`` or ``get_node("/root")``).
In any case, while changing the root Viewport params is probably the
most flexible way to deal with the problem, it can be a lot of work,
code and guessing, so Godot provides a simple set of parameters in the
project settings to handle multiple resolutions.
Stretch settings
----------------
Stretch settings are located in the project settings, it's just a bunch
of configuration variables that provide several options:
.. image:: /img/stretchsettings.png
Stretch mode
------------
- **Disabled**: The first is the stretch mode. By default this is
disabled, which means no stretching happens (the bigger the screen or
window, the bigger the resolution, always matching pixels 1:1).
- **2D**: In this mode, the resolution specified in display/width and
display/height in the project settings will be stretched to cover the
whole screen. This means that 3D will be unaffected (will just render
to higher-res) and 2D will also be rendered at higher-res, just
enlarged.
- **Viewport**: Viewport scaling is different, the root
:ref:`Viewport <class_Viewport>`
is set as a render target, and still renders precisely to the
resolution specified in the ``display/`` section of the project
settings. Finally, this viewport is copied and scaled to fit the
screen. This mode is useful when working with pixel-precise games, or
just for the sake of rendering to a lower resolution for improving
performance.
.. image:: /img/stretch.png
Stretch aspect
--------------
- **Ignore**: Ignore the aspect ratio when stretching the screen. This
means that the original resolution will be stretched to fit the new
one, even if it's wider or narrower.
- **Keep**: Keep aspect ratio when stretching the screen. This means
that the original resolution will be kept when fitting the new one,
and black bars will be added to the sides or the top/bottom of the
screen.
- **Keep Width**: Keep aspect ratio when stretching the screen, but if
the resulting screen is taller than the specified resolution, it will
be stretched vertically (and more vertical resolution will be
reported in the viewport, proportionally). This is usually the best
option for creating GUIs or HUDs that scale, so some controls can be
anchored to the bottom (:ref:`doc_size_and_anchors`).
- **Keep Height**: Keep aspect ratio when stretching the screen, but if
the resulting screen is wider than the specified resolution, it will
be stretched horizontally (and more horizontal resolution will be
reported in the viewport, proportionally). This is usually the best
option for 2D games that scroll horizontally (like runners or
platformers).

View File

@@ -0,0 +1,184 @@
.. _doc_viewports:
Viewports
=========
Introduction
------------
Godot has a small but very useful feature called viewports. Viewports
are, as they name implies, rectangles where the world is drawn. They
have three main uses, but can flexibly adapted to a lot more. All this
is done via the :ref:`Viewport <class_Viewport>` node.
.. image:: /img/viewportnode.png
The main uses in question are:
- **Scene Root**: The root of the active scene is always a Viewport.
This is what displays the scenes created by the user. (You should
know this by having read previous tutorials!)
- **Sub-Viewports**: These can be created when a Viewport is a child of
a :ref:`Control <class_Control>`.
- **Render Targets**: Viewports can be set to "RenderTarget" mode. This
means that the viewport is not directly visible, but its contents
can be accessed via a :ref:`Texture <class_Texture>`.
Input
-----
Viewports are also responsible of delivering properly adjusted and
scaled input events to all its children nodes. Both the root viewport
and sub-viewports do this automatically, but render targets do not.
Because of this, the user must do it manually via the
:ref:`Viewport.input() <class_Viewport_input>` function if needed.
Listener
--------
Godot supports 3D sound (in both 2D and 3D nodes), more on this can be
found in another tutorial (one day..). For this type of sound to be
audible, the viewport needs to be enabled as a listener (for 2D or 3D).
If you are using a custom viewport to display your world, don't forget
to enable this!
Cameras (2D & 3D)
-----------------
When using a 2D or 3D :ref:`Camera <class_Camera>` /
:ref:`Camera2D <class_Camera2D>`, cameras will always display on the
closest parent viewport (going towards the root). For example, in the
following hierarchy:
- Viewport
- Camera
Camera will display on the parent viewport, but in the following one:
- Camera
- Viewport
It will not (or may display in the root viewport if this is a subscene).
There can be only one active camera per viewport, so if there is more
than one, make sure that the desired one has the "current" property set,
or make it the current camera by calling:
::
camera.make_current()
Scale & stretching
------------------
Viewports have a "rect" property. X and Y are often not used (only the
root viewport really uses them), while WIDTH AND HEIGHT represent the
size of the viewport in pixels. For Sub-Viewports, these values are
overridden by the ones from the parent control, but for render targets
this sets their resolution.
It is also possible to scale the 2D content and make it believe the
viewport resolution is other than the one specified in the rect, by
calling:
::
viewport.set_size_override(w,h) #custom size for 2D
viewport.set_size_override_stretch(true/false) #enable stretch for custom size
The root viewport uses this for the stretch options in the project
settings.
Worlds
------
For 3D, a Viewport will contain a :ref:`World <class_World>`. This
is basically the universe that links physics and rendering together.
Spatial-base nodes will register using the World of the closest
viewport. By default, newly created viewports do not contain a World but
use the same as a parent viewport (root viewport does contain one
though, which is the one objects are rendered to by default). A world can
be set in a viewport using the "world" property, and that will separate
all children nodes of that viewport from interacting with the parent
viewport world. This is specially useful in scenarios where, for
example, you might want to show a separate character in 3D imposed over
the game (like in Starcraft).
As a helper for situations where you want to create viewports that
display single objects and don't want to create a world, viewport has
the option to use its own World. This is very useful when you want to
instance 3D characters or objects in the 2D world.
For 2D, each Viewport always contains its own :ref:`World2D <class_World2D>`.
This suffices in most cases, but in case sharing them may be desired, it
is possible to do so by calling the viewport API manually.
Capture
-------
It is possible to query a capture of the viewport contents. For the root
viewport this is effectively a screen capture. This is done with the
following API:
::
# queues a screen capture, will not happen immediately
viewport.queue_screen_capture()
After a frame or two (check _process()), the capture will be ready,
get it back by using:
::
var capture = viewport.get_screen_capture()
If the returned image is empty, capture still didn't happen, wait a
little more, as this API is asyncronous.
Sub-viewport
------------
If the viewport is a child of a control, it will become active and
display anything it has inside. The layout is something like this:
- Control
- Viewport
The viewport will cover the area of its parent control completely.
.. image:: /img/subviewport.png
Render target
-------------
To set as a render target, just toggle the "render target" property of
the viewport to enabled. Note that whatever is inside will not be
visible in the scene editor. To display the contents, the render target
texture must be used. This can be requested via code using (for
example):
::
var rtt = viewport.get_render_target_texture()
sprite.set_texture(rtt)
By default, re-rendering of the render target happens when the render
target texture has been drawn in a frame. If visible, it will be
rendered, otherwise it will not. This behavior can be changed to manual
rendering (once), or always render, no matter if visible or not.
A few classes are created to make this easier in most common cases
inside the editor:
- :ref:`ViewportSprite <class_ViewportSprite>` (for 2D).
- ViewportQuad (for 3D).
- ViewportFrame (for GUI).
*TODO: Review the doc, ViewportQuad and ViewportFrame don't exist in 2.0.*
Make sure to check the viewport demos! Viewport folder in the demos
archive available to download, or
https://github.com/godotengine/godot-demo-projects/tree/master/viewport

View File

@@ -0,0 +1,97 @@
.. _doc_animations:
Animations
==========
Introduction
------------
This tutorial will explain how everything is animated in Godot. Godot's
animation system is extremely powerful and flexible.
To begin, let's just use the scene from the previous tutorial (:ref:`doc_splash_screen`).
The goal is, to add a simple animation to it. Here's a copy
just in case: :download:`robisplash.zip </files/robisplash.zip>`.
Creating the animation
----------------------
First of all, add an :ref:`AnimationPlayer <class_AnimationPlayer>`
node to the scene as a child of "bg" (the root node):
.. image:: /img/animplayer.png
When a node of this type is selected, the animation editor panel will
appear:
.. image:: /img/animpanel.png
So, it's time to create a new animation! Press the new animation button
and name the animation "intro".
.. image:: /img/animnew.png
After the animation has been created, it's time to edit it, by
pressing the "edit" button:
.. image:: /img/animedit.png
Editing the animation
---------------------
Now this is when the magic happens! Several things happen when the
"edit" button is pressed, the first one is that the animation editor
appears above the animation panel. (In Godot 2.x, this button has been
removed, instead, click on the 'animation' toggle at the bottom right
for similar functionality.)
.. image:: /img/animeditor.png
The second and most important, is that the property editor enters
"animation editing" mode. In this mode, a key icon appears next to
every property of the property editor. This means that, in Godot, *any
property of any object* can be animated:
.. image:: /img/propertykeys.png
Making the logo appear
----------------------
The logo will appear from the top of the screen. After selecting
the animation player, the editor panel will stay visible until
manually hidden (or the animation node is erased). Taking advantage of
this, select the "logo" node and go to the "pos" property, move it up
to position: 114,-400.
Once in this position, press the key button next to the property:
.. image:: /img/keypress.png
As the track is new, a dialog will appear asking to create it. Confirm
it!
.. image:: /img/addtrack.png
The keyframe will be added in the animation player editor:
.. image:: /img/keyadded.png
Move the editor cursor to the end, by clicking here:
.. image:: /img/move_cursor.png
Change the logo position to 114,0 and add a keyframe again. With two
keyframes, the animation happens.
.. image:: /img/animation.png
Pressing Play on the animation panel will make the logo descend. To test
it by running the scene, the autoplay button can tag the animation to
start automatically when the scene starts:
.. image:: /img/autoplay.png
And finally, when running the scene, the animation should look like
this:
.. image:: /img/out.gif

View File

@@ -0,0 +1,111 @@
.. _doc_filesystem:
File system
==========
Introduction
------------
File systems are yet another hot topic in engine development. The
file system manages how the assets are stored, and how they are accessed.
A well designed file system also allows multiple developers to edit the
same source files and assets while collaborating together.
Initial versions of the Godot engine (and previous iterations before it was
named Godot) used a database. Assets were stored in it and assigned an
ID. Other approaches were tried as well, such as local databases, files with
metadata, etc. In the end the simple approach won and now Godot stores
all assets as files in the file system.
Implementation
--------------
The file system stores resources on disk. Anything, from a script, to a scene or a
PNG image is a resource to the engine. If a resource contains properties
that reference other resources on disk, the paths to those resources are also
included. If a resource has sub-resources that are built-in, the resource is
saved in a single file together with all the bundled sub-resources. For
example, a font resource is often bundled together with the font textures.
In general the Godot file system avoids using metadata files. The reason for
this is simple, existing asset managers and VCSs are simply much better than
anything we can implement, so Godot tries the best to play along with SVN,
Git, Mercurial, Perforce, etc.
Example of a file system contents:
::
/engine.cfg
/enemy/enemy.scn
/enemy/enemy.gd
/enemy/enemysprite.png
/player/player.gd
engine.cfg
----------
The engine.cfg file is the project description file, and it is always found at
the root of the project. In fact its location defines where the root is. This
is the first file that Godot looks for when opening a project.
This file contains the project configuration in plain text, using the win.ini
format. Even an empty engine.cfg can function as a basic definition of a blank
project.
Path delimiter
-------------------
Godot only supports ``/`` as a path delimiter. This is done for
portability reasons. All operating systems support this, even Windows,
so a path such as ``c:\project\engine.cfg`` needs to be typed as
``c:/project/engine.cfg``.
Resource path
-------------
When accessing resources, using the host OS file system layout can be
cumbersome and non-portable. To solve this problem, the special path
``res://`` was created.
The path ``res://`` will always point at the project root (where
engine.cfg is located, so in fact ``res://engine.cfg`` is always
valid).
This file system is read-write only when running the project locally from
the editor. When exported or when running on different devices (such as
phones or consoles, or running from DVD), the file system will become
read-only and writing will no longer be permitted.
User path
---------
Writing to disk is often still needed for various tasks such as saving game
state or downloading content packs. To this end, the engine ensures that there is a
special path ``user://`` that is always writable.
Host file system
---------------
Alternatively host file system paths can also be used, but this is not recommended
for a released product as these paths are not guaranteed to work on all platforms.
However, using host file system paths can be very useful when writing development
tools in Godot!
Drawbacks
---------
There are some drawbacks to this simple file system design. The first issue is that
moving assets around (renaming them or moving them from one path to another inside
the project) will break existing references to these assets. These references will
have to be re-defined to point at the new asset location.
The second is that under Windows and OSX file and path names are case insensitive.
If a developer working in a case insensitive host file system saves an asset as "myfile.PNG",
but then references it as "myfile.png", it will work just fine on their platorm, but not
on other platforms, such as Linux, Android, etc. This may also apply to exported binaries,
which use a compressed package to store all files.
It is recommended that your team clearly defines a naming convention for files when
working with Godot! One simple fool-proof convention is to only allow lowercase
file and path names.

View File

@@ -0,0 +1,176 @@
.. _doc_gui_tutorial:
GUI tutorial
============
Introduction
~~~~~~~~~~~~
If there is something that most programmers hate with passion, it is
programming graphical user interfaces (GUIs). It's boring, tedious and
unchallenging. Several aspects make matters worse, such as:
- Pixel alignment of UI elements is difficult (such that it looks just
like the designer intends).
- UIs are changed constantly due to design and usability issues that
appear during testing.
- Handling proper screen re-sizing for different display resolutions.
- Animating several screen components, to make it look less static.
GUI programming is one of the leading causes of programmer burnout.
During the development of Godot (and previous engine iterations),
several techniques and philosophies for UI development were put into
practice, such as immediate mode, containers, anchors, scripting, etc.
This was always done with the main goal of reducing the stress
programmers had to face while putting together user interfaces.
In the end, the resulting UI subsystem in Godot is an efficient solution
to this problem, and works by mixing together a few different
approaches. While the learning curve is a little steeper than in other
toolkits, developers can put together complex user interfaces in very
little time, by sharing the same set of tools with designers and
animators.
Control
~~~~~~~
The basic node for UI elements is :ref:`Control <class_Control>`
(sometimes called "Widget" or "Box" in other toolkits). Every node that
provides user interface functionality descends from it.
When controls are put in a scene tree as a child of another control,
its coordinates (position, size) are always relative to the parent.
This sets the basis for editing complex user interfaces quickly and
visually.
Input and drawing
~~~~~~~~~~~~~~~~~
Controls receive input events by means of the
:ref:`Control._input_event() <class_Control__input_event>`
callback. Only one control, the one in focus, will receive
keyboard/joypad events (see
:ref:`Control.set_focus_mode() <class_Control_set_focus_mode>`
and :ref:`Control.grab_focus() <class_Control_grab_focus>`).
Mouse motion events are received by the control directly below the mouse
pointer. When a control receives a mouse button pressed event, all
subsequent motion events are received by the pressed control until that
button is released, even if the pointer moves outside the control
boundary.
Like any class that inherits from :ref:`CanvasItem <class_CanvasItem>`
(Control does), a :ref:`CanvasItem._draw() <class_CanvasItem__draw>`
callback will be received at the beginning and every time the control
needs to be redrawn (the programmer needs to call
:ref:`CanvasItem.update() <class_CanvasItem_update>`
to enqueue the CanvasItem for redraw). If the control is not visible
(yet another CanvasItem property), the control does not receive any
input.
In general though, the programmer does not need to deal with drawing and
input events directly when building UIs (that is more useful when
creating custom controls). Instead, controls emit different kinds of
signals with contextual information for when action occurs. For
example, a :ref:`Button <class_Button>` emits
a "pressed" signal when pressed, a :ref:`Slider <class_Slider>` will
emit a "value_changed" when dragged, etc.
Custom control mini tutorial
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Before going into more depth, creating a custom control will be a good
way to get the picture on how controls works, as they are not as
complex as it might seem.
Additionally, even though Godot comes with dozens of controls for
different purposes, it happens often that it's easier to attain a
specific functionality by creating a new one.
To begin, create a single-node scene. The node is of type "Control" and
has a certain area of the screen in the 2D editor, like this:
.. image:: /img/singlecontrol.png
Add a script to that node, with the following code:
::
extends Control
var tapped=false
func _draw():
var r = Rect2( Vector2(), get_size() )
if (tapped):
draw_rect(r, Color(1,0,0) )
else:
draw_rect(r, Color(0,0,1) )
func _input_event(ev):
if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed):
tapped=true
update()
Then run the scene. When the rectangle is clicked/tapped, it will change
color from blue to red. That synergy between the events and the drawing
is pretty much how most controls work internally.
.. image:: /img/ctrl_normal.png
.. image:: /img/ctrl_tapped.png
UI complexity
~~~~~~~~~~~~~
As mentioned before, Godot includes dozens of controls ready for use
in a user interface. Such controls are divided in two categories. The
first is a small set of controls that work well for creating most game
user interfaces. The second (and most controls are of this type) are
meant for complex user interfaces and uniform skinning through styles. A
description is presented as follows to help understand which one should
be used in which case.
Simplified UI controls
~~~~~~~~~~~~~~~~~~~~~~
This set of controls is enough for most games, where complex
interactions or ways to present information are not necessary. They can
be skinned easily with regular textures.
- :ref:`Label <class_Label>`: Node used for showing text.
- :ref:`TextureFrame <class_TextureFrame>`: Displays a single texture,
which can be scaled or kept fixed.
- :ref:`TextureButton <class_TextureButton>`: Displays a simple textured
button, states such as pressed, hover, disabled, etc. can be set.
- :ref:`TextureProgress <class_TextureProgress>`: Displays a single
textured progress bar.
Additionally, re-positioning of controls is most efficiently done with
anchors in this case (see the :ref:`doc_size_and_anchors` tutorial for more
information).
In any case, it will happen often that even for simple games, more
complex UI behaviors are required. An example of this is a scrolling
list of elements (for a high score table, for example), which needs a
:ref:`ScrollContainer <class_ScrollContainer>`
and a :ref:`VBoxContainer <class_VBoxContainer>`.
These kind of more advanced controls can be mixed with the regular ones
seamlessly (they are all controls after all).
Complex UI controls
~~~~~~~~~~~~~~~~~~~
The rest of the controls (and there are dozens of them!) are meant for
another set of scenarios, most commonly:
- Games that require complex UIs, such as PC RPGs, MMOs, strategy,
sims, etc.
- Creating custom development tools to speed up content creation.
- Creating Godot Editor Plugins, to extend the engine functionality.
Re-positioning controls for these kind of interfaces is more commonly
done with containers (see the :ref:`doc_size_and_anchors` tutorial for more
information).

View File

@@ -0,0 +1,113 @@
.. _doc_instancing:
Instancing
==========
Rationale
---------
Having a scene and throwing nodes into it might work for small projects,
but as a project grows, more and more nodes are used and it can quickly
become unmanageable. To solve this, Godot allows a project to be
separated in several scenes. This, however, does not work the same way
as in other game engines. In fact, it's quite different, so please do
not skip this tutorial!
To recap: A scene is a collection of nodes organized as a tree, where
they can have only one single node as the tree root.
.. image:: /img/tree.png
In Godot, a scene can be created and saved to disk. As many scenes
can be created and saved as desired.
.. image:: /img/instancingpre.png
Afterwards, while editing an existing or a new scene, other scenes can
be instanced as part of it:
.. image:: /img/instancing.png
In the above picture, Scene B was added to Scene A as an instance. It
may seem weird at first, but at the end of this tutorial it will make
complete sense!
Instancing, step by step
------------------------
To learn how to do instancing, let's start with downloading a sample
project: :download:`instancing.zip </files/instancing.zip>`.
Unzip this scene in any place of your preference. Then, add this scene to
the project manager using the 'Import' option:
.. image:: /img/importproject.png
Simply browse to inside the project location and open the "engine.cfg"
file. The new project will appear on the list of projects. Edit the
project by using the 'Edit' option.
This project contains two scenes "ball.scn" and "container.scn". The
ball scene is just a ball with physics, while container scene has a
nicely shaped collision, so balls can be thrown in there.
.. image:: /img/ballscene.png
.. image:: /img/contscene.png
Open the container scene, then select the root node:
.. image:: /img/controot.png
Afterwards, push the link shaped button, this is the instancing button!
.. image:: /img/continst.png
Select the ball scene (ball.scn), the ball should appear in the origin
(0,0), move it to around the center
of the scene, like this:
.. image:: /img/continstanced.png
Press Play and Voila!
.. image:: /img/playinst.png
The instanced ball fell to the bottom of the pit.
A little more
-------------
There can be as many instances as desired in a scene, just try
instancing more balls, or duplicating them (ctrl-D or duplicate button):
.. image:: /img/instmany.png
Then try running the scene again:
.. image:: /img/instmanyrun.png
Cool, huh? This is how instancing works.
Editing instances
-----------------
Select one of the many copies of the balls and go to the property
editor. Let's make it bounce a lot more, so look for the bounce
parameter and set it to 1.0:
.. image:: /img/instedit.png
The next it will happen is that a green "revert" button appears. When
this button is present, it means we modified a property from the
instanced scene to override for a specific value in this instance. Even
if that property is modified in the original scene, the custom value
will always overwrite it. Pressing the revert button will restore the
property to the original value that came from the scene.
Conclusion
----------
Instancing seems handy, but there is more to it than meets the eye!
The next part of the instancing tutorial should cover the rest..

View File

@@ -0,0 +1,77 @@
.. _doc_instancing_continued:
Instancing (continued)
======================
Recap
-----
Instancing has many handy uses. At a glance, with instancing you have:
- The ability to subdivide scenes and make them easier to manage.
- A more flexible alternative to prefabs (and much more powerful given
instances work at many levels).
- A way to design more complex game flows or even UIs (UI Elements are
nodes in Godot too).
Design language
---------------
But the real strong point of instancing scenes is that it works as an
excellent design language. This is pretty much what makes Godot special
and different to any other engine out there. The entire engine was designed
from the ground up around this concept.
When making games with Godot, the recommended approach is to leave aside
other design patterns such as MVC or Entity-Relationship diagrams and
start thinking games in a more natural way. Start by imagining the
visible elements in a game, the ones that can be named not by just a
programmer but by anyone.
For example, here's how a simple shooter game can be imagined:
.. image:: /img/shooter_instancing.png
It's pretty easy to come up with a diagram like this for almost any kind
of game. Just write down the elements that come to mind, and then the
arrows that represent ownership.
Once this diagram exists, making a game is about creating a scene for
each of those nodes, and use instancing (either by code or from the editor) to represent ownership.
Most of the time programming games (or software in general) is spent
designing an architecture and fitting game components to that
architecture. Designing based on scenes replaces that and makes
development much faster and more straightforward, allowing to
concentrate on the game itself. Scene/Instancing based design is
extremely efficient at saving a large part of that work, since most of
the components designed map directly to a scene. This way, none or
little architectural code is needed.
The following is a more complex example, an open-world type of game with
lots of assets and parts that interact:
.. image:: /img/openworld_instancing.png
Make some rooms with furniture, then connect them. Make a house later,
and use those rooms as the interior.
The house can be part of a citadel, which has many houses. Finally the
citadel can be put on the world map terrain. Add also guards and other
NPCs to the citadel by previously creating their scenes.
With Godot, games can grow as quickly as desired, as all it needs is
to create and instance more scenes. The editor UI is designed to be
operated by non programmers too, so a typical team development process
can involve 3D or 2D artists, level designers, game designers, animators,
etc all working with the editor interface.
Information overload!
---------------------
Do not worry too much, the important part of this tutorial is to create
awareness on how scenes and instancing are used in real life. The best
way to understand all this is to make some games.
Everything will become very obvious when put to practice, so please do
not scratch your head and go on to the next tutorial!

View File

@@ -0,0 +1,144 @@
.. _doc_resources:
Resources
=========
Nodes and resources
-------------------
So far, :ref:`Nodes <class_Node>`
have been the most important datatype in Godot, as most of the behaviors
and features of the engine are implemented through them. There is
another datatype that is equally important:
:ref:`Resource <class_Resource>`.
Where *Nodes* focus on behaviors, such as drawing a sprite, drawing a
3D model, physics, GUI controls, etc,
**Resources** are mere **data containers**. This means that they don't
do any action nor process any information. Resources just contain
data.
Examples of resources are
:ref:`Texture <class_Texture>`,
:ref:`Script <class_Script>`,
:ref:`Mesh <class_Mesh>`,
:ref:`Animation <class_Animation>`,
:ref:`Sample <class_Sample>`,
:ref:`AudioStream <class_AudioStream>`,
:ref:`Font <class_Font>`,
:ref:`Translation <class_Translation>`,
etc.
When Godot saves or loads (from disk) a scene (.scn or .xml), an image
(png, jpg), a script (.gd) or pretty much anything, that file is
considered a resource.
When a resource is loaded from disk, **it is always loaded once**. That
means, if there is a copy of that resource already loaded in memory,
trying to load the resource again will just return the same copy again
and again. This corresponds with the fact that resources are just data
containers, so there is no need to have them duplicated.
Typically, every object in Godot (Node, Resource, or anything else) can
export properties, properties can be of many types (like a string,
integer, Vector2, etc) and one of those types can be a resource. This
means that both nodes and resources can contain resources as properties.
To make it a little more visual:
.. image:: /img/nodes_resources.png
External vs built-in
--------------------
The resource properties can reference resources in two ways,
*external* (on disk) or **built-in**.
To be more specific, here's a :ref:`Texture <class_Texture>`
in a :ref:`Sprite <class_Sprite>` node:
.. image:: /img/spriteprop.png
Pressing the ">" button on the right side of the preview allows to
view and edit the resources properties. One of the properties (path)
shows where it comes from. In this case, it comes from a png image.
.. image:: /img/resourcerobi.png
When the resource comes from a file, it is considered an *external*
resource. If the path property is erased (or it never had a path to
begin with), it is considered a built-in resource.
For example, if the path \`"res://robi.png"\` is erased from the "path"
property in the above example, and then the scene is saved, the resource
will be saved inside the .scn scene file, no longer referencing the
external "robi.png". However, even if saved as built-in, and even though
the scene can be instanced multiple times, the resource will always
be loaded only once. That means, different Robi robot scenes instanced
at the same time will still share the same image.
Loading resources from code
---------------------------
Loading resources from code is easy. There are two ways to do it. The
first is to use load(), like this:
::
func _ready():
var res = load("res://robi.png") # resource is loaded when line is executed
get_node("sprite").set_texture(res)
The second way is more optimal, but only works with a string constant
parameter, because it loads the resource at compile-time.
::
func _ready():
var res = preload("res://robi.png") # resource is loaded at compile time
get_node("sprite").set_texture(res)
Loading scenes
--------------
Scenes are also resources, but there is a catch. Scenes saved to disk
are resources of type :ref:`PackedScene <class_PackedScene>`,
this means that the scene is packed inside a resource.
To obtain an instance of the scene, the method
:ref:`PackedScene.instance() <class_PackedScene_instance>`
must be used.
::
func _on_shoot():
var bullet = preload("res://bullet.scn").instance()
add_child(bullet)
This method creates the nodes in hierarchy, configures them (sets all
the properties) and returns the root node of the scene, which can be
added to any other node.
The approach has several advantages. As the
:ref:`PackedScene.instance() <class_PackedScene_instance>`
function is pretty fast, adding extra content to the scene can be done
efficiently. New enemies, bullets, effects, etc can be added or
removed quickly, without having to load them again from disk each
time. It is important to remember that, as always, images, meshes, etc
are all shared between the scene instances.
Freeing resources
-----------------
Resource extends from :ref:`Reference <class_Reference>`.
As such, when a resource is no longer in use, it will automatically free
itself. Since, in most cases, Resources are contained in Nodes, scripts
or other resources, when a node is removed or freed, all the children
resources are freed too.
Scripting
---------
Like any object in Godot, not just nodes, resources can be scripted,
too. However, there isn't generally much of an advantage, as resources
are just data containers.

View File

@@ -0,0 +1,153 @@
.. _doc_scene_tree:
SceneTree
=========
Introduction
------------
This is where things start getting abstract, but don't panic, as
there's not really more depth than this.
In previous tutorials, everything revolves around the concept of
nodes, scenes are made of them, and they become active once they enter
the *scene tree*.
This concept deserves going into a little more detail. In fact, the
scene system is not even a core component of Godot, as it is possible to
skip it and write a script (or C++ code) that talks directly to the
servers. But making a game that way would be a lot of work.
MainLoop
--------
The way Godot works internally is as follows. There is the
:ref:`OS <class_OS>` class,
which is the only instance that runs at the beginning. Afterwards, all
drivers, servers, scripting languages, scene system, etc are loaded.
When initialization is complete, :ref:`OS <class_OS>` needs to be
supplied a :ref:`MainLoop <class_MainLoop>`
to run. Up to this point, all this is internals working (you can check
main/main.cpp file in the source code if you are ever interested to
see how this works internally).
The user program, or game, starts in the MainLoop. This class has a few
methods, for initialization, idle (frame-syncronized callback), fixed
(physics-synchronized callback), and input. Again, this is really low
level and when making games in Godot, writing your own MainLoop does not
even make sense.
SceneTree
---------
One of the ways to explain how Godot works, is that it's a high level
game engine over a low level middleware.
The scene system is the game engine, while the :ref:`OS <class_OS>`
and servers are the low level API.
In any case, the scene system provides its own main loop to OS,
:ref:`SceneTree <class_SceneTree>`.
This is automatically instanced and set when running a scene, no need
to do any extra work.
It's important to know that this class exists because it has a few
important uses:
- It contains the root :ref:`Viewport <class_Viewport>`, to which a
scene is added as a child when it's first opened, to become
part of the *Scene Tree* (more on that next)
- It contains information about the groups, and has means to call all
nodes in a group, or get a list of them.
- It contains some global state functionality, such as setting pause
mode, or quitting the process.
When a node is part of the Scene Tree, the
:ref:`SceneTree <class_SceneTree>`
singleton can be obtained by simply calling
:ref:`Node.get_tree() <class_Node_get_tree>`.
Root viewport
-------------
The root :ref:`Viewport <class_Viewport>`
is always at the top of the scene. From a node, it can be obtained in
two different ways:
::
get_tree().get_root() # access via scenemainloop
get_node("/root") # access via absolute path
This node contains the main viewport, anything that is a child of a
:ref:`Viewport <class_Viewport>`
is drawn inside of it by default, so it makes sense that the top of all
nodes is always a node of this type, otherwise nothing would be seen!
While other viewports can be created in the scene (for split-screen
effects and such), this one is the only one that is never created by the
user. It's created automatically inside SceneTree.
Scene tree
----------
When a node is connected, directly or indirectly, to the root
viewport, it becomes part of the *scene tree*.
This means that, as explained in previous tutorials, it will get the
_enter_tree() and _ready() callbacks (as well as _exit_tree()).
.. image:: /img/activescene.png
When nodes enter the *Scene Tree*, they become active. They get access
to everything they need to process, get input, display 2D and 3D,
notifications, play sound, groups, etc. When they are removed from the
*scene tree*, they lose access.
Tree order
----------
Most node operations in Godot, such as drawing 2D, processing or getting
notifications are done in tree order. This means that parents and
siblings with a smaller rank in the tree order will get notified before
the current node.
.. image:: /img/toptobottom.png
"Becoming active" by entering the *Scene Tree*
----------------------------------------------
#. A scene is loaded from disk or created by scripting.
#. The root node of that scene (only one root, remember?) is added as
either a child of the "root" Viewport (from SceneTree), or to any
child or grand-child of it.
#. Every node of the newly added scene, will receive the "enter_tree"
notification ( _enter_tree() callback in GDScript) in top-to-bottom
order.
#. An extra notification, "ready" ( _ready() callback in GDScript) is
provided for convenience, when a node and all its children are
inside the active scene.
#. When a scene (or part of it) is removed, they receive the "exit
scene" notification ( _exit_tree() callback in GDScript) in
bottom-to-top order
Changing current scene
----------------------
After a scene is loaded, it is often desired to change this scene for
another one. The simple way to do this is to use the
:ref:`SceneTree.change_scene() <class_SceneTree_change_scene>`
function:
::
func _my_level_was_completed():
get_tree().change_scene("res://levels/level2.scn")
This is a quick and useful way to switch scenes, but has the drawback
that the game will stall until the new scene is loaded and running. At
some point in your game, it may be desired to create proper loading
screens with progress bar, animated indicators or thread (background)
loading. This must be done manually using autoloads (see next chapter!)
and :ref:`doc_background_loading`.

View File

@@ -0,0 +1,212 @@
.. _doc_scenes_and_nodes:
Scenes and nodes
================
Introduction
------------
.. image:: /img/chef.png
Imagine for a second that you are not a game developer anymore. Instead,
you're a chef! Change your hipster outfit for a toque and a double
breasted jacket. Now, instead of making games, you create new and
delicious recipes for your guests.
So, how does a chef create a recipe? Recipes are divided into two
sections: the first is the ingredients and the second is the
instructions to prepare it. This way, anyone can follow the recipe and
savor your magnificent creation.
Making games in Godot feels pretty much the same way. Using the engine
feels like being in a kitchen. In this kitchen, *nodes* are like a
refrigerator full of fresh ingredients to cook with.
There are many types of nodes, some show images, others play sound,
other nodes display 3D models, etc. There's dozens of them.
Nodes
-----
But let's start with the basics. A node is a basic element for creating a
game, it has the following characteristics:
- Has a name.
- Has editable properties.
- Can receive a callback to process every frame.
- Can be extended (to have more functions).
- Can be added to other nodes as children.
.. image:: /img/tree.png
The last one is very important. Nodes can have other nodes as
children. When arranged in this way, the nodes become a **tree**.
In Godot, the ability to arrange nodes in this way creates a powerful
tool for organizing projects. Since different nodes have different
functions, combining them allows for creation of more complex functions.
This is probably not clear yet and makes little sense, but everything
will click a few sections ahead. The most important fact to remember for
now is that nodes exist and can be arranged this way.
Scenes
------
.. image:: /img/scene_tree_example.png
Now that the concept of nodes has been defined, the next logical
step is to explain what a Scene is.
A scene is composed of a group of nodes organized hierarchically (in
tree fashion). It has the following properties:
- A scene always has only one root node.
- Scenes can be saved to disk and loaded back.
- Scenes can be *instanced* (more on that later).
- Running a game means running a scene.
- There can be several scenes in a project, but for it to start, one of
them must be selected to be loaded first.
Basically, the Godot editor is a **scene editor**. It has plenty of
tools for editing 2D and 3D scenes as well as user interfaces, but the
editor is based on the concept of editing a scene and the nodes
that compose it.
Creating a new project
----------------------
Theory is boring, so let's change the subject and go practical. Following a
long tradition in tutorials, the first project will be a Hello World.
For this, the editor will be used.
When the godot executable is run outside a project, the Project Manager
appears. This helps developers manage their projects.
.. image:: /img/project_manager.png
To create a new project, the "New Project" option must be used. Choose
and create a path for the project and specify the project name:
.. image:: /img/create_new_project.png
Editor
------
Once the "New Project" is created, the next step is opening it. This
will open the Godot editor. Here is how the editor looks when freshly
opened:
.. image:: /img/empty_editor.png
As mentioned before, making games in Godot feels like being in a
kitchen, so let's open the refrigerator and add some fresh nodes to the
project. We'll begin with a Hello World! To do this, the "New Node"
button must be pressed (looks like a plus symbol):
.. image:: /img/newnode_button.png
This will open the Create Node dialog, showing the long list of nodes
that can be created:
.. image:: /img/node_classes.png
From there, select the "Label" node first. Searching for it is probably
the quickest way:
.. image:: /img/node_search_label.png
And finally, create the Label! A lot happens when Create is pressed:
.. image:: /img/editor_with_label.png
First of all, the scene is changed to the 2D editor (because Label is
a 2D Node type), and the Label appears, selected, at the top left
corner of the viewport.
The node appears in the scene tree editor (box in the top left
corner), and the label properties appear in the Inspector (box on the
right side).
The next step will be to change the "Text" Property of the label, let's
change it to "Hello, World!":
.. image:: /img/hw.png
Ok, everything's ready to run the scene! Press the PLAY SCENE Button on
the top bar (or hit F6):
.. image:: /img/playscene.png
Aaaand... Oops.
.. image:: /img/neversaved.png
Scenes need to be saved to be run, so save the scene to something like
hello.scn in Scene -> Save:
.. image:: /img/save_scene.png
And here's when something funny happens. The file dialog is a special
file dialog, and only allows you to save inside the project. The project
root is "res://" which means "resource path". This means that files can
only be saved inside the project. For the future, when doing file
operations in Godot, remember that "res://" is the resource path, and no
matter the platform or install location, it is the way to locate where
resource files are from inside the game.
After saving the scene and pressing run scene again, the "Hello, World!"
demo should finally execute:
.. image:: /img/helloworld.png
Success!
.. _doc_scenes_and_nodes-configuring_the_project:
Configuring the project
-----------------------
Ok, It's time to do some configuration to the project. Right now, the
only way to run something is to execute the current scene. Projects,
however, have several scenes so one of them must be set as the main
scene. This scene is the one that will be loaded at the time the project
is run.
These settings are all stored in the engine.cfg file, which is a
plaintext file in win.ini format, for easy editing. There are dozens of
settings that can be changed in this file to alter how a project executes,
so to make matters simpler, a project setting dialog exists, which is
sort of a frontend to editing engine.cfg
To access that dialog, simply go to Scene -> Project Settings.
Once the window opens, the task will be to select a main scene. This can
be done easily by changing the application/main_scene property and
selecting 'hello.scn'.
.. image:: /img/main_scene.png
With this change, pressing the regular Play button (or F5) will run the
project, no matter which scene is being edited.
Going back to the project settings dialog. This dialog provides a lot
of options that can be added to engine.cfg, and shows their default
values. If the default value is ok, then there isn't any need to
change it.
When a value is changed, a tick is marked to the left of the name.
This means that the property will be saved to the engine.cfg file and
remembered.
As a side note, for future reference and a little out of context (this
is the first tutorial after all!), it is also possible to add custom
configuration options and read them in run-time using the
:ref:`Globals <class_Globals>` singleton.
To be continued...
------------------
This tutorial talks about "scenes and nodes", but so far there has been
only *one* scene and *one* node! Don't worry, the next tutorial will
deal with that...

View File

@@ -0,0 +1,224 @@
.. _doc_scripting:
Scripting
=========
Introduction
------------
Much has been said about tools that allow users to create video games
without programming. It's been a dream for many independent developers
to create games without learning how to code. This need has been around
for a long time, even inside companies, where game designers wish to
have more control of the game flow.
Many products have been shipped promising a no-programming environment,
but the result is often incomplete, too complex or inefficient compared
to traditional code. As a result, programming is here to stay for a long
time. In fact, the general direction in game engines has been to add
tools that try to reduce the amount of code that needs to be written for
specific tasks, to speed up development.
In that sense, Godot has taken some useful design decisions towards that
goal. The first and most important is the scene system. The aim of it is
not obvious at first, but works well later on. That is, to relieve
programmers from the responsibility of architecting code.
When designing games using the scene system, the whole project is
fragmented into *complementary* scenes (not individual ones). Scenes
complement each other, instead of being separate. There will be plenty
of examples about this later on, but it's very important to remember it.
For those with a good amount of programming expertise, this means a
different design pattern to MVC. Godot promises efficiency at the
expense of dropping the MVC habits, which are replaced by the *scenes as
a complement* pattern.
Godot also uses the `extend <http://c2.com/cgi/wiki?EmbedVsExtend>`__
pattern for scripting, meaning that scripts extend from all the
available engine classes.
GDScript
--------
:ref:`doc_gdscript` is a dynamically typed scripting language to fit
inside Godot. It was designed with the following goals:
- First and most importantly, making it simple, familiar and as easy to
learn as possible.
- Making the code readable and error safe. The syntax is mostly
borrowed from Python.
Programmers generally take a few days to learn it, and within two weeks
feel comfortable with it.
As with most dynamically typed languages, the higher productivity
(code is easier to learn, faster to write, no compilation, etc) is
balanced with a performance penalty. But most critical code is written
in C++ already in the engine (vector ops, physics, math, indexing, etc),
resulting in a more than sufficient performance for most types of
games.
In any case, if more performance is required, critical sections can be
rewritten in C++ and exposed transparently to the script. This allows
the replacement of a GDScript class with a C++ class without altering
the rest of the game.
Scripting a scene
-----------------
Before continuing, please make sure to read the :ref:`doc_gdscript` reference.
It's a simple language and the reference is short, it will not take
more than a few minutes to get an overview of the concepts.
Scene setup
~~~~~~~~~~~
This tutorial will begin by scripting a simple GUI scene. Use the add
node dialog to create the following hierarchy, with the following nodes:
- Panel
* Label
* Button
It should look like this in the scene tree:
.. image:: /img/scripting_scene_tree.png
Use the 2D editor to position and resize the button and label so that they
look like the image below. You can set the text in the Inspector pane.
.. image:: /img/label_button_example.png
Finally, save the scene, a fitting name could be "sayhello.scn"
.. _doc_scripting-adding_a_script:
Adding a script
~~~~~~~~~~~~~~~
Right click on the panel node, then select "Add Script" in the context
menu:
.. image:: /img/add_script.png
The script creation dialog will pop up. This dialog allows to select
the language, class name, etc. GDScript does not use class names in
script files, so that field is not editable. The script should inherit
from "Panel" (as it is meant to extend the node, which is of Panel type,
this is automatically filled).
Enter a path name for the script and then select "Create":
.. image:: /img/script_create.png
Once this is done, the script will be created and added to the node. You
can see this both as an extra icon in the node, as well as in the script
property:
.. image:: /img/script_added.png
To edit the script, select either of the highlighted buttons.
This will bring you to the script editor where an existing template will
be included by default:
.. image:: /img/script_template.png
There is not much in there. The "_ready()" function is called when the
node (and all its children) entered the active scene. (Remember, it's
not a constructor, the constructor is "_init()" ).
The role of the script
~~~~~~~~~~~~~~~~~~~~~~
A script adds behavior to a node. It is used to control the
node functions as well as other nodes (children, parent, siblings, etc).
The local scope of the script is the node (just like in regular
inheritance) and the virtual functions of the node are captured by the
script.
.. image:: /img/brainslug.jpg
Handling a signal
~~~~~~~~~~~~~~~~~
Signals are used mostly in GUI nodes (although other nodes have them
too). Signals are "emitted" when some specific kind of action happens,
and can be connected to any function of any script instance. In this
step, the "pressed" signal from the button will be connected to a custom
function.
An interface for connecting signals to your scripts exists in the editor.
You can access this by selecting the node in the scene tree and then
selecting the "Node" tab. Make sure that you have "Signals" selected.
.. image:: /img/signals.png
In any case, at this point it is clear that we are interested in
the "pressed" signal. Instead of using the visual interface, we will opt
to code the connection.
For this, a function exists that is probably the one most used by Godot
programmers, namely :ref:`Node.get_node() <class_Node_get_node>`.
This function uses paths to fetch nodes in the current tree or anywhere
in the scene, relative to the node holding the script.
To fetch the button, the following must be used:
::
get_node("Button")
Next, a callback will be added that will change the label's text when
the button is pressed:
::
func _on_button_pressed():
get_node("Label").set_text("HELLO!")
Finally, the button "pressed" signal will be connected to that callback
in _ready(), by using :ref:`Object.connect() <class_Object_connect>`.
::
func _ready():
get_node("Button").connect("pressed",self,"_on_button_pressed")
The final script should look like this:
::
extends Panel
# member variables here, example:
# var a=2
# var b="textvar"
func _on_button_pressed():
get_node("Label").set_text("HELLO!")
func _ready():
get_node("Button").connect("pressed",self,"_on_button_pressed")
Running the scene should have the expected result when pressing the
button:
.. image:: /img/scripting_hello.png
**Note:** As it is a common misunderstanding in this tutorial, let's clarify
again that get_node(path) works by returning the *immediate* children of
the node controlled by the script (in this case, *Panel*), so *Button*
must be a child of *Panel* for the above code to work. To give this
clarification more context, if *Button* were a child of *Label*, the code
to obtain it would be:
::
# not for this case
# but just in case
get_node("Label/Button")
Also, remember that nodes are referenced by name, not by type.

View File

@@ -0,0 +1,235 @@
.. _doc_scripting_continued:
Scripting (continued)
=====================
Processing
----------
Several actions in Godot are triggered by callbacks or virtual
functions, so there is no need to check for writing code that runs all
the time. Additionally, a lot can be done with animation players.
However, it is still a very common case to have a script process on every
frame. There are two types of processing, idle processing and fixed
processing.
Idle processing is activated with the
:ref:`Node.set_process() <class_Node_set_process>`
function. Once active, the :ref:`Node._process() <class_Node__process>`
callback will be called every frame. Example:
::
func _ready():
set_process(true)
func _process(delta):
# do something...
The delta parameter describes the time elapsed (in seconds, as
floating point) since the previous call to _process().
Fixed processing is similar, but only needed for synchronization with
the physics engine.
A simple way to test this is to create a scene with a single Label node,
with the following script:
::
extends Label
var accum=0
func _ready():
set_process(true)
func _process(delta):
accum += delta
set_text(str(accum))
Which will show a counter increasing each frame.
Groups
------
Nodes can be added to groups (as many as desired per node). This is a
simple yet useful feature for organizing large scenes. There are two
ways to do this, the first is from the UI, from the Groups button under Node-panel:
.. image:: /img/groups_in_nodes.PNG
And the second from code. One useful example would be to tag scenes
which are enemies.
::
func _ready():
add_to_group("enemies")
This way, if the player is discovered sneaking into the secret base,
all enemies can be notified about the alarm sounding, by using
:ref:`SceneTree.call_group() <class_SceneTree_call_group>`:
::
func _on_discovered():
get_tree().call_group(0, "guards", "player_was_discovered")
The above code calls the function "player_was_discovered" on every
member of the group "guards".
Optionally, it is possible to get the full list of "guards" nodes by
calling
:ref:`SceneTree.get_nodes_in_group() <class_SceneTree_get_nodes_in_group>`:
::
var guards = get_tree().get_nodes_in_group("guards")
More will be added about
:ref:`SceneTree <class_SceneTree>`
later.
Notifications
-------------
Godot has a system of notifications. This is usually not needed for
scripting, as it's too low level and virtual functions are provided for
most of them. It's just good to know they exists. Simply
add a
:ref:`Object._notification() <class_Object__notification>`
function in your script:
::
func _notification(what):
if (what == NOTIFICATION_READY):
print("This is the same as overriding _ready()...")
elif (what == NOTIFICATION_PROCESS):
var delta = get_process_time()
print("This is the same as overriding _process()...")
The documentation of each class in the :ref:`Class Reference <toc-class-ref>`
shows the notifications it can receive. However, for most cases GDScript
provides simpler overrideable functions.
Overrideable functions
----------------------
Nodes provide many useful overrideable functions, which are described as
follows:
::
func _enter_tree():
# When the node enters the _Scene Tree_, it becomes active
# and this function is called. Children nodes have not entered
# the active scene yet. In general, it's better to use _ready()
# for most cases.
pass
func _ready():
# This function is called after _enter_tree, but it ensures
# that all children nodes have also entered the _Scene Tree_,
# and became active.
pass
func _exit_tree():
# When the node exits the _Scene Tree_, this function is called.
# Children nodes have all exited the _Scene Tree_ at this point
# and all became inactive.
pass
func _process(delta):
# When set_process() is enabled, this function is called every frame.
pass
func _fixed_process(delta):
# When set_fixed_process() is enabled, this is called every physics
# frame.
pass
func _paused():
# Called when game is paused. After this call, the node will not receive
# any more process callbacks.
pass
func _unpaused():
# Called when game is unpaused.
pass
As mentioned before, it's best to use these functions.
Creating nodes
--------------
To create a node from code, just call the .new() method (like for any
other class based datatype). Example:
::
var s
func _ready():
s = Sprite.new() # create a new sprite!
add_child(s) # add it as a child of this node
To delete a node, be it inside or outside the scene, free() must be
used:
::
func _someaction():
s.free() # immediately removes the node from the scene and frees it
When a node is freed, it also frees all its children nodes. Because of
this, manually deleting nodes is much simpler than it appears. Just free
the base node and everything else in the sub-tree goes away with it.
However, it might happen very often that we want to delete a node that
is currently "blocked", because it is emitting a signal or calling a
function. This will result in crashing the game. Running Godot
in the debugger often will catch this case and warn you about it.
The safest way to delete a node is by using
:ref:`Node.queue_free() <class_Node_queue_free>`.
This erases the node safely during idle.
::
func _someaction():
s.queue_free() # remove the node and delete it while nothing is happening
Instancing scenes
-----------------
Instancing a scene from code is pretty easy and done in two steps. The
first one is to load the scene from disk.
::
var scene = load("res://myscene.scn") # will load when the script is instanced
Preloading it can be more convenient sometimes, as it happens at parse
time.
::
var scene = preload("res://myscene.scn") # will load when parsing the script
But 'scene' is not yet a node containing subnodes. It's packed in a
special resource called :ref:`PackedScene <class_PackedScene>`.
To create the actual node, the function
:ref:`PackedScene.instance() <class_PackedScene_instance>`
must be called. This will return the tree of nodes that can be added to
the active scene:
::
var node = scene.instance()
add_child(node)
The advantage of this two-step process is that a packed scene may be
kept loaded and ready to use, so it can be used to create as many
instances as desired. This is especially useful to quickly instance
several enemies, bullets, etc. in the active scene.

View File

@@ -0,0 +1,271 @@
.. _doc_simple_2d_game:
Simple 2D game
==============
Pong
~~~~
In this tutorial, a basic game of Pong will be created. There are plenty
of more complex examples in the demos included with the engine, but this
should get you introduced to the basic functionalities for 2D Games.
To begin with, run the Godot Engine and start a new project.
Assets
~~~~~~
Some assets are included for this tutorial:
:download:`pong_assets.zip </files/pong_assets.zip>`. Unzip its content
in your project folder.
Scene setup
~~~~~~~~~~~
For the sake of the old times, the game will be in 640x400 pixels
resolution. This can be configured in the Project Settings (see
:ref:`doc_scenes_and_nodes-configuring_the_project`) under Scene/Project
settings menu. The default background color should be set to black:
.. image:: /img/clearcolor.png
Create a :ref:`class_Node2D` node for the project root. Node2D is the
base type for the 2D engine. After this, add some sprites
(:ref:`class_Sprite` node) for the left and right paddles, the separator
and ball. You can set a custom name for each node, and set the texture
for each sprite in the Inspector.
.. image:: /img/pong_nodes.png
Set nodes positions:
- "left" node: (67, 183)
- "right" node: (577, 187)
- "separator" node: (320, 200)
- "ball" node: (320, 188)
The final scene layout should look similar to this (note: the ball is in
the middle!):
.. image:: /img/pong_layout.png
Save the scene as "pong.tscn" and set it as the main scene in the
project
properties.
.. _doc_simple_2d_game-input_actions_setup:
Input actions setup
~~~~~~~~~~~~~~~~~~~
Video games can be played using various input methods: Keyboard, Joypad,
Mouse, Touchscreen (multitouch)... Godot is able to use them all.
However, it would be interesting to define the inputs as "Input Actions"
instead of hardware actions that you'd manage separately. This way, any
input method can be used: each of them only require the user to connect
buttons to game actions that you defined.
This is Pong. The only input that matters is for the pads going up and
down.
Open the project properties dialog again (Scene/Project settings), but
this time move to the
"Input Map" tab.
In this tab, add 4 actions:
``left_move_up``, ``left_move_down``, ``right_move_up``,
``right_move_down``.
Assign the keys that you desire. A/Z (for the left player) and Up/Down
(for the right player) as keys
should work in most cases.
.. image:: /img/inputmap.png
Script
~~~~~~
Create a script for the root node of the scene and open it (as explained
in :ref:`doc_scripting-adding_a_script`). This script inherits Node2D:
::
extends Node2D
func _ready():
pass
First things first, we need to define some members for our script so it
can store useful values. Such values are the dimensions of the screen, the pad
and the initial direction of the ball.
::
extends Node2D
# Member variables
var screen_size
var pad_size
var direction = Vector2(1.0, 0.0)
func _ready():
pass
As you know, the ``_ready()`` function is the first function called
(after ``_enter_tree()`` which we don't need here). In this function,
two things have to be done. The first one is to enable
processing: this is the purpose of the ``set_process(true)`` function.
The second one is to initalize our two member variables.
::
extends Node2D
# Member variables
var screen_size
var pad_size
var direction = Vector2(1.0, 0.0)
func _ready():
screen_size = get_viewport_rect().size
pad_size = get_node("left").get_texture().get_size()
set_process(true)
We initialize the ``pad_size`` variable by getting one of the pads nodes
(the left one here), and obtain its texture size. The ``screen_size`` is
initialized using the ``get_viewport_rect()`` which returns a Rect
object corresponding to the game window, and we store its size.
Now, we need to add some other members to our script in order to make
our ball move.
::
extends Node2D
# Member variables
var screen_size
var pad_size
var direction = Vector2(1.0, 0.0)
# Constant for pad speed (in pixels/second)
const INITIAL_BALL_SPEED = 80
# Speed of the ball (also in pixels/second)
var ball_speed = INITIAL_BALL_SPEED
# Constant for pads speed
const PAD_SPEED = 150
func _ready():
screen_size = get_viewport_rect().size
pad_size = get_node("left").get_texture().get_size()
set_process(true)
Finally, the ``_process()`` function. All the code below is contained by
this function.
We have to init some useful values for computation. The first one is the
ball position (from the node), the second one is the rectangle
(``Rect2``) for each pad. These rectangles will be used for collision
tests between the ball and the pads. Sprites center their textures by
default, so a small adjustment of ``pad_size / 2`` must be added.
::
func _process(delta):
var ball_pos = get_node("ball").get_pos()
var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size )
var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size )
Now, let's add some movement to the ball in the ``_process()`` function.
Since the ball position is stored in the ``ball_pos`` variable,
integrating it is simple:
::
# Integrate new ball postion
ball_pos += direction * ball_speed * delta
This code line is called at each iteration of the ``_process()``
function. That means the ball position will be updated at each new
frame.
Now that the ball has a new position, we need to test if it
collides with anything, that is the window borders and the pads. First,
the floor and the roof:
::
# Flip when touching roof or floor
if ((ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0)):
direction.y = -direction.y
Second, the pads: if one of the pads is touched, we need to invert the
direction of the ball on the X axis so it goes back, and define a new
random Y direction using the ``randf()`` function. We also increase its
speed a little.
::
# Flip, change direction and increase speed when touching pads
if ((left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
direction.x = -direction.x
direction.y = randf()*2.0 - 1
direction = direction.normalized()
ball_speed *= 1.1
Finally, if the ball went out of the screen, it's game over. That is, we test if
the X position of the ball is less than 0 or greater than the screen
width. If so, the game restarts:
::
# Check gameover
if (ball_pos.x < 0 or ball_pos.x > screen_size.x):
ball_pos = screen_size*0.5
ball_speed = INITIAL_BALL_SPEED
direction = Vector2(-1, 0)
Once everything is done, the node is updated with the new position of
the ball, which was computed before:
::
get_node("ball").set_pos(ball_pos)
Next, we allow the pads to move. We only update their position according
to player input. This is done using the Input class:
::
# Move left pad
var left_pos = get_node("left").get_pos()
if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
left_pos.y += -PAD_SPEED * delta
if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
left_pos.y += PAD_SPEED * delta
get_node("left").set_pos(left_pos)
# Move right pad
var right_pos = get_node("right").get_pos()
if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
right_pos.y += -PAD_SPEED * delta
if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
right_pos.y += PAD_SPEED * delta
get_node("right").set_pos(right_pos)
We use the four actions previously defined in the Input actions setup
section above. When the player activates the respective key, the
corresponding action is triggered. As soon as this happens, we simply
compute a new position for the pad in the desired direction and apply it
to the node.
That's it! A simple Pong was written with a few lines of code.

View File

@@ -0,0 +1,178 @@
.. _doc_singletons_autoload:
Singletons (AutoLoad)
=====================
Introduction
------------
Scene singletons are very useful, catering to a common use case where you need
to store persistent information between scenes.
Albeit very powerful, the scene system by itself has a few drawbacks:
- There is no common place to store information (e.g. a player's items etc.)
required by more than one scene.
- While it is possible for a scene that loads and unloads other scenes as
its children to store information common to these child scenes, it is no
longer possible to run these scenes by themselves and expect them to work
correctly.
- While information can be stored to disk in \`user://\` and this information
can be loaded by scenes that require it, continuously saving and loading this
data when changing scenes is cumbersome and may be slow.
However there is still a need in Godot to create parts of a scene that:
- Are always loaded, no matter which scene is opened from the editor
- Can store global variables, such as player information, items, money
etc. and share information between scenes
- Can handle switching scenes and transitions
- Acts like a singleton, since GDScript does not support global variables by design.
Auto-loading nodes and scripts caters to this need.
AutoLoad
--------
You can use AutoLoad to load a scene, or a script that inherits from Node (a node
will be created and the script will be set to it).
To autoload a scene or script, select Scene > Project Settings from the menu and switch
to the AutoLoad tab. Each entry in the list requires a name, which is used as the name
of the node, and the node is always added to the root viewport before any other scenes
are loaded.
.. image:: /img/singleton.png
This means that any node can access a singleton named "playervariables" with:
::
var player_vars = get_node("/root/playervariables")
Custom scene switcher
---------------------
This short tutorial will explain how to make a scene switcher using
autoload. For simple scene switching, the
:ref:`SceneTree.change_scene() <class_SceneTree_change_scene>`
method suffices (described in :ref:`doc_scene_tree`), so this method is for
more complex behavior when switching between scenes.
First download the template from here:
:download:`autoload.zip </files/autoload.zip>`, then open it.
Two scenes are present, scene_a.scn and scene_b.scn on an otherwise
empty project. Each are identical and contain a button connected to a
callback for switching to the other scene. When the project runs, it
starts in scene_a.scn. However, this currently does nothing and pressing the
button does not work.
global.gd
---------
First of all, create a global.gd script. The easy way to create a
resource from scratch is from the new resource button in the inspector tab:
.. image:: /img/newscript.png
Save the script as `global.gd`:
.. image:: /img/saveasscript.png
The script should open in the script editor. The next step is to add
it to AutoLoad list. Select Scene > Project Settings from the menu,
switch to the AutoLoad tab and add a new entry with name "global" that
points to this file:
.. image:: /img/addglobal.png
Now, whenever you run any of your scenes, the script is always loaded.
Returning to our script, the current scene needs to be fetched in the
`_ready()` function. Both the current scene and `global.gd` are children of
root, but the autoloaded nodes are always first. This means that the
last child of root is always the loaded scene.
Note: Make sure that global.gd extends Node, otherwise it won't be
loaded!
::
extends Node
var current_scene = null
func _ready():
var root = get_tree().get_root()
current_scene = root.get_child( root.get_child_count() -1 )
Next up is the function for changing the scene. This function frees the
current scene and replaces it with the requested one.
::
func goto_scene(path):
# This function will usually be called from a signal callback,
# or some other function from the running scene.
# Deleting the current scene at this point might be
# a bad idea, because it may be inside of a callback or function of it.
# The worst case will be a crash or unexpected behavior.
# The way around this is deferring the load to a later time, when
# it is ensured that no code from the current scene is running:
call_deferred("_deferred_goto_scene",path)
func _deferred_goto_scene(path):
# Immediately free the current scene,
# there is no risk here.
current_scene.free()
# Load new scene
var s = ResourceLoader.load(path)
# Instance the new scene
current_scene = s.instance()
# Add it to the active scene, as child of root
get_tree().get_root().add_child(current_scene)
# optional, to make it compatible with the SceneTree.change_scene() API
get_tree().set_current_scene( current_scene )
As mentioned in the comments above, we really want to avoid the
situation of having the current scene being deleted while being used
(code from functions of it being run), so using
:ref:`Object.call_deferred() <class_Object_call_deferred>`
is desired at this point. The result is that execution of the commands
in the second function will happen at a later time when no code from
the current scene is running.
Finally, all that is left is to fill the empty functions in scene_a.gd
and scene_b.gd:
::
#add to scene_a.gd
func _on_goto_scene_pressed():
get_node("/root/global").goto_scene("res://scene_b.scn")
and
::
#add to scene_b.gd
func _on_goto_scene_pressed():
get_node("/root/global").goto_scene("res://scene_a.scn")
Now if you run the project, you can switch between both scenes by pressing
the button!
To load scenes with a progress bar, check out the next tutorial,
:ref:`doc_background_loading`

View File

@@ -0,0 +1,43 @@
.. _doc_splash_screen:
Splash screen
=============
Tutorial
--------
This is a simple tutorial to establish the basic idea of how the GUI
subsystem works. The goal is to create a really simple, static
splash screen.
Following is a file with the assets that will be used. These can be added directly to your project folder - no need to import them:
:download:`robisplash_assets.zip </files/robisplash_assets.zip>`.
Setting up
----------
Set the display resolution to 800x450 in Project Settings, and set up a new scene like this:
.. image:: /img/robisplashscene.png
.. image:: /img/robisplashpreview.png
The nodes "background" and "logo" are of :ref:`TextureFrame <class_TextureFrame>`
type. These have a special property for setting the texture to be
displayed, just load the corresponding file.
.. image:: /img/texframe.png
The node "start" is a :ref:`TextureButton <class_TextureButton>`.
It takes several images for different states, but only the normal and
pressed will be supplied in this example:
.. image:: /img/texbutton.png
Finally, the node "copyright" is a :ref:`Label <class_Label>`.
A custom font can be set for labels by editing the following property:
.. image:: /img/label.png
As a side note, the font was imported from a TTF, see :ref:`doc_importing_fonts`.

View File

@@ -0,0 +1,478 @@
.. _doc_gdscript_more_efficiently:
GDScript more efficiently
=========================
About
-----
This tutorial aims to be a quick reference for how to use GDScript more
efficiently. It focuses in common cases specific to the language, but
also covers a lot related to using dynamically typed languages.
It's meant to be specially useful for programmers without previous or
little experience of dynamically typed languages.
Dynamic nature
--------------
Pros & cons of dynamic typing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
GDScript is a Dynamically Typed language. As such, it's main advantages
are that:
- Language is very simple to learn.
- Most code can be written and changed quickly and without hassle.
- Less code written means less errors & mistakes to fix.
- Easier to read the code (less clutter).
- No compilation is required to test.
- Runtime is tiny.
- Duck-typing and polymorphism by nature.
While the main cons are:
- Less performance than statically typed languages.
- More difficult to refactor (symbols can't be traced)
- Some errors that would typically be detected at compile time in
statically typed languages only appear while running the code
(because expression parsing is more strict).
- Less flexibility for code-completion (some variable types are only
known at run-time).
This, translated to reality, means that Godot+GDScript are a combination
designed to games very quickly and efficiently. For games that are very
computationally intensive and can't benefit from the engine built-in
tools (such as the Vector types, Physics Engine, Math library, etc), the
possibility of using C++ is present too. This allows to still create the
entire game in GDScript and add small bits of C++ in the areas that need
a boost.
Variables & assignment
~~~~~~~~~~~~~~~~~~~~~~
All variables in a dynamically typed language are "variant"-like. This
means that their type is not fixed, and is only modified through
assignment. Example:
Static:
::
int a; // value uninitialized
a = 5; // this is valid
a = "Hi!"; // this is invalid
Dynamic:
::
var a # null by default
a = 5 # valid, 'a' becomes an integer
a = "Hi!" # valid, 'a' changed to a string
As function arguments:
~~~~~~~~~~~~~~~~~~~~~~
Functions are of dynamic nature too, which means they can be called with
different arguments, for example:
Static:
::
void print_value(int value)
{
printf("value is %i\n",value);
}
[..]
print_value(55); // valid
print_value("Hello"); // invalid
Dynamic:
::
func print_value(value):
print(value)
[..]
print_value(55) # valid
print_value("Hello") # valid
Pointers & referencing:
~~~~~~~~~~~~~~~~~~~~~~~
In static languages such as C or C++ (and to some extent Java and C#),
there is a distinction between a variable and a pointer/reference to a
variable. The later allows the object to be modified by other functions
by passing a reference to the original one.
In C# or Java, everything not a built-in type (int, float, sometimes
String) is always a pointer or a reference. References are also
garbage-collected automatically, which means they are erased when no
longer used. Dynamically typed languages tend to use this memory model
too. Some Examples:
- C++:
.. code:: cpp
void use_class(SomeClass *instance) {
instance->use();
}
void do_something() {
SomeClass *instance = new SomeClass; // created as pointer
use_class(instance); // passed as pointer
delete instance; // otherwise it will leak memory
}
- Java:
.. code:: java
@Override
public final void use_class(SomeClass instance) {
instance.use();
}
public final void do_something() {
SomeClass instance = new SomeClass(); // created as reference
use_class(instance); // passed as reference
// garbage collector will get rid of it when not in
// use and freeze your game randomly for a second
}
- GDScript:
::
func use_class(instance); # does not care about class type
instance.use() # will work with any class that has a ".use()" method.
func do_something():
var instance = SomeClass.new() # created as reference
use_class(instance) # passed as reference
# will be unreferenced and deleted
In GDScript, only base types (int, float, string and the vector types)
are passed by value to functions (value is copied). Everything else
(instances, arrays, dictionaries, etc) is passed as reference. Classes
that inherit :ref:`class_Reference` (the default if nothing is specified)
will be freed when not used, but manual memory management is allowed too
if inheriting manually from :ref:`class_Object`.
Arrays
------
Arrays in dynamically typed languages can contain many different mixed
datatypes inside and are always dynamic (can be resized at any time).
Compare for example arrays in statically typed languages:
::
int *array = new int[4]; // create array
array[0] = 10; // initialize manually
array[1] = 20; // can't mix types
array[2] = 40;
array[3] = 60;
// can't resize
use_array(array); // passed as pointer
delete[] array; // must be freed
//or
std::vector<int> array;
array.resize(4);
array[0] = 10; // initialize manually
array[1] = 20; // can't mix types
array[2] = 40;
array[3] = 60;
array.resize(3); // can be resized
use_array(array); // passed reference or value
// freed when stack ends
And in GDScript:
::
var array = [10, "hello", 40, 60] # simple, and can mix types
array.resize(3) # can be resized
use_array(array) # passed as reference
# freed when no longer in use
In dynamically typed languages, arrays can also double as other
datatypes, such as lists:
::
var array = []
array.append(4)
array.append(5)
array.pop_front()
Or unordered sets:
::
var a = 20
if a in [10, 20, 30]:
print("We have a winner!")
Dictionaries
------------
Dictionaries are always a very powerful in dynamically typed languages.
Most programmers that come from statically typed languages (such as C++
or C#) ignore their existence and make their life unnecessarily more
difficult. This datatype is generally not present in such languages (or
only on limited form).
Dictionaries can map any value to any other value with complete
disregard for the datatype used as either key or value. Contrary to
popular belief, they are very efficient because they can be implemented
with hash tables. They are, in fact, so efficient that some languages
will go as far as implementing arrays as dictionaries.
Example of Dictionary:
::
var d = { "name": "john", "age": 22 } # simple syntax
print("Name: ", d["name"], " Age: ", d["age"])
Dictionaries are also dynamic, keys can be added or removed at any point
at little cost:
::
d["mother"] = "Rebecca" # addition
d["age"] = 11 # modification
d.erase("name") # removal
In most cases, two-dimensional arrays can often be implemented more
easily with dictionaries. Here's a simple battleship game example:
::
# battleship game
const SHIP = 0
const SHIP_HIT = 1
const WATER_HIT = 2
var board = {}
func initialize():
board[Vector(1,1)] = SHIP
board[Vector(1,2)] = SHIP
board[Vector(1,3)] = SHIP
func missile(pos):
if pos in board: # something at that pos
if board[pos] == SHIP: # there was a ship! hit it
board[pos] = SHIP_HIT
else:
print("already hit here!") # hey dude you already hit here
else: # nothing, mark as water
board[pos] = WATER_HIT
func game():
initialize()
missile(Vector2(1,1))
missile(Vector2(5,8))
missile(Vector2(2,3))
Dictionaries can also be used as data markup or quick structures. While
GDScript dictionaries resemble python dictionaries, it also supports Lua
style syntax an indexing, which makes it very useful for writing initial
states and quick structs:
::
# same example, lua-style support
# this syntax is a lot more readable and usable
var d = {
name = "john",
age = 22
}
print("Name: ", d.name, " Age: ", d.age) # used "." based indexing
# indexing
d.mother = "rebecca" # this doesn't work (use syntax below to add a key:value pair)
d["mother"] = "rebecca" # this works
d.name = "caroline" # if key exists, assignment does work, this is why it's like a quick struct.
For & while
-----------
Iterating in some statically typed languages can be quite complex:
::
const char* strings = new const char*[50];
[..]
for(int i=0; i<50; i++)
{
printf("value: %s\n", i, strings[i]);
}
// even in STL:
for(std::list<std::string>::const_iterator it = strings.begin(); it != strings.end(); it++) {
std::cout << *it << std::endl;
}
This is usually greatly simplified in dynamically typed languages:
::
for s in strings:
print(s)
Container datatypes (arrays and dictionaries) are iterable. Dictionaries
allow iterating the keys:
::
for key in dict:
print(key, " -> ", dict[key])
Iterating with indices is also possible:
::
for i in range(strings.size()):
print(strings[i])
The range() function can take 3 arguments:
::
range(n) (will go from 0 to n-1)
range(b, n) (will go from b to n-1)
range(b, n, s) (will go from b to n-1, in steps of s)
Some examples:
::
for(int i=0; i<10; i++) {}
for(int i=5; i<10; i++) {}
for(int i=5; i<10; i+=2) {}
Translate to:
::
for i in range(10):
for i in range(5, 10):
for i in range(5, 10, 2):
And backwards looping is done through a negative counter:
::
for(int i=10; i>0; i--) {}
becomes
::
for i in range(10, 0, -1):
While
-----
while() loops are the same everywhere:
::
var i = 0
while(i < strings.size()):
print(strings[i])
i += 1
Duck typing
-----------
One of the most difficult concepts to grasp when moving from a
statically typed language to a dynamic one is duck typing. Duck typing
makes overall code design much simpler and straightforward to write, but
it's not obvious how it works.
As an example, imagine a situation where a big rock is falling down a
tunnel, smashing everything on its way. The code for the rock, in a
statically typed language would be something like:
::
void BigRollingRock::on_object_hit(Smashable *entity)
{
entity->smash();
}
This, way, everything that can be smashed by a rock would have to
inherit Smashable. If a character, enemy, piece of furniture, small rock
were all smashable, they would need to inherit from the class Smashable,
possibly requiring multiple inheritance. If multiple inheritance was
undesired, then they would have to inherit a common class like Entity.
Yet, it would not be very elegant to add a virtual method ``smash()`` to
Entity only if a few of them can be smashed.
With dynamically typed languages, this is not a problem. Duck typing
makes sure you only have to define a ``smash()`` function where required
and that's it. No need to consider inheritance, base classes, etc.
::
func _on_object_hit(object):
object.smash()
And that's it. If the object that hit the big rock has a smash() method,
it will be called. No need for inheritance or polymorphism. Dynamically
typed languages only care about the instance having the desired method
or member, not what it inherits or the class type. The definition of
Duck Typing should make this clearer:
*"When I see a bird that walks like a duck and swims like a duck and
quacks like a duck, I call that bird a duck"*
In this case, it translates to:
*"If the object can be smashed, don't care what it is, just smash it."*
Yes, we should call it Hulk typing instead. Anyway though, there exists
the possibility of the object being hit not having a smash() function.
Some dynamically typed languages simply ignore a method call when it
doesn't exist (like Objective C), but GDScript is more strict, so
checking if the function exists is desirable:
::
func _on_object_hit(object):
if (object.has_method("smash")):
object.smash()
Then, simply define that method and anything the rock touches can be
smashed.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
.. _doc_gdscript_printf:
GDScript format strings
=======================
GDScript offers a feature called *format strings* which allows reusing text
templates to succinctly create different but similar strings.
Format strings are just like normal strings, except they contain certain
placeholder character-sequences. These placeholders can then easily be replaced
by parameters handed to the format string.
As an example, with ``%s`` as a placeholder, the format string ``"Hello %s, how
are you?`` can easily be changed to ``"Hello World, how are you?"``. Notice
the placeholder is in the middle of the string; modifying it without format
strings could be cumbersome.
Usage in GDScript
-----------------
Examine this concrete GDScript example::
# Define a format string with placeholder '%s'
var format_string = "We're waiting for %s."
# Using the '%' operator, the placeholder is replaced with the desired value
var actual_string = format_string % "Godot"
print(actual_string)
# output: "We're waiting for Godot."
Placeholders always start with a ``%``, but the next character or characters,
the *format specifier*, determines how the given value is converted to a
string.
The ``%s`` seen in the example above is the simplest placeholder and works for
most use cases: it converts the value by the same method by which an implicit
String conversion or ``str()`` would convert it. Strings remain unchanged,
Booleans turn into either ``"True"`` or ``"False"``, an integral or real number
becomes a decimal, other types usually return their data in a human-readable
string.
There are other `format specifiers`_.
Multiple placeholders
---------------------
Format strings may contain multiple placeholders. In such a case, the values
are handed in the form of an array, one value per placeholder (unless using a
format specifier with ``*``, see `dynamic padding`_)::
var format_string = "%s was reluctant to learn %s, but now he enjoys it."
var actual_string = format_string % ["Estragon", "GDScript"]
print(actual_string)
# output: "Estragon was reluctant to learn GDScript, but now he enjoys it."
Note the values are inserted in order. Remember all placeholders must be
replaced at once, so there must be an appropriate number of values.
Format specifiers
-----------------
There are format specifiers other than ``s`` that can be used in placeholders.
They consist of one or more characters. Some of them work by themselves like
``s``, some appear before other characters, some only work with certain
values or characters.
Placeholder types
~~~~~~~~~~~~~~~~~
One and only one of these must always appear as the last character in a format
specifier. Apart from ``s``, these require certain types of parameters.
+-------+---------------------------------------------------------------------+
| ``s`` | **Simple** conversion to String by the same method as implicit |
| | String conversion. |
+-------+---------------------------------------------------------------------+
| ``c`` | A single **Unicode character**. Expects an unsigned 8-bit integer |
| | (0-255) for a code point or a single-character string. |
+-------+---------------------------------------------------------------------+
| ``d`` | A **decimal integral** number. Expects an integral or real number |
| | (will be floored). |
+-------+---------------------------------------------------------------------+
| ``o`` | An **octal integral** number. Expects an integral or real number |
| | (will be floored). |
+-------+---------------------------------------------------------------------+
| ``x`` | A **hexadecimal integral** number with **lower-case** letters. |
| | Expects an integral or real number (will be floored). |
+-------+---------------------------------------------------------------------+
| ``X`` | A **hexadecimal integral** number with **upper-case** letters. |
| | Expects an integral or real number (will be floored). |
+-------+---------------------------------------------------------------------+
| ``f`` | A **decimal real** number. Expects an integral or real number. |
+-------+---------------------------------------------------------------------+
Placeholder modifiers
~~~~~~~~~~~~~~~~~~~~~
These characters appear before the above. Some of them work only under certain
conditions.
+---------+-------------------------------------------------------------------+
| ``+`` | In number specifiers, **show + sign** if positive. |
+---------+-------------------------------------------------------------------+
| Integer | Set **padding**. Padded with spaces or with zeroes if integer |
| | starts with ``0`` in an integer placeholder. When used after |
| | ``.``, see ``.``. |
+---------+-------------------------------------------------------------------+
| ``.`` | Before ``f``, set **precision** to 0 decimal places. Can be |
| | followed up with numbers to change. Padded with zeroes. |
+---------+-------------------------------------------------------------------+
| ``-`` | **Pad to the right** rather than the left. |
+---------+-------------------------------------------------------------------+
| ``*`` | **Dynamic padding**, expect additional integral parameter to set |
| | padding or precision after ``.``, see `dynamic padding`_. |
+---------+-------------------------------------------------------------------+
Padding
-------
The ``.`` (*dot*), ``*`` (*asterisk*), ``-`` (*minus sign*) and digit
(``0``-``9``) characters are used for padding. This allows printing several
values aligned vertically as if in a column, provided a fixed-width font is
used.
To pad a string to a minimum length, add an integer to the specifier::
print("%10d" % 12345)
# output: " 12345"
# 5 leading spaces for a total length of 10
If the integer starts with ``0``, integral values are padded with zeroes
instead of white space::
print("%010d" % 12345)
# output: "0000012345"
Precision can be specified for real numbers by adding a ``.`` (*dot*) with an
integer following it. With no integer after ``.``, a precision of 0 is used,
rounding to integral value. The integer to use for padding must appear before
the dot.
::
# pad to minimum length of 10, round to 3 decimal places
print("%10.3f" % 10000.5555)
# output: " 10000.556"
# 1 leading space
The ``-`` character will cause padding to the right rather than the left,
useful for right text alignment::
print("%-10d" % 12345678)
# output: "12345678 "
# 2 trailing spaces
Dynamic padding
~~~~~~~~~~~~~~~
By using the ``*`` (*asterisk*) character, the padding or precision can be set
without modifying the format string. It is used in place of an integer in the
format specifier. The values for padding and precision are then passed when
formatting::
var format_string = "%*.*f"
# pad to length of 7, round to 3 decimal places:
print(format_string % [7, 3, 8.8888])
# output: " 8.889"
# 2 leading spaces
It is still possible to pad with zeroes in integer placeholders by adding ``0``
before ``*``::
print("%0*d" % [2, 3])
#output: "03"
Escape sequence
---------------
To insert a literal ``%`` character into a format string, it must be escaped to
avoid reading it as a placeholder. This is done by doubling the character::
var health = 56
print("Remaining health: %d%%" % health)
# output: "Remaining health: 56%"

View File

@@ -0,0 +1,67 @@
.. _doc_exporting_images:
Exporting images
================
It is often desired to do an operation to all or a group of images upon
export. Godot provides some tools for this. Examples of such operations
are:
- Converting all images from a lossless format to a lossy one (ie: png
-> WebP) for greater compression.
- Shrinking all images to half the size, to create a low resolution
build for smaller screens.
- Create an atlas for a group of images and crop them, for higher
performance and less memory usage.
Image export options
--------------------
In the "Project Export Settings" dialog, go to the Images tab:
.. image:: /img/exportimages.png
In this dialog the image extensions for conversion can be selected, and
operations can be performed that apply to all images (except those in
groups, see the next section for those):
- **Convert Image Format**: Probably the most useful operation is to
convert to Lossy (WebP) to save disk space. For lossy, a Quality bar
can set the quality/vs size ratio.
- **Shrink**: This allows to shrink all images by a given amount. It's
useful to export a game to half or less resolution for special
devices.
- **Compress Formats**: Allows to select which image exensions to
convert.
On export, Godot will perform the desired operation. The first export
might be really slow, but subsequent exports will be fast, as the
converted images will be cached.
Image group export options
--------------------------
This section is similar to the previous one, except it can operate on a
selected group of images. When a image is in a group, the settings from
the global export options are overridden by the ones from the group. An
image can only be in one group at the same time. So if the image is in
another group different to the current one being edited, it will not be
selectable.
.. image:: /img/imagegroup.png
Atlas
~~~~~
Grouping images allows a texture atlas to be created. When this mode is
active, a button to preview the resulting atlas becomes available. Make
sure that atlases don't become too big, as some hardware will not
support textures bigger than 2048x2048 pixels. If this happens, just
create another atlas.
The atlas can be useful to speed up drawing of some scenes, as state
changes are minimized when drawing from it (through unlike other
engines, Godot is designed so state changes do not affect it as much).
Textures added to an atlas get cropped (empty spaces around the image
are removed), so this is another reason to use them (save space). If
unsure, though, just leave that option disabled.

View File

@@ -0,0 +1,167 @@
.. _doc_import_process:
Import process
==============
What is it for?
---------------
When Godot was created, it was probably after several failed and not so
failed engine attempts (well, each attempt failed a little less.. and so
on). One of the most difficult areas of creating game engines is
managing the import process. That means, getting the assets that artists
make into the game, in a way that functions optimally.
Artists use certain tools and formats, and programmers would rather have
their data into a different format. This is because artists put their
focus on creating assets with the best quality possible, while
programmers have to make sure they actually run at decent speed (or run
at all), use a certain amount of memory, and don't take ages loading
from disk.
One would think that just writing a converter/importer would be enough,
but this is not all there is to it. The same way programmers iterate
several times over their code, artists keep making changes to their
assets. This generates some bottleneck, because *someone* has to keep
re-importing that artwork right? And importing assets is often something
that has to be agreed by both parties, as the programmer needs to decide
how the artwork is imported and the artists needs to see how it looks.
The goal to establishing an import process is that both can agree on how
the rules under which the assets are going to be imported the first
time, and the system will apply those rules automatically each time the
asset is re-imported.
Godot does not do the re-import process automatically, though. It gives
the team the option to do it at any time ( a red icon on the top right
of the screen, allows the ability to do it at any desired time).
Does it always work?
--------------------
The aim of the import system is that it works well enough for most
common cases and projects. What is there has been tested and seems to
cover most needs.
However, as mentioned before, this is one of the most difficult areas of
writing a game engine. It may happen often (specially on large projects,
ports, or projects with unusual requirement) that what is provided is
not enough. It's easy to say that the engine is open source and that the
programmer should make their own if they don't like what is there, but
that would be making a huge disservice to the users and not the right
attitude. Because of that, we made sure to provide as many tools and
helpers as possible to support a custom import process, for example:
- Access to the internals of almost all data structures is provided to
the scripting and C++ API, as well as saving and loading in all
supported file formats.
- Some importers (like the 3D asset importer) support scripts to modify
the data being imported.
- Support for creating custom import plugins is also provided, even for
replacing the existing ones.
- If all else fails, Godot supports adding custom resource loaders,
to load data in alternative formats, without intermediate conversion.
Both the import system and the custom tools provided will improve over
time as more use cases are revealed to us.
Importing assets
----------------
Source asset location
~~~~~~~~~~~~~~~~~~~~~
To begin, it is a good idea to define where the original assets created
by the artists (before they are imported) will be located. Normally,
Godot does not mind much about the location, but if the project has
several developers, it is a good idea to understand the simple rule for
it to work for everyone.
First of all, it would be really good for this location to **not** be
inside the project path (where engine.cfg is located, or any
sub-folder). Godot expects regular resources in there, and may consider
many of the files used as source art as regular resources. This would
lead to it bundling all of them when the project is exported, something
which is undesired.
Now that it is clear that this location must be outside the project
folder, the rule that Godot uses to reference external assets can be
explained. When an asset is imported, the engine stores a relative path
from the project path to the asset (In windows, this works as long as
they are on the same drive, otherwise an absolute path is stored). This
ensures that the same asset can be re-imported in another computer.
The usual approach to this, when using a VCS such as Subversion,
Perforce or GIT, is to create the project in a subfolder, so both it and
the source assets can be committed to a same repository. For example:
Repository layout:
::
source_assets/sfx/explosion.wav
source_assets/sfx/crash.wav
source_assets/fonts/myfont.ttf
source_assets/translation/strings.csv
source_assets/art/niceart.psd
game/engine.cfg
In the above example, artists, musician, translators, etc. can work in
the source_assets/ folder, then import the assets to the game/ folder.
When the repository is updated, anyone can re-import the assets if they
changed.
Import dialogs
~~~~~~~~~~~~~~
Godot provides for importing several types of assets, all of them can be
accessed from the import dialog:
.. image:: /img/import.png
Each of the dialog shares a similar function, a source file (or several
of them) must be provided, as well as a target destination inside the
project folders. Once imported, Godot saves this information as metadata
in the imported asset itself.
.. image:: /img/importdialogs.png
More information about each specific type of asset can be found in
specific sections, such as `Importing Textures <import_textures>`__.
Tracking changes and re-importing
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Godot tracks changes in the source assets constantly. If at least one
asset has been found to be modified (md5 is different than when it was
imported), a small red indicator will appear in the top right corner of
the screen.
.. image:: /img/changes.png
From that moment onward, the user can choose to re-import at any given
time by clicking on the red-icon. When this action is done, a dialog
will pop-up showing which resources can be re-imported (all selected
by default).
Accepting that dialog will immediately re-import the resources and
will update any of them currently in use in the editor (like a
texture, model or audio file).
.. image:: /img/changed.png
Manually re-importing
~~~~~~~~~~~~~~~~~~~~~
The re-import process is automatic, but it may be desired at some point
to change the settings of an already imported file, so it can be
re-imported differently. For this, the Import Settings window is
provided.
.. image:: /img/isettings.png
This screen allows the user to re-open the corresponding import-window
to re-import that asset again, with the ability to change any of the
settings.
.. image:: /img/reimported.png

View File

@@ -0,0 +1,113 @@
.. _doc_importing_audio_samples:
Importing audio samples
=======================
Why importing?
--------------
Importing Audio Samples into the game engine is a process that should be
easier than it really is. Most readers are probably thinking "Why not
just copy the wav files to a folder inside the project and be over
with it?"
It's not usually that simple. Most game engines use uncompressed audio
(in memory, at least) for sound effects. The reason for this is because
it's really cheap to play back and resample. Compressed streamed audio
(such as ogg files) takes a large amount of processor to decode so no
more than one or two are streamed simultaneously. However, with sound
effects, one expects a dozen of them to be playing at the same time in
several situations.
Because of this, sound effects are loaded uncompressed into memory, and
here is where the problems begin.
As is usual with graphics, the situation where programmers don't really
know about audio and audio engineers don't know about programming is
also common in the industry. This leads to a scenario where a project
ends up wasting resources unnecessarily.
To be more precise, SFX artists tend to work with audio formats that
give them a lot of room for tweaking the audio with a low noise floor and
minimum aliasing, such as 96kHz, 24 bits. In many cases, they work in
stereo too. Added to that, many times they add effects with an infinite
or really long fadeout, such as reverb, which leads to apparent trailing
silences. Finally, many DAWs also add silence at the beginning when
normalizing to wav.
These often result in extremely large files to integration into a game engine
with sound effects taking dozens of megabytes.
How much does quality matter?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
First of all, it is important to know that Godot has an internal reverb
generator. Sound effects can go to four different setups (small, medium
and large room, as well as hall), with different send amounts. This saves
SFX artists the need to add reverb to the sound effects, reducing their
size greatly and ensuring correct trimming. Say no to SFX with baked
reverb!
.. image:: /img/reverb.png
Another common problem is that, while it's useful for working inside a
DAW, high bit depths (24 bits) and high sampling rate (96kHz) are
completely unnecessary for use in a game, as there is no `audible
difference <http://www.youtube.com/watch?v=cIQ9IXSUzuM>`__. If
positional sound is going to be used (for 2D and 3D), the panning and
stereo reverb will be provided by the engine, so there is little need
for stereo sound. How does this affect the resource usage? Look at the
following comparison:
+---------------------------+---------------------+--------------+
| Format | 1 Second of Audio | Frame Size |
+===========================+=====================+==============+
| 24 bits, 96 kHz, Stereo | 576kb | 12 |
+---------------------------+---------------------+--------------+
| 16 bits, 44 kHz, Mono | 88kb | 2 |
+---------------------------+---------------------+--------------+
| 16 bits, IMA-ADPCM | 22kb | 1/2 |
+---------------------------+---------------------+--------------+
As seen, for being no audible difference, the 16 bits, 44kHz, mono conversion
takes *6 times less memory* than the 24 bits, 96kHz, Stereo version. The
IMA-ADPCM version (using computationally-light audio compression) takes *24
times less memory* than what was exported from the DAW.
Trimming
~~~~~~~~
One last issue that happens often is that the waveform files received
have silences at the beginning and at the end. These are inserted by
DAWs when saving to a waveform, increase their size unnecessarily and
add latency to the moment they are played back. Trimming them solves
this, but it takes effort for the SFX artist, as they have to do it in a
separate application. In the worst case, they may not even know the
silences are being added.
.. image:: /img/trim.png
Importing audio samples
-----------------------
Godot has a simple screen for importing audio samples to the engine. SFX
artists only have to save the wav files to a folder outside the
project, and the import dialog will fix the files for inclusion, as well
as doing it automatically every time they are modified and re-imported.
.. image:: /img/importaudio.png
In this screen, the quality of the audio can be limited to what is
needed, and trimming is done automatically. In addition, several samples
can be loaded and batch-converted, just as textures can.
Looping
~~~~~~~
Godot supports looping in the samples (Tools such as Sound Forge or
Audition can add loop points to wav files). This is useful for sound
effects such as engines, machine guns, etc. Ping-pong looping is also
supported.
As an alternative, the import screen has a "loop" option that enables
looping for the entire sample when importing.

View File

@@ -0,0 +1,115 @@
.. _doc_importing_fonts:
Importing fonts
===============
What is a font?
---------------
Fonts in modern operating systems are created as scalable vector
graphics. They are stored as a collection of curves (usually one for
each character), which are independent of the screen resolution, and
stored in standardized file formats, such as TTF (TrueType) or OTF
(OpenType).
Rendering such fonts to bitmaps is a complex process, which employs
different methods to convert curves to pixels depending on context and
target size. Due to this, this rendering process must be done by using
the CPU. Game engines use the GPU to render, and 3D APIs don't really
support the means to do this efficiently, so fonts have to be converted
to a format that is friendly to the GPU when imported to a project.
Converting fonts
----------------
This conversion process consists of rendering a vector font to a given
point size and storing all the resulting characters in a bitmap texture.
The bitmap texture is then used by the GPU to draw a small quad for each
character and form readable strings.
.. image:: /img/bitmapfont.png
The drawback of this process is that fonts must be pre-imported in the
specific sizes that they will use in the project. However, given that
that bitmap fonts compress really well, this is not as bad as it sounds.
Importing a font
----------------
Fonts are imported via the Font import dialog. The dialog will ask for a
font, a size, some options and a target resource file to save.
.. image:: /img/fontimport.png
The dialog is fully dynamic, which means that any change will be
reflected in the font preview window. The user can tweak almost every
parameter and get instant feedback on how the font will look.
Since the resulting font is a bitmap, a few more options were added to
make the imported font look even nicer. These options were added to
please graphic designers, who love putting gradients, outlines and
shadows in fonts, as well as changing all the inter-spaces available :).
These options will be explained in the next section.
Extra spacing
~~~~~~~~~~~~~
It is possible to add more space for:
- **Characters**, the space between them can be varied.
- **"space" character**, so the distance between words is bigger.
- **Top and Bottom margins**, this changes the spacing between lines as
well as the space between the top and bottom lines and the borders.
.. image:: /img/fontspacing.png
Shadows & outline
~~~~~~~~~~~~~~~~~
Fonts can have a shadow. For this, the font is drawn again, below the original,
in a different color, and then blurred with a Gaussian kernel of different
sizes. The resulting shadow can be adjusted with an exponential function
to make it softer or more like an outline. A second shadow is also
provided to create some added effects, like a bump or outline+shadow.
.. image:: /img/shadowoutline.png
Gradients
~~~~~~~~~
Gradients are also another of the visual effects that graphic designers
often use. To show how much we love them, we added those too. Gradients
can be provided as a simple curve between two colors, or a special png
file with a hand drawn gradient.
.. image:: /img/fontgradients.png
Internationalization
--------------------
Colors, shadows and gradients are beautiful, but it's time we get to
serious business. Developing games for Asian markets is a common
practice in today's globalized world and app stores.
Here's when things get tricky with using bitmap fonts. Asian alphabets
(Chinese, Japanese and Korean) contain dozens of thousands of
characters. Generating bitmap fonts with every single of them is pretty
expensive, as the resulting textures are huge. If the font size is small
enough, it can be done without much trouble, but when the fonts become
bigger, we run out of video ram pretty quickly!
To solve this, Godot allows the user to specify a text file (in UTF-8
format) where it expects to find all the characters that will be used in
the project. This seems difficult to provide at first, and more to keep
up to date, but it becomes rather easy when one realizes that the .csv
with the translations can be used as such source file (see the
:ref:`doc_importing_translations` section). As Godot re-imports assets when
their dependencies change, both the translation and font files will be
updated and re-imported automatically if the translation csv changes.
Another cool trick for using a text file as limit of which characters
can be imported is when using really large fonts. For example, the user
might want to use a super large font, but only to show numbers. For
this, he or she writes a numbers.txt file that contains "1234567890",
and Godot will only limit itself to import data, thus saving a lot of
video memory.

View File

@@ -0,0 +1,256 @@
.. _doc_importing_textures:
Importing textures
==================
Do NOT import them in most cases
--------------------------------
In most cases you **don't** want images imported when dealing with 2D
and GUI. Just copy them to the filesystem. Read the tutorial on
:ref:`doc_managing_image_files` before continuing! For 3D,
textures are always imported by the 3D scene importer, so importing
those is only useful when importing a texture used for 3D that doesn't
come with the 3D scene (for example, in a shader). The flags and options
are the same as here, so reading the rest of the document might help
too.
OK, you *might* want to import them
-----------------------------------
So, if you have read the previous tutorial on the texture exporter, the
texture importer gives you more fine-grained control on how textures
are imported. If you want to change flags such as repeat, filter,
mipmaps, fix edges, etc. ***PER texture***, importing them is the best
way to accomplish this (since you can't save such flags in a standard
image file).
Lack of MipMaps
---------------
Images in 3D hardware are scaled with a (bi)linear filter, but this
method has limitations. When images are shrunk too much, two problems
arise:
- **Aliasing**: Pixels are skipped too much, and the image shows
discontinuities. This decreases quality.
- **Cache Misses**: Pixels being read are too far apart, so texture
cache reads a lot more data than it should. This decreases
performance.
.. image:: /img/imagemipmap.png
To solve this, mipmaps are created. Mipmaps are versions of the image
shrunk by half in both axis, recursively, until the image is 1 pixel of
size. When the 3D hardware needs to shrink the image, it finds the
largest mipmap it can scale from, and scales from there. This improves
performance and image quality.
.. image:: /img/mipmaps.png
Godot automatically creates mipmaps upon load for standard image files.
This process is time consuming (although not much) and makes load times
a little worse. Pre-importing the textures allows the automatic
generation of mipmaps.
Unwanted MipMaps
----------------
Remember the previous point about mipmaps? Yes, they are cool, but
mobile GPUs only support them if the textures are in power of 2
dimensions (i.e. 256x256 or 512x128). In these platforms, Godot will
stretch and enlarge the texture to the closest power of 2 size and then
generate the mipmaps. This process takes more of a performance hit and
it might degrade the quality a little more.
Because of this, there are some scenarios when it may be desirable to
not use them, and just use a linear filter. One of them is when working
with graphical user interfaces (GUIs). Usually they are made of large
images and don't stretch much. Even if the screen resolution is in a
larger or smaller value than original art, the amount of stretch is not
as much and the art can retain the quality. Pre-importing the textures
also allows the disabling of mipmap generation.
Blending artifacts
------------------
The `blending
equation <http://en.wikipedia.org/wiki/Alpha_compositing>`__ used by
applications like Photoshop is too complex for realtime. There are
better approximations such as `pre-multiplied
alpha <http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx?Redirected=true>`__,
but they impose more stress in the asset pipeline. In the end, we are
left with textures that have artifacts in the edges, because apps such
as Photoshop store white pixels in completely transparent areas. Such
white pixels end up showing thanks to the texture filter.
Godot has an option to fix the edges of the image (by painting invisible
pixels the same color as the visible neighbours):
.. image:: /img/fixedborder.png
However, this must be done every time the image changes. Pre-Importing
the textures makes sure that every time the original file changes, this
artifact is fixed upon automatic re-import.
Texture flags
-------------
Textures have flags. The user can choose for them to repeat or clamp to
edges (when UVs exceed the 0,0,1,1 boundary). The magnifying filter can
also be turned off (for a Minecraft-like effect). Such values can not be
edited in standard file formats (png, jpg, etc.), but can be edited and
saved in Godot .tex files. Then again, the user may not want to change
the values every time the texture changes. Pre-Importing the textures
also takes care of that.
Texture compression
-------------------
Aside from the typical texture compression, which saves space on disk
(.png, jpg, etc.), there are also texture compression formats that save
space in memory (more specifically video memory. This allows to have
much better looking textures in games without running out of memory, and
decrease memory bandwidth when reading them so they are a big plus.
There are several video texture compression formats, none of which are
standard. Apple uses PVRTC. PC GPUs, consoles and nVidia Android devices use
S3TC (BC), other chipsets use other formats. OpenGL ES 3.0 standardized on ETC
format, but we are still a few years away from that working everywhere.
Still, when using this option, Godot converts and compresses to the
relevant format depending on the target platform (as long as the user
pre-imported the texture and specified video ram compression!).
This kind of compression is often not desirable for many types of 2D games
and UIs because it is lossy, creating visual artifacts. This is especially
noticeable on games that use the trendy vectory social game artwork.
However, the fact that it saves space and improves performance may make up for
it.
The 3D scene importer always imports textures with this option turned
on.
Atlases
-------
Remember how mobile GPUs have this limitation of textures having to be
in power of 2 sizes to be able to generate mimpmaps for optimum
stretching? What if we have a lot of images in different random sizes?
All will have to be scaled and mipmapped when loaded (using more CPU and
memory) or when imported (taking more storage space). This is probably still
OK, but there is a tool that can help improve this situation.
Atlases are big textures that fit a lot of small textures inside
efficiently. Godot supports creating atlases in the importer, and the
imported files are just small resources that reference a region of the
bigger texture.
Atlases can be a nice solution to save some space on GUI or 2D artwork
by packing everything together. The current importer is not as useful
for 3D though (3D Atlases are created differently, and not all 3D
models can use them).
As a small plus, atlases can decrease the amount of "state changes" when
drawing. If a lot of objects that are drawn using several different
textures are converted to an atlas, then the texture rebinds per object
will go from dozens or hundreds to one. This will give the performance a
small boost.
Artists use PSD
---------------
Still wondering whether to use the texture importer or not? Remember
that in the end, artists will often use Photoshop anyway, so it may be
wiser to just let the import subsystem to take care of importing and
converting the PSD files instead of asking the artist to save a png and
copy it to the project every time.
Texture importer
----------------
Finally! It's time to take a look at the texture importer. There are 3
options in the import menu. They are pretty much (almost) the same
dialog with a different set of defaults.
.. image:: /img/importtex.png
When selected, the texture import dialog will appear. This is the
default one for 2D textures:
.. image:: /img/import_images.png
Each import option has a function, explained as follows:
Source texture(s)
~~~~~~~~~~~~~~~~~
One or more source images can be selected from the same folder (this
importer can do batch-conversion). This can be from inside or outside
the project.
Target path
~~~~~~~~~~~
A destination folder must be provided. It must be inside the project, as
textures will be converted and saved to it. Extensions will be changed
to .tex (Godot resource file for textures), but names will be kept.
Texture format
~~~~~~~~~~~~~~
This combo allows to change the texture format (compression in this
case):
.. image:: /img/compressopts.png
Each of the four options described in this table together with their
advantages and disadvantages ( |good| = Best, |bad| =Worst ):
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| | Uncompressed | Compress Lossless (PNG) | Compress Lossy (WebP) | Compress VRAM |
+================+========================+===========================+=========================+======================================================+
| Description | Stored as raw pixels | Stored as PNG | Stored as WebP | Stored as S3TC/BC,PVRTC/ETC, depending on platform |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| Size on Disk | |bad| Large | |regular| Small | |good| Very Small | |regular| Small |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| Memory Usage | |bad| Large | |bad| Large | |bad| Large | |good| Small |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| Performance | |regular| Normal | |regular| Normal | |regular| Normal | |good| Fast |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| Quality Loss | |good| None | |good| None | |regular| Slight | |bad| Moderate |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
| Load Time | |regular| Normal | |bad| Slow | |bad| Slow | |good| Fast |
+----------------+------------------------+---------------------------+-------------------------+------------------------------------------------------+
Texture options
~~~~~~~~~~~~~~~
Provided are a small amount of options for fine grained import control:
- **Streaming Format** - This does nothing as of yet, but a texture
format for streaming different mipmap levels is planned. Big engines
have support for this.
- **Fix Border Alpha** - This will fix texture borders to avoid the
white auras created by white invisible pixels (see the rant above).
- **Alpha Bit Hint** - Godot auto-detects if the texture needs alpha
bit support for transparency (instead of full range), which is useful
for compressed formats such as BC. This forces alpha to be 0 or 1.
- **Compress Extra** - Some VRAM compressions have alternate formats
that compress more at the expense of quality (PVRTC2 for example). If
this is ticked, texture will be smaller but look worse.
- **No MipMaps** - Force imported texture to NOT use mipmaps. This may
be desirable in some cases for 2D (as explained in the rant above),
though it's NEVER desirable for 3D.
- **Repeat** - Texture will repeat when UV coordinates go beyond 1 and
below 0. This is often desirable in 3D, but may generate artifacts in
2D.
- **Filter** - Enables linear filtering when a texture texel is larger
than a screen pixel. This is usually turned on, unless it's required
for artistic purposes (Minecraft look, for example).
.. |bad| image:: /img/bad.png
.. |good| image:: /img/good.png
.. |regular| image:: /img/regular.png

View File

@@ -0,0 +1,86 @@
.. _doc_importing_translations:
Importing translations
======================
Games and internationalization
------------------------------
The world is full of different markets and cultures and, to maximize
profits™, nowadays games are released in several languages. To solve
this, internationalized text must be supported in any modern game
engine.
In regular desktop or mobile applications, internationalized text is
usually located in resource files (or .po files for GNU stuff). Games,
however, can use several orders of magnitude more text than
applications, so they must support efficient methods for dealing with
loads of multilingual text.
There are two approaches to generate multilingual language games and
applications. Both are based on a key:value system. The first is to use
one of the languages as the key (usually English), the second is to use a
specific identifier. The first approach is probably easier for
development if a game is released first in English, later in other
languages, but a complete nightmare if working with many languages at
the same time.
In general, games use the second approach and a unique ID is used for
each string. This allows to revise the text while it's being translated
to others. The unique ID can be a number, a string, or a string with a
number (it's just a unique string anyway).
Translators also, most of the time prefer to work with spreadsheets
(either as a Microsoft Excel file or a shared Google Spreadsheet).
Translation format
------------------
To complete the picture and allow efficient support for translations,
Godot has a special importer that can read csv files. Both Microsoft
Excel and Google Spreadsheet can export to this format, so the only
requirement is that the files have a special arrangement. The csv files must
be saved in utf-8 encoding and be formatted as follows:
+--------+----------+----------+----------+
| | <lang1> | <lang2> | <langN> |
+========+==========+==========+==========+
| KEY1 | string | string | string |
+--------+----------+----------+----------+
| KEY2 | string | string | string |
+--------+----------+----------+----------+
| KEYN | string | string | string |
+--------+----------+----------+----------+
The "lang" tags must represent a language, which must be one of the :ref:`valid
locales <doc_locales>` supported by the engine. The "KEY" tags must be
unique and represent a string universally (they are usually in
uppercase, to differentiate from other strings). Here's an example:
+---------+------------------+----------------+--------------+
| id | en | es | ja |
+=========+==================+================+==============+
| GREET | Hello, friend! | Hola, Amigo! | こんにちは |
+---------+------------------+----------------+--------------+
| ASK | How are you? | Cómo está? | 元気ですか |
+---------+------------------+----------------+--------------+
| BYE | Good Bye | Adiós | さようなら |
+---------+------------------+----------------+--------------+
Import dialog
-------------
The import dialog takes a csv file in the previously described format
and generates several compressed translation resource files inside the
project.
Selecting a csv file autodetects the languages from the first row and
determines which column represents which language. It is possible to
change this manually, by selecting the language for each column.
.. image:: /img/trans.png
The import dialog also can add the translation to the list of
translations to load when the game runs, specified in engine.cfg (or the
project properties). Godot allows loading and removing translations at
runtime as well.

View File

@@ -0,0 +1,150 @@
.. _doc_managing_image_files:
Managing image files
====================
If you have read the previous tutorials on :ref:`doc_resources` and
:ref:`doc_filesystem`, at this point you know that regular image files
(.png, .jpg, etc.) are treated as regular resources in Godot.
Unlike texture resources (.tex files), image files contain no extra
information on tiling (texture repeat), mipmaps or filtering. Editing
this information and saving the texture back will not have any effect,
since such formats can't contain that information.
Image loader
------------
Loading of images is done by the image loader. The behavior of the
loader for all image files can be changed in the Project Settings dialog
(Scene -> Project Settings). There is a section with values that
are used for all image resources:
.. image:: /img/imgloader.png
Image loader options
--------------------
Filter
~~~~~~
Filter is used when the image is stretched more than its original size,
so a texel in the image is bigger than a pixel on the screen. Turning
off the filter produces a retro-like look:
.. image:: /img/imagefilter.png
Repeat
~~~~~~
Repeat is mainly used for 3D textures, so it's off by default (textures
are imported with the scenes and usually are not in the project as image
files). When using UV coordinates (something not as common in 2D), and
the UV value goes beyond the 0,0,1,1 rect, the texture repeats instead
of clamping to the edge.
Mipmaps
~~~~~~~
When the mipmaps option is enabled, Godot will generate mipmaps.
Mipmaps are versions of the image shrunk by half in both axis,
recursively, until the image is 1 pixel of size. When the 3D hardware
needs to shrink the image, it finds the largest mipmap it can scale
from, and scales from there. This improves performance and image
quality.
.. image:: /img/mipmaps.png
When mipmaps are disabled, images start distorting badly when shrunk
excessively:
.. image:: /img/imagemipmap.png
Alpha blending
~~~~~~~~~~~~~~
The `blending
equation <http://en.wikipedia.org/wiki/Alpha_compositing>`__ used by
applications like Photoshop is too complex for real-time. There are
better approximations such as `pre-multiplied
alpha <http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx?Redirected=true>`__,
but they impose more stress in the asset pipeline. In the end, we are
left with textures that have artifacts in the edges, because apps such
as Photoshop store white pixels in completely transparent areas. Such
white pixels end up showing thanks to the texture filter (when active).
Godot has an option to fix the edges of the image (by painting invisible
pixels the same color as the visible neighbours):
.. image:: /img/fixedborder.png
To do this, open the image from the resources tab, or edit it from the
property editor from another node or resource, then go to the object
options and select "Fix Alpha Edges", then save it.
.. image:: /img/imagefixalpha.png
Since fixing this in so many images can be a little annoying, both
Texture Import and Image Export can also perform this operation.
Texture import
~~~~~~~~~~~~~~
Sometimes, it might be desired to change the above settings per image.
Unfortunately, the image loader settings are global. Texture flags also
can't be saved in a regular .png or .jpg file.
For such cases, the image can be imported as a texture (.tex), where the
individual flags can be changed. Godot also keeps track of the original
file and will re-import if it changes.
Importing also allows conversion to other formats (WebP, or RAM
compression) which might be of use in some cases. More information on
the :ref:`doc_importing_textures` page.
Image export
~~~~~~~~~~~~
It is also possible to convert images to other formats (WebP or RAM
compression) on export, as well as instructing the exporter to create an
Atlas for a set of images. It is also possible to ask the exporter to
scale all images (or selected groups).
More information on the :ref:`doc_exporting_images` page.
Fixing PNGs iCCP chunk
----------------------
With the upgrade of libpng to 1.6.23, libpng became more strict in terms of
enforcing iCC profile correctness. This means that it now warns when it comes
across an image with a non-conforming iCC chunk.
WARNING: _png_warn_function: iCCP: known incorrect sRGB profile
This can be fixed by either using a tool that exports PNGs with the correct
iCC profile (in some tools this profile can even be manually changed on export)
or using a tool that removes/fixes the iCC chunks.
Linux/Mac
~~~~~
Using ImageMagicks ``convert`` or ``mogrify`` fixes these warnings.
To fix all PNGs in a project folder do:
.. code-block:: shell
$ find . -type f -name "*.png" -exec convert {} {} \;
``pngcheck`` is also useful in locating the non-conforming images:
.. code-block:: shell
find . -type f -name "*.png" -exec pngcheck {} \;
Windows
~~~~~~~
Using `optiPNG <http://optipng.sourceforge.net/>` fixes these warnings on Windows.
To fix a PNG inplace do:
.. code-block:: shell
optipng -clobber -strip all file.png

View File

@@ -0,0 +1,63 @@
.. _doc_exporting_for_android:
Exporting for Android
=====================
Exporting for Android has fewer requirements than compiling Godot for it. The
following steps detail what is needed to setup the SDK and the engine.
Download the Android SDK
------------------------
Download and install the Android SDK from
http://developer.android.com/sdk/index.html
Install OpenJDK or Oracle JDK
-----------------------------
Download and install OpenJDK or Oracle JDK. Version 6 and 8 are known to
work, some users have reported issues with the jarsigner (used to sign the
APKs) in JDK 7.
Create a debug.keystore
-----------------------
Android needs a debug keystore file to install to devices and distribute
non-release APKs. If you have used the SDK before and have built
projects, ant or eclipse probably generated one for you (In Linux and
OSX, you can find it in the ~/.android folder).
If you can't find it or need to generate one, the keytool command from
the JDK can be used for this purpose:
::
keytool -keyalg RSA -genkeypair -alias androiddebugkey -keypass android -keystore debug.keystore -storepass android -dname "CN=Android Debug,O=Android,C=US" -validity 9999
Make sure you have adb
----------------------
Android Debug Bridge (adb) is the command line tool used to communicate with
Android devices. It's installed with the SDK, but you may need to install one
(any) of the Android API levels for it to be installed in the SDK directory.
Setting it up in Godot
----------------------
Enter the Editor Settings screen. This screens contains the editor
settings for the user account in the computer (It's independent from the
project).
.. image:: /img/editorsettings.png
Scroll down to the section where the Android settings are located:
.. image:: /img/androidsdk.png
In that screen, the path to 3 files needs to be set:
- The *adb* executable (adb.exe on Windows)
- The *jarsigner* executable (from JDK 6 or 8)
- The debug *keystore*
Once that is configured, everything is ready to export to Android!

View File

@@ -0,0 +1,75 @@
.. _doc_exporting_for_ios:
Exporting for iOS
=================
Exporting for iOS is done manually at the moment. These are the steps to
load your game in an XCode project, where you can deploy to a device,
publish, etc.
Requirements
------------
- Download XCode for iOS
- Download the export templates: https://godotengine.org/download
- Since there is no automatic deployer yet, unzip export_templates.tpz
manually and extract GodotiOSXCode.zip from it.
The zip contains an XCode project, godot_ios.xcodeproj, an empty
data.pck file and the engine executable. Open the project, and modify
the game name, icon, organization, provisioning signing certificate
identities (??), etc.
Add your project data
---------------------
Using the Godot editor, :ref:`doc_exporting_for_pc`, to obtain the data.pck
file. Replace the empty data.pck in the XCode project with the new one,
and run/archive.
If you want to test your scenes on the iOS device as you edit them, you
can add your game directory to the project (instead of data.pck), and
add a property "godot_path" to Info.plist, with the name of your
directory as its value.
.. image:: /img/godot_path.png
Alternatively you can add all the files from your game directly, with
"engine.cfg" at the root.
Loading files from a host
-------------------------
Sometimes your game becomes too big and deploying to the device takes
too long every time you run. In that case you can deploy only the engine
executable, and serve the game files from your computer.
Setting up the file host
~~~~~~~~~~~~~~~~~~~~~~~~
On your PC, open the editor, and click the righ-most icon on the
top-center group of icons, and select "Enable File Server". The icon
turns red. Your PC will open a port and accept connections to serve
files from your project's directory (so enable your local firewall
accordingly).
.. image:: /img/rfs_server.png
Setting up the game
~~~~~~~~~~~~~~~~~~~
On XCode, click on your app name (top left, next to the "Stop" button),
and select "Edit Scheme". Go to the "Arguments" tab, and add 2
arguments, "-rfs" and the IP of your PC.
.. image:: /img/edit_scheme.png
When you run, your device will connect to the host and open the files
remotely. Note that the directory with the game data ("platformer") is
no longer added to the project, only the engine executable.
Services for iOS
----------------
Special iOS services can be used in Godot. Check out the
:ref:`doc_services_for_ios` page.

View File

@@ -0,0 +1,17 @@
.. _doc_exporting_for_pc:
Exporting for PC
================
The simplest way to distribute a game for PC is to copy the executables
(godot.exe on windows, godot on the rest), zip the folder and send it to
someone else. However, this is often not desired.
Godot offers a more elegant approach for PC distribution when using the
export system. When exporting for PC (Linux, Windows, Mac), the exporter
takes all the project files and creates a "data.pck" file. This file is
bundled with a specially optimized binary that is smaller, faster and
lacks tools and debugger.
Optionally, the files can be bundled inside the executable, though this
does not always works properly.

View File

@@ -0,0 +1,71 @@
.. _doc_exporting_for_uwp:
Exporting for Universal Windows Platform
========================================
There's no extra requirement to export an ``.appx`` package that can be
installed as a Windows App or submited to the Windows Store. Exporting
packages also works from any platform, not only on Windows.
However, if you want to install and run the app, you need to sign it with a
trusted signature. Currently, Godot supports no signing of packages and you
need to use externals to tools to do so.
Also, make sure the Publisher name you set when export the package matches
the name on the certificate.
Limitations on Xbox One
------------
As described in `UWP documentation <https://msdn.microsoft.com/en-us/windows/uwp/xbox-apps/system-resource-allocation>`__:
- available RAM is 1GB (after exceeding it, application will encounter memory allocation failures and will crash)
- share of 2-4 CPU cores
- share of 45% of GPU power
Creating a signing certificate
------------------------------
This requires the tools ``MakeCert.exe`` and ``Pvk2Pfx.exe`` which comes
with the Windows SDK. If you use Visual Studio, open one of its Developer
Prompts since they come with those tools available and in the path.
You can get more detailed instructions from `Microsof documentation
<https://msdn.microsoft.com/en-us/library/windows/desktop/jj835832(v=vs.85).aspx>`__.
First, run ``MakeCert`` to create a private key::
MakeCert /n publisherName /r /h 0 /eku "1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13" /e expirationDate /sv MyKey.pvk MyKey.cer
Where ``publisherName`` matches the Publisher Name of your package and
``expirationDate`` is in the ``mm/dd/yyyy`` format.
Next, create a Personal Information Exchange (.pfx) file using ``Pvk2Pfx.exe``::
Pvk2Pfx /pvk MyKey.pvk /pi pvkPassword /spc MyKey.cer /pfx MyKey.pfx [/po pfxPassword]
If you don't specify a password with ``/po`` argument, the PFX will have the
same password as the private key.
You also need to trust this certificate to be able to actually install the
apps. Open the Command Prompt as Administrator and run the following command::
Certutil -addStore TrustedPeople MyKey.cer
Signing the package
-------------------
Using the ``SignTool.exe`` this requires a single command::
SignTool sign /fd SHA256 /a /f MyKey.pfx /p pfxPassword package.appx
Installing the package
----------------------
After Windows 10 Anniversary Update you can install packages by just double
clicking the ``.appx`` file from the Windows Explorer.
It's also possible to install using the ``Add-AppxPackage`` PowerShell cmdlet.
Note that if you don't update the version number, you'll have to uninstall the
previous installed package before reinstalling it.

View File

@@ -0,0 +1,90 @@
.. _doc_exporting_for_web:
Exporting for the Web
=====================
Exporting for the web generates several files to be served from a web server,
including a default HTML page for presentation. A custom HTML file can be
used, see :ref:`doc_compiling_for_web`.
The default HTML file is designed to fit the game perfectly without cutting off
parts of the canvas when the browser window is scaled to the game's dimensions.
This way it can be inserted into an ``<iframe>`` with the game's size, as is
common on most web game hosting sites.
Serving the files
-----------------
The default ``.html`` file can be used as ``DirectoryIndex`` and can be
renamed to e.g. ``index.html`` at any time, its name is never depended on.
It can also be inserted into another HTML file as an ``<iframe>`` element.
Users must allow **third-party** cookies when playing a game presented in an
iframe.
The ``.mem`` and ``.pck`` files are binary, usually delivered with MIME-type
``application/octet-stream``.
Delivering the files with gzip compression is recommended especially for the
``.pck``, ``.asm.js`` and ``.mem`` files, which are usually large in size.
Export options
--------------
Turning on **Debugging Enabled** when exporting will, in addition to enabling
various debug features of the engine, display a debug output below the canvas,
displaying JavaScript and engine errors. If controls are
enabled as well, display of this output can be toggled.
You can also use the browser-integrated developer console, usually opened with
the F12 key, which often shows more information, including WebGL errors.
**Memory Size** is fixed and must thus be set during export. Try using no more
than necessary to strain users' browsers as little as possible.
**Enable Run** will add a button between the *Stop scene* and *Play edited Scene*
buttons in the editor to quickly open the game in the default browser for
testing.
The remaining options customize the generated HTML page:
**Title** is the content of the ``<title>`` element of the page, usually used by
browsers as the tab and window name. The title set here is only displayed until
the game is started, afterwards the title is set to the application name set in
the project settings.
**Head Include** and **Style Include** are appended into the ``<head>`` and
CSS ``<style>`` elements respectively. This allows, for example, linking
web fonts for use in the page.
**Font Family** is the CSS ``font-family`` used on the page, without terminating
semicolon.
**Controls Enabled** toggles display of controls, offering e.g. a toggle for
output display in debug mode and a fullscreen button.
In the default page, the controls are displayed in the top-right corner on top
of the canvas, which can get in the way in games that use the cursor.
Security restrictions
---------------------
Browsers do not allow arbitrarily **entering full screen** at any time.
Instead, these actions have to occur as a response to a JavaScript input event.
In Godot, this is most easily done by entering full screen from within an
``_input()`` callback.
Chromium-derived browsers will not load exported projects when
**opened locally** per ``file://`` protocol. To get around this, you can start
the browser with the ``--allow-file-access-from-files`` flag, or use a local
server. Python offers an easy way for this, using ``python -m SimpleHTTPServer``
with Python 2 or ``python -m http.server`` with Python 3 will serve the
current working directory on ``http://localhost:8000``.
Locale
------
Godot tries to detect the user's locale using information provided by the
browser, but this is rather unreliable. A better way is to use CGI to read the
HTTP ``Accept-Language`` header. If you assign its value to the JavaScript
property ``Module.locale`` after the ``Module`` objects is created, but before
the engine starts, Godot will use that value to initialize the locale.
In any case, users should always be offered the option to configure the locale
manually.

View File

@@ -0,0 +1,128 @@
.. _doc_exporting_projects:
Exporting projects
==================
Why exporting?
--------------
Originally, Godot did not have any means to export projects. The
developers would compile the proper binaries and build the packages for
each platform manually.
When more developers (and even non-programmers) started using it, and
when our company started taking more projects at the same time, it
became evident that this was a bottleneck.
On PC
~~~~~
Distributing a game project on PC with Godot is rather easy. Just drop
the godot.exe (or godot) binary together in the same place as the
engine.cfg file, zip it and you are done. This can be taken advantage of to
make custom installers.
It sounds simple, but there are probably a few reasons why the developer
may not want to do this. The first one is that it may not be desirable
to distribute loads of files. Some developers may not like curious users
peeking at how the game was made, others may just find it inelegant,
etc.
Another reason is that, for distribution, the developer might use a
specially compiled binary, which is smaller in size, more optimized and
does not include tools inside (like the editor, debugger, etc.).
Finally, Godot has a simple but efficient system for creating DLCs as
extra package files.
On mobile
~~~~~~~~~
The same scenario in mobile is a little worse. To distribute a project
in those devices, a binary for each of those platforms is built, then
added to a native project together with the game data.
This can be troublesome because it means that the developer must be
familiarized with the SDK of each platform before even being able to
export. In other words, while learning each SDK is always encouraged, it
can be frustrating to be forced to do it at an undesired time.
There is also another problem with this approach, which is the fact that
different devices prefer some data in different formats to run. The main
example of this is texture compression. All PC hardware uses S3TC (BC)
compression and that has been standardized for more than a decade, but
mobile devices use different formats for texture compression, such as
PVRCT (iOS) or ETC (Android).
Export dialog
-------------
After many attempts at different export workflows, the current one has
proven to work the best. At the time of this writing, not all platforms are
supported yet, but the supported platforms continue to grow.
To open the export dialog, just click the "Export" button:
.. image:: /img/export.png
The dialog will open, showing all the supported export platforms:
.. image:: /img/export_dialog.png
The default options are often enough to export, so tweaking them is not
necessary, but provide extra control. However, many platforms require additional
tools (SDKs) to be installed to be able to export. Additionally, Godot
needs exports templates installed to create packages. The export dialog
will complain when something is missing and will not allow the user to
export for that platform until they resolve it:
.. image:: /img/export_error.png
At that time, the user is expected to come back to the documentation and follow
instructions on how to properly set up that platform.
Export templates
~~~~~~~~~~~~~~~~
Apart from setting up the platform, the export templates must be
installed to be able to export projects. They can be obtained as a
.tpz (a renamed .zip) file from the `download page of the website
<https://www.godotengine.org/download>`_.
Once downloaded, they can be installed using the "Install Export
Templates" option in the editor:
.. image:: /img/exptemp.png
Export mode
~~~~~~~~~~~
When exporting, Godot makes a list of all the files to export and then
creates the package. There are 3 different modes for exporting:
- Export every single file in the project
- Export only resources (+custom filter), this is default.
- Export only selected resources (+custom filter)
.. image:: /img/expres.png
- **Export every single file** - This mode exports every single file in
the project. This is good to test if something is being forgotten,
but developers often have a lot of unrelated stuff around in the dev
directory, which makes it a bad idea.
- **Export only resources** - Only resources are exported. For most
projects, this is enough. However many developers like to use custom
datafiles in their games. To compensate for this, filters can be
added for extra extensions (like, *.txt,*.csv, etc.).
- **Export only selected resources** - Only select resources from a
list are exported. This is probably overkill for most projects, but
in some cases it is justified (usually huge projects). This mode
offers total control of what is exported. Individual resources can be
selected and dependency detection is performed to ensure that
everything needed is added. As a plus, this mode allows to
"Bundle" scenes and dependencies into a single file, which is
*really* useful for games distributed on optical media.
.. image:: /img/expselected.png

View File

@@ -0,0 +1,33 @@
.. _doc_one-click_deploy:
One-click deploy
================
Sounds good, what is it?
------------------------
This feature will pop up automatically once a platform is properly
configured and a supported device is connected to the computer. Since
things can go wrong at many levels (platform may not be configured
correctly, SDK may incorrectly installed, device may be improperly
configured, kitty ate the USB cable, etc.), it's good to let the user
know that it exists.
Some platforms (at the time of this writing, only Android and Blackberry
10) can detect when a USB device is connected to the computer, and offer
the user to automatically export, install and run the project (in debug
mode) on the device. This feature is called, in industry buzz-words,
"One Click Deploy" (though, it's technically two clicks...).
Steps for one-click deploy
--------------------------
#. Configure target platform.
#. Configure device (make sure it's in developer mode, likes the
computer, usb is recognized, usb cable is plugged, etc.).
#. Connect the device..
#. And voila!
.. image:: /img/oneclick.png
Click once.. and deploy!

View File

View File

@@ -0,0 +1,133 @@
.. _doc_project_organization:
Project organization
====================
Introduction
------------
This tutorial is aimed to propose a simple workflow on how to organize
projects. Since Godot allows the programmer to use the file-system as he
or she pleases, figuring out a way to organize the projects when
starting to use the engine can be a little challenging. Because of this,
a simple workflow will be described, which can be used or not, but
should work as a starting point.
Additionally, using version control can be challenging so this
proposition will include that too.
Organization
------------
Other game engines often work by having an asset database, where you can
browse images, models, sounds, etc. Godot is more scene-based in nature
so most of the time the assets are bundled inside the scenes or just
exist as files but are referenced from scenes.
Importing & game folder
-----------------------
It is very often necessary to use asset importing in Godot. As the
source assets for importing are also recognized as resources by the
engine, this can become a problem if both are inside the project folder,
because at the time of export the exporter will recognize them and
export both.
To solve this, it is a good practice to have your game folder inside
another folder (the actual project folder). This allows to have the game
assets separated from the source assets, and also allows to use version
control (such as svn or git) for both. Here is an example:
::
myproject/art/models/house.max
myproject/art/models/sometexture.png
myproject/sound/door_open.wav
myproject/sound/door_close.wav
myproject/translations/sheet.csv
Then also, the game itself is, in this case, inside a game/ folder:
::
myproject/game/engine.cfg
myproject/game/scenes/house/house.scn
myproject/game/scenes/house/sometexture.tex
myproject/game/sound/door_open.smp
myproject/game/sound/door_close.smp
myproject/game/translations/sheet.en.xl
myproject/game/translations/sheet.es.xl
Following this layout, many things can be done:
- The whole project is still inside a folder (myproject/).
- Exporting the project will not export the .wav and .png files which
were imported.
- myproject/ can be put directly inside a VCS (like svn or git) for
version control, both game and source assets are kept track of.
- If a team is working on the project, assets can be re-imported by
other project members, because Godot keeps track of source assets
using relative paths.
Scene organization
------------------
Inside the game folder, a question that often arises is how to organize
the scenes in the filesystem. Many developers try asset-type based
organization and end up having a mess after a while, so the best answer
is probably to organize them based on how the game works and not based
on asset type. Here are some examples.
If you were organizing your project based on asset type, it would look
like this:
::
game/engine.cfg
game/scenes/scene1.scn
game/scenes/scene2.scn
game/textures/texturea.png
game/textures/another.tex
game/sounds/sound1.smp
game/sounds/sound2.wav
game/music/music1.ogg
Which is generally a bad idea. When a project starts growing beyond a
certain point, this becomes unmanageable. It's really difficult to tell
what belongs to what.
It's generally a better idea to use game-context based organization,
something like this:
::
game/engine.cfg
game/scenes/house/house.scn
game/scenes/house/texture.tex
game/scenes/valley/canyon.scn
game/scenes/valley/rock.scn
game/scenes/valley/rock.tex
game/scenes/common/tree.scn
game/scenes/common/tree.tex
game/player/player.scn
game/player/player.gd
game/npc/theking.scn
game/npc/theking.gd
game/gui/main_screen/main_sceen.scn
game/gui/options/options.scn
This model or similar models allows projects to grow to really large
sizes and still be completely manageable. Notice that everything is
based on parts of the game that can be named or described, like the
settings screen or the valley. Since everything in Godot is done with
scenes, and everything that can be named or described can be a scene,
this workflow is very smooth and easygoing.
Cache files
-----------
Godot uses a hidden file called ".fscache" at the root of the project.
On it, it caches project files and is used to quickly know when one is
modified. Make sure to **not commit this file** to git or svn, as it
contains local information and might confuse another editor instance in
another computer.