From 95784cf94ff4f898b30130d24f00fd51e211023e Mon Sep 17 00:00:00 2001 From: Michael Alexsander Date: Fri, 6 Mar 2020 16:28:58 -0300 Subject: [PATCH] General formating fixes for GDScript scripting pages (#3248) --- .../scripting/gdscript/gdscript_advanced.rst | 106 +++++++++--------- .../scripting/gdscript/gdscript_basics.rst | 92 ++++++++------- .../scripting/gdscript/static_typing.rst | 42 ++++--- 3 files changed, 131 insertions(+), 109 deletions(-) diff --git a/getting_started/scripting/gdscript/gdscript_advanced.rst b/getting_started/scripting/gdscript/gdscript_advanced.rst index d3e91415a..9e512c52d 100644 --- a/getting_started/scripting/gdscript/gdscript_advanced.rst +++ b/getting_started/scripting/gdscript/gdscript_advanced.rst @@ -59,17 +59,17 @@ Static: .. code-block:: cpp - int a; // Value uninitialized - a = 5; // This is valid - a = "Hi!"; // This is invalid + 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 + var a # 'null' by default. + a = 5 # Valid, 'a' becomes an integer. + a = "Hi!" # Valid, 'a' changed to a string. As function arguments: ~~~~~~~~~~~~~~~~~~~~~~ @@ -88,8 +88,8 @@ Static: [..] - print_value(55); // Valid - print_value("Hello"); // Invalid + print_value(55); // Valid. + print_value("Hello"); // Invalid. Dynamic: @@ -100,8 +100,8 @@ Dynamic: [..] - print_value(55) # Valid - print_value("Hello") # Valid + print_value(55) # Valid. + print_value("Hello") # Valid. Pointers & referencing: ~~~~~~~~~~~~~~~~~~~~~~~ @@ -128,9 +128,9 @@ too. Some Examples: void do_something() { - SomeClass *instance = new SomeClass; // Created as pointer - use_class(instance); // Passed as pointer - delete instance; // Otherwise it will leak memory + SomeClass *instance = new SomeClass; // Created as pointer. + use_class(instance); // Passed as pointer. + delete instance; // Otherwise it will leak memory. } - Java: @@ -145,10 +145,10 @@ too. Some Examples: public final void do_something() { - SomeClass instance = new SomeClass(); // Created as reference - use_class(instance); // Passed as reference + 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 + // use and freeze your game randomly for a second. } - GDScript: @@ -159,9 +159,9 @@ too. Some Examples: 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 + 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 @@ -179,35 +179,35 @@ Compare for example arrays in statically typed languages: .. code-block:: cpp - int *array = new int[4]; // Create array - array[0] = 10; // Initialize manually - array[1] = 20; // Can't mix types + 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 + // Can't resize. + use_array(array); // Passed as pointer. + delete[] array; // Must be freed. // or std::vector array; array.resize(4); - array[0] = 10; // Initialize manually - array[1] = 20; // Can't mix types + 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 + 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 + 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: @@ -246,7 +246,7 @@ Example of Dictionary: :: - var d = {"name": "John", "age": 22} # Simple syntax + 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 @@ -254,16 +254,16 @@ at little cost: :: - d["mother"] = "Rebecca" # Addition - d["age"] = 11 # Modification - d.erase("name") # Removal + 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 + # Battleship Game const SHIP = 0 const SHIP_HIT = 1 @@ -277,12 +277,12 @@ easily with dictionaries. Here's a simple battleship game example: board[Vector2(1, 3)] = SHIP func missile(pos): - if pos in board: # Something at that pos - if board[pos] == SHIP: # There was a ship! hit it + if pos in board: # Something at that position. + 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 + print("Already hit here!") # Hey dude you already hit here. + else: # Nothing, mark as water. board[pos] = WATER_HIT func game(): @@ -299,20 +299,21 @@ states and quick structs: :: # Same example, lua-style support. - # This syntax is a lot more readable and usable - # Like any GDScript identifier, keys written in this form cannot start with a digit. + # This syntax is a lot more readable and usable. + # Like any GDScript identifier, keys written in this form cannot start + # with a digit. var d = { name = "John", age = 22 } - print("Name: ", d.name, " Age: ", d.age) # Used "." based indexing + print("Name: ", d.name, " Age: ", d.age) # Used "." based indexing. # Indexing d["mother"] = "Rebecca" - d.mother = "Caroline" # This would work too to create a new key + d.mother = "Caroline" # This would work too to create a new key. For & while ----------- @@ -325,8 +326,7 @@ Iterating in some statically typed languages can be quite complex: [..] - for (int i = 0; i < 50; i++) - { + for (int i = 0; i < 50; i++) { printf("Value: %s\n", i, strings[i]); } @@ -364,9 +364,9 @@ 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 + 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 statically typed programming language examples: @@ -457,7 +457,7 @@ And it can be used like any other iterator: var itr = ForwardIterator.new(0, 6, 2) for i in itr: - print(i) # Will print 0, 2, and 4 + print(i) # Will print 0, 2, and 4. Make sure to reset the state of the iterator in ``_iter_init``, otherwise nested for-loops that use custom iterators will not work as expected. diff --git a/getting_started/scripting/gdscript/gdscript_basics.rst b/getting_started/scripting/gdscript/gdscript_basics.rst index 05bc0d707..58507c3cb 100644 --- a/getting_started/scripting/gdscript/gdscript_basics.rst +++ b/getting_started/scripting/gdscript/gdscript_basics.rst @@ -63,6 +63,7 @@ here's a simple example of how GDScript looks. class_name MyClass, "res://path/to/optional/icon.svg" + # Member variables var a = 5 @@ -87,6 +88,7 @@ here's a simple example of how GDScript looks. var v2 = Vector2(1, 2) var v3 = Vector3(1, 2, 3) + # Function func some_function(param1, param2): @@ -108,17 +110,20 @@ here's a simple example of how GDScript looks. var local_var2 = param1 + 3 return local_var2 + # Functions override functions with the same name on the base/parent class. # If you still want to call them, use '.' (like 'super' in other languages). func something(p1, p2): .something(p1, p2) + # Inner class class Something: var a = 10 + # Constructor func _init(): @@ -563,8 +568,8 @@ after the variable name, followed by the type. If the variable is initialized within the declaration, the type can be inferred, so it's possible to omit the type name:: - var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2' - var my_node := Sprite.new() # 'my_node' is of type 'Sprite' + var my_vector2 := Vector2() # 'my_vector2' is of type 'Vector2'. + var my_node := Sprite.new() # 'my_node' is of type 'Sprite'. Type inference is only possible if the assigned value has a defined type, otherwise it will raise an error. @@ -590,14 +595,14 @@ same type or a subtype of the cast type. :: var my_node2D: Node2D - my_node2D = $Sprite as Node2D # Works since Sprite is a subtype of Node2D + my_node2D = $Sprite as Node2D # Works since Sprite is a subtype of Node2D. If the value is not a subtype, the casting operation will result in a ``null`` value. :: var my_node2D: Node2D - my_node2D = $Button as Node2D # Results in 'null' since a Button is not a subtype of Node2D + my_node2D = $Button as Node2D # Results in 'null' since a Button is not a subtype of Node2D. For built-in types, they will be forcibly converted if possible, otherwise the engine will raise an error. @@ -605,8 +610,8 @@ engine will raise an error. :: var my_int: int - my_int = "123" as int # The string can be converted to int - my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error + my_int = "123" as int # The string can be converted to int. + my_int = Vector2() as int # A Vector2 can't be converted to int, this will cause an error. Casting is also useful to have better type-safe variables when interacting with the scene tree:: @@ -987,11 +992,11 @@ By default, all script files are unnamed classes. In this case, you can only reference them using the file's path, using either a relative or an absolute path. For example, if you name a script file ``character.gd``:: - # Inherit from Character.gd + # Inherit from 'Character.gd'. extends "res://path/to/character.gd" - # Load character.gd and create a new node instance from it + # Load character.gd and create a new node instance from it. var Character = load("res://path/to/character.gd") var character_node = Character.new() @@ -1067,7 +1072,7 @@ the ``is`` keyword can be used:: # [...] # Use 'is' to check inheritance. - if (entity is Enemy): + if entity is Enemy: entity.apply_damage() To call a function in a *parent class* (i.e. one ``extend``-ed in your current @@ -1293,7 +1298,7 @@ to. To create custom signals for a class, use the ``signal`` keyword. extends Node - # A signal named health_depleted + # A signal named health_depleted. signal health_depleted .. note:: @@ -1312,14 +1317,14 @@ In the example below, we connect the ``health_depleted`` signal from a ``Character`` node to a ``Game`` node. When the ``Character`` node emits the signal, the game node's ``_on_Character_health_depleted`` is called:: - # Game.gd + # Game.gd - func _ready(): - var character_node = get_node('Character') - character_node.connect("health_depleted", self, "_on_Character_health_depleted") + func _ready(): + var character_node = get_node('Character') + character_node.connect("health_depleted", self, "_on_Character_health_depleted") - func _on_Character_health_depleted(): - get_tree().reload_current_scene() + func _on_Character_health_depleted(): + get_tree().reload_current_scene() You can emit as many arguments as you want along with a signal. @@ -1342,7 +1347,7 @@ the :ref:`Object.connect() ` method:: health -= amount # We emit the health_changed signal every time the - # character takes damage + # character takes damage. emit_signal("health_changed", old_health, health) ... @@ -1351,7 +1356,7 @@ the :ref:`Object.connect() ` method:: # Lifebar.gd # Here, we define a function to use as a callback when the - # character's health_changed signal is emitted + # character's health_changed signal is emitted. ... func _on_Character_health_changed(old_value, new_value): @@ -1361,7 +1366,7 @@ the :ref:`Object.connect() ` method:: progress_bar.modulate = Color.green # Imagine that `animate` is a user-defined function that animates the - # bar filling up or emptying itself + # bar filling up or emptying itself. progress_bar.animate(old_value, new_value) ... @@ -1376,13 +1381,13 @@ node in this case. :: - # Game.gd + # Game.gd - func _ready(): - var character_node = get_node('Character') - var lifebar_node = get_node('UserInterface/Lifebar') + func _ready(): + var character_node = get_node('Character') + var lifebar_node = get_node('UserInterface/Lifebar') - character_node.connect("health_changed", lifebar_node, "_on_Character_health_changed") + character_node.connect("health_changed", lifebar_node, "_on_Character_health_changed") This allows the ``Lifebar`` to react to health changes without coupling it to the ``Character`` node. @@ -1390,8 +1395,8 @@ the ``Character`` node. You can write optional argument names in parentheses after the signal's definition:: - # Defining a signal that forwards two arguments - signal health_changed(old_value, new_value) + # Defining a signal that forwards two arguments. + signal health_changed(old_value, new_value) These arguments show up in the editor's node dock, and Godot can use them to generate callback functions for you. However, you can still emit any number of @@ -1414,23 +1419,24 @@ taken by each character on the screen, like ``Player1 took 22 damage.``. The damage. So when we connect the signal to the in-game console, we can add the character's name in the binds array argument:: - # Game.gd + # Game.gd - func _ready(): - var character_node = get_node('Character') - var battle_log_node = get_node('UserInterface/BattleLog') + func _ready(): + var character_node = get_node('Character') + var battle_log_node = get_node('UserInterface/BattleLog') - character_node.connect("health_changed", battle_log_node, "_on_Character_health_changed", [character_node.name]) + character_node.connect("health_changed", battle_log_node, "_on_Character_health_changed", [character_node.name]) Our ``BattleLog`` node receives each element in the binds array as an extra argument:: - # BattleLog.gd + # BattleLog.gd - func _on_Character_health_changed(old_value, new_value, character_name): - if not new_value <= old_value: - return - var damage = old_value - new_value - label.text += character_name + " took " + str(damage) + " damage." + func _on_Character_health_changed(old_value, new_value, character_name): + if not new_value <= old_value: + return + + var damage = old_value - new_value + label.text += character_name + " took " + str(damage) + " damage." Coroutines with yield @@ -1445,9 +1451,9 @@ function returns. Once resumed, the state object becomes invalid. Here is an example:: func my_func(): - print("Hello") - yield() - print("world") + print("Hello") + yield() + print("world") func _ready(): var y = my_func() @@ -1466,9 +1472,9 @@ It is also possible to pass values between ``yield()`` and ``resume()``, for example:: func my_func(): - print("Hello") - print(yield()) - return "cheers!" + print("Hello") + print(yield()) + return "cheers!" func _ready(): var y = my_func() diff --git a/getting_started/scripting/gdscript/static_typing.rst b/getting_started/scripting/gdscript/static_typing.rst index ea406a348..c38207c26 100644 --- a/getting_started/scripting/gdscript/static_typing.rst +++ b/getting_started/scripting/gdscript/static_typing.rst @@ -33,16 +33,17 @@ who work with your code should always pass an ``Item`` to the :: - # In Item.gd + # In 'Item.gd'. class_name Item - - # In Inventory.gd + # In 'Inventory.gd'. class_name Inventory + func add(reference: Item, amount: int = 1): var item = find_item(reference) if not item: item = _instance_item_from_db(reference) + item.amount += amount Another significant advantage of typed GDScript is the new **warning @@ -122,7 +123,7 @@ script you want to use as a type in a constant: :: - const Rifle = preload('res://player/weapons/Rifle.gd') + const Rifle = preload("res://player/weapons/Rifle.gd") var my_rifle: Rifle The second method is to use the ``class_name`` keyword when you create. @@ -165,6 +166,7 @@ to use this type. This forces the variable to stick to the var player := body as PlayerController if not player: return + player.damage() As we’re dealing with a custom type, if the ``body`` doesn’t extend @@ -238,6 +240,7 @@ You can also use your own nodes as return types: var item: Item = find_item(reference) if not item: item = ItemDatabase.get_instance(reference) + item.amount += amount return item @@ -257,20 +260,28 @@ dynamic style: :: extends Node - func _ready(): - pass - func _process(delta): - pass + + + func _ready(): + pass + + + func _process(delta): + pass And with static typing: :: extends Node - func _ready() -> void: - pass - func _process(delta: float) -> void: - pass + + + func _ready() -> void: + pass + + + func _process(delta: float) -> void: + pass As you can see, you can also use types with the engine’s virtual methods. Signal callbacks, like any methods, can also use types. Here’s @@ -296,6 +307,7 @@ to cast parameters automatically: func _on_area_entered(bullet: Bullet) -> void: if not bullet: return + take_damage(bullet.damage) The ``bullet`` variable could hold any ``CollisionObject2D`` here, but @@ -378,7 +390,7 @@ element the ``for`` keyword loops over already has a different type. So you :: - var names = ['John', 'Marta', 'Samantha', 'Jimmy'] + var names = ["John", "Marta", "Samantha", "Jimmy"] for name: String in names: pass @@ -387,17 +399,21 @@ Two scripts can’t depend on each other in a cyclic fashion: :: # Player.gd + extends Area2D class_name Player + var rifle: Rifle :: # Rifle.gd + extends Area2D class_name Rifle + var player: Player Summary