From 0af279915caea71e4e60f691902c509f5a56eb32 Mon Sep 17 00:00:00 2001 From: David Herman Date: Thu, 27 Jul 2017 16:26:12 -0700 Subject: [PATCH 1/2] Polish text in the "Scripting" section None of the changes in this CL change the meaning or spirit of the underlying text. Instead, my goal was to tidy up miscellaneous issues and make the text flow a little more smoothly. --- learning/step_by_step/scripting.rst | 210 ++++++++++++++-------------- 1 file changed, 108 insertions(+), 102 deletions(-) diff --git a/learning/step_by_step/scripting.rst b/learning/step_by_step/scripting.rst index 7ac95f8b..40c294a0 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 script's 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: :: From 3f05b443d19dc05fad7fc7c2b945129b881e9c4d Mon Sep 17 00:00:00 2001 From: David Herman Date: Tue, 1 Aug 2017 16:39:49 -0700 Subject: [PATCH 2/2] Replace "script's constructor" with just "a constructor" The script is not a class, so it technially doesn't have a constructor. --- learning/step_by_step/scripting.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/learning/step_by_step/scripting.rst b/learning/step_by_step/scripting.rst index 40c294a0..82eee9d3 100644 --- a/learning/step_by_step/scripting.rst +++ b/learning/step_by_step/scripting.rst @@ -138,7 +138,7 @@ you to the script editor where an existing template will be included by default: There is not much in there. The "_ready()" function is called when the node (and all its children) enter the active scene. (Note: "_ready()" is not -the script's constructor; the constructor is "_init()"). +the a constructor; the constructor is "_init()"). The role of the script ~~~~~~~~~~~~~~~~~~~~~~