diff --git a/learning/step_by_step/scripting.rst b/learning/step_by_step/scripting.rst index 7ac95f8b..82eee9d3 100644 --- a/learning/step_by_step/scripting.rst +++ b/learning/step_by_step/scripting.rst @@ -7,75 +7,84 @@ 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. +without programming. This appeals to many people who would love to be able to +make a game without having to learn how to code. This need has been around for +a long time, even inside game companies, where game designers would like to +have more control of their game's 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. +Many products have been shipped promising such a no-programming environment, +but the results often fall short of expectations. The projects they produce end +up being too complex or require solutions that are too inefficient compared to +what could have been accomplished with traditional code. -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 is understandable later on. That is, it relieves -programmers from the responsibility of designing and structuring code. +As a result, we think that programming is here to stay. In fact, game engines +have been moving in this direction, adding tools that try to reduce the amount +of code that needs to be written rather than eliminating it. The engine can +provide many general solutions, while the developer can use code to accomplish +specific tasks. -When designing games using the scene system, the whole project is -fragmented into *complementary* scenes (not individual ones). Scenes -complement (i.e. help) each other, instead of being separate. There will be -plenty of examples of this later on, but it's very important to remember it. +Godot has embraced this goal from the beginning, and it has influenced many of +its design decisions. First and foremost is the scene system. This system has +many benefits, but fundamentally its goal is to relieve programmers from the +responsibility of having to implement an overall architecture. -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 `__ -pattern for scripting, meaning that scripts extend from all the -available engine classes. +When designing games using the scene system, the whole project is fragmented +into *complementary* scenes (not individual ones). Scenes complement +(i.e. help) each other, instead of being separate. There will be plenty of +examples of this later on, but it's very important to remember it. GDScript -------- -:ref:`doc_gdscript` is a dynamically-typed scripting language designed to -fit inside Godot. It was designed with the following goals: +:ref:`doc_gdscript` is a dynamically typed scripting language which 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. +- Most importantly, it should feel simple, familiar, and as easy to learn as + possible. +- It should have a syntax that's very readable. The syntax is mostly borrowed + from Python. +- It should integrate tightly with Godot itself, for example sharing its memory + model, taking advantage of the scene/node system, and exposing useful + game-related classes already part of the Godot engine. -Programmers generally take a few days to learn it, and within two weeks -feel comfortable with it. +Programmers generally take a few days to learn GDScript and feel comfortable +with it within two weeks. -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 more than sufficient performance for most types of -games. +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. However, keep in mind that most critical code is already +written in C++ in the engine (vector ops, physics, math, indexing, etc.), which +results in 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. +rewritten in C++ and registered with Godot, which in turn exposes them to all +scripts. In this way, you can write a class in GDScript first but convert it to +a C++ class later, and the rest of the game will work the same as before. + +Finally, note that GDScript provides the powerful +`extend `__ keyword. Many classes in the +Godot engine are available as base classes to be extended from. Scripting a scene ----------------- +In the rest of this tutorial, we'll set up a simple GUI scene consisting of a +button and a label, where pressing the button will update the label. This will +demonstrate: + +- how to write a basic script and attach it to a node +- how to hook up UI elements via *signals* +- how to write a script that can access other nodes in the 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. +It's a simple language and the reference is short, so 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: +Use the add node dialog to create the following hierarchy, with the following +nodes: - Panel @@ -91,129 +100,126 @@ 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.tscn" +Finally, save the scene, with a name such as "sayhello.tscn" .. _doc_scripting-adding_a_script: Adding a script ~~~~~~~~~~~~~~~ -Right click on the panel node, then select "Add Script" in the context +Right click on the panel node, and 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). +The script creation dialog will pop up. This dialog allows you to set the +language, class name, and other relevant options. -Enter a path name for the script and then select "Create": +Actually, in GDScript, the file itself represents the class, so in this case, +the class name field is not editable. + +The node we're attaching the script to is a panel, so the "Inherits" field +should automatically be filled in with "Panel". This is what we want as our +script's goal is to extend this panel node's functionality. + +Finally, enter a path name for the script and 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: +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: +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()"). +node (and all its children) enter the active scene. (Note: "_ready()" is not +the 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. +A script adds behavior to a node. It is used to control how the node functions +as well as how it interacts with other nodes (children, parent, siblings, +etc.). The local scope of the script is the node. In other words, the script +inherits the functions provided by that node. .. 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. +Signals are "emitted" when some specific kind of action happens, and they can be +connected to any function of any script instance. Signals are used mostly in +GUI nodes (although other nodes have them too, and you can even define custom +signals in your own scripts). -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. +In this step, we'll connect the "pressed" signal to a custom function. + +The editor provides an interface for connecting signals to your scripts. You +can access this by selecting the node in the scene tree and then selecting the +"Node" tab. Next, 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. +At this point, you could use the visual interface to hook up the "pressed" +signal by double clicking on it and selecting a target node that already has a +script attached to it. But for the sake of learning, we're going to code up the +connection manually. -For this, a function exists that is probably the one most used by Godot -programmers, namely :ref:`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 accomplish this, we will introduce a function that is probably the most used +by Godot programmers, namely :ref:`Node.get_node() `. +This function uses paths to fetch nodes anywhere in the scene, relative to the +node that owns the script. -To fetch the button, the following must be used: +In our case, because the button and the label are siblings under the panel +where the script is attached, you can fetch the button as follows: :: get_node("Button") -Next, a callback will be added that will change the label's text when -the button is pressed: +Next, write a function which will be called 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() `. +Finally, connect the button's "pressed" signal to that callback in _ready(), by +using :ref:`Object.connect() `. :: func _ready(): get_node("Button").connect("pressed",self,"_on_button_pressed") -The final script should look like this: +The final script should look basically 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: +Run the scene and press the button. You should get the following result: .. 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: +Why hello there! Congratulations on scripting your first scene. + +**Note:** A common misunderstanding in this tutorial is how get_node(path) +works. For some given node, get_node(path) searches its immediate children. +In the above code, this means that *Button* must be a child of *Panel*. If +*Button* were instead a child of *Label*, the code to obtain it would be: ::