Skip to content

Commit 29ec0d2

Browse files
committed
Add documentation for traits to relevant pages
Add trait-related keywords to syntax highlighting Update style guide and static typing pages Currently, the style guide uses what seem like good reasonable policies to me (notably, PascalCase adjectives for trait names, and `uses` after `extends`). We'll need to make sure this is agreed-upon as the good way to do it before merging, though Document behavior of static variables in traits [no ci] Document behavior of casting to traits
1 parent 469176a commit 29ec0d2

File tree

4 files changed

+254
-37
lines changed

4 files changed

+254
-37
lines changed

_extensions/gdscript.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,9 @@ def innerstring_rules(ttype):
151151
"namespace", # Reserved for potential future use.
152152
"signal",
153153
"static",
154-
"trait", # Reserved for potential future use.
154+
"trait",
155+
"trait_name",
156+
"uses",
155157
"var",
156158
# Other keywords.
157159
"await",

tutorials/scripting/gdscript/gdscript_basics.rst

+199-13
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ here's an example of how GDScript looks.
4242
# Inheritance:
4343
extends BaseClass
4444

45+
# Trait usage:
46+
uses Talkable, Flammable
47+
4548

4649
# Member variables.
4750
var a = 5
@@ -103,6 +106,19 @@ here's an example of how GDScript looks.
103106
super.something(p1, p2)
104107

105108

109+
# When traits are used, they may have to implement abstract
110+
# methods defined by the trait:
111+
func talk_to():
112+
print("Hi, you just talked to me!")
113+
114+
115+
# Traits can also implement methods that the concrete class
116+
# can use without defining itself:
117+
func yet_another_something():
118+
print("I'm going to light on fire!")
119+
light_on_fire()
120+
121+
106122
# Inner class
107123
class Something:
108124
var a = 10
@@ -174,7 +190,13 @@ in case you want to take a look under the hood.
174190
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
175191
| extends | Defines what class to extend with the current class. |
176192
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
177-
| is | Tests whether a variable extends a given class, or is of a given built-in type. |
193+
| trait | Defines an inner trait. See `Inner traits`_. |
194+
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
195+
| trait_name | Defines the script as a globally accessible trait with the specified name. See `Registering named traits`_. |
196+
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
197+
| uses | Defines what trait(s) the current class should use. |
198+
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
199+
| is | Tests whether a variable extends a given class, uses a given trait, or is of a given built-in type. |
178200
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
179201
| in | Tests whether a value is within a string, array, range, dictionary, or node. When used with ``for``, it iterates through them instead of testing. |
180202
+------------+---------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -853,15 +875,16 @@ The GDScript static analyzer takes typed arrays into account, however array meth
853875
``front()`` and ``back()`` still have the ``Variant`` return type.
854876

855877
Typed arrays have the syntax ``Array[Type]``, where ``Type`` can be any ``Variant`` type,
856-
native or user class, or enum. Nested array types (like ``Array[Array[int]]``) are not supported.
878+
native or user class, trait, or enum. Nested array types (like ``Array[Array[int]]``) are not supported.
857879

858880
::
859881

860882
var a: Array[int]
861883
var b: Array[Node]
862884
var c: Array[MyClass]
863885
var d: Array[MyEnum]
864-
var e: Array[Variant]
886+
var e: Array[MyTrait]
887+
var f: Array[Variant]
865888

866889
``Array`` and ``Array[Variant]`` are the same thing.
867890

@@ -1036,9 +1059,10 @@ Valid types are:
10361059

10371060
- Built-in types (Array, Vector2, int, String, etc.).
10381061
- Engine classes (Node, Resource, RefCounted, etc.).
1039-
- Constant names if they contain a script resource (``MyScript`` if you declared ``const MyScript = preload("res://my_script.gd")``).
1040-
- Other classes in the same script, respecting scope (``InnerClass.NestedClass`` if you declared ``class NestedClass`` inside the ``class InnerClass`` in the same scope).
1062+
- Constant names if they contain a script or trait resource (``MyScript`` if you declared ``const MyScript = preload("res://my_script.gd")``).
1063+
- Other classes or traits in the same file, respecting scope (``InnerClass.NestedClass`` if you declared ``class NestedClass`` inside the ``class InnerClass`` in the same scope).
10411064
- Script classes declared with the ``class_name`` keyword.
1065+
- Traits declared with the ``trait_name`` keyword.
10421066
- Autoloads registered as singletons.
10431067

10441068
.. note::
@@ -1104,11 +1128,11 @@ A class member variable can be declared static::
11041128

11051129
static var a
11061130

1107-
Static variables belong to the class, not instances. This means that static variables
1131+
Static variables belong to the class or trait, not instances. This means that static variables
11081132
share values between multiple instances, unlike regular member variables.
11091133

1110-
From inside a class, you can access static variables from any function, both static and non-static.
1111-
From outside the class, you can access static variables using the class or an instance
1134+
From inside a class/trait, you can access static variables from any function, both static and non-static.
1135+
From outside the class/trait, you can access static variables using the class/trait or an instance
11121136
(the second is not recommended as it is less readable).
11131137

11141138
.. note::
@@ -1179,6 +1203,24 @@ A base class static variable can also be accessed via a child class::
11791203
B.x = 3
11801204
prints(A.x, B.x) # 3 3
11811205

1206+
.. warning::
1207+
1208+
Static variables declared on traits belong to the trait *itself*, and are *not*
1209+
inherited by classes that use the trait::
1210+
1211+
trait HasStatic:
1212+
static var static_var = 3
1213+
1214+
class UsingClass:
1215+
uses HasStatic
1216+
1217+
func _ready():
1218+
# Will work
1219+
print(HasStatic.static_var)
1220+
1221+
# Will NOT work, as UsingClass does not get static_var from HasStatic
1222+
print(UsingClass.static_var)
1223+
11821224
``@static_unload`` annotation
11831225
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11841226

@@ -1208,15 +1250,15 @@ Values assigned to typed variables must have a compatible type. If it's needed t
12081250
coerce a value to be of a certain type, in particular for object types, you can
12091251
use the casting operator ``as``.
12101252

1211-
Casting between object types results in the same object if the value is of the
1212-
same type or a subtype of the cast type.
1253+
Casting between object types or traits results in the same object if the value is of the
1254+
same type or a subtype of the cast type, or if the value uses the trait.
12131255

12141256
::
12151257

12161258
var my_node2D: Node2D
12171259
my_node2D = $Sprite2D as Node2D # Works since Sprite2D is a subtype of Node2D.
12181260

1219-
If the value is not a subtype, the casting operation will result in a ``null`` value.
1261+
If the value is not a subtype or does not use the trait, the casting operation will result in a ``null`` value.
12201262

12211263
::
12221264

@@ -1324,7 +1366,7 @@ or ``0`` if it is the first entry in the enum. Multiple keys with the same value
13241366
Functions
13251367
---------
13261368

1327-
Functions always belong to a `class <Classes_>`_. The scope priority for
1369+
Functions always belong to a `class <Classes_>`_ or a `trait <Traits_>`_. The scope priority for
13281370
variable look-up is: local → class member → global. The ``self`` variable is
13291371
always available and is provided as an option for accessing class members, but
13301372
is not always required (and should *not* be sent as the function's first
@@ -1941,6 +1983,11 @@ A class (stored as a file) can inherit from:
19411983

19421984
Multiple inheritance is not allowed.
19431985

1986+
.. note::
1987+
Godot 4.x introduces `traits <Traits_>`_ to GDScript, which may cover many of
1988+
the use cases for multiple inheritance. See their section for more information
1989+
about how they work.
1990+
19441991
Inheritance uses the ``extends`` keyword::
19451992

19461993
# Inherit/extend a globally available class.
@@ -1957,7 +2004,7 @@ Inheritance uses the ``extends`` keyword::
19572004
If inheritance is not explicitly defined, the class will default to inheriting
19582005
:ref:`class_RefCounted`.
19592006

1960-
To check if a given instance inherits from a given class,
2007+
To check if a given instance inherits from a given class or uses a given trait,
19612008
the ``is`` keyword can be used::
19622009

19632010
# Cache the enemy class.
@@ -1969,6 +2016,15 @@ the ``is`` keyword can be used::
19692016
if entity is Enemy:
19702017
entity.apply_damage()
19712018

2019+
# Cache the Flammable trait.
2020+
const Flammable = preload("flammable.gdt")
2021+
2022+
# [...]
2023+
2024+
# Use 'is' to check usage of the trait.
2025+
if entity is Flammable:
2026+
entity.light_on_fire()
2027+
19722028
To call a function in a *super class* (i.e. one ``extend``-ed in your current
19732029
class), use the ``super`` keyword::
19742030

@@ -2121,6 +2177,136 @@ class resource is done by calling the ``new`` function on the class object::
21212177
var a = MyClass.new()
21222178
a.some_function()
21232179

2180+
Traits
2181+
------
2182+
2183+
Traits are collections of behaviors and attributes that classes can use to guarantee
2184+
functionality to themselves and other objects that may be attempting to use them.
2185+
2186+
Like classes, by default all ``.gdt`` files are unnamed traits, and you must reference
2187+
them using a relative or absolute path.
2188+
::
2189+
# Use the trait 'interactable.gdt'.
2190+
uses "res://path/to/interactable.gdt"
2191+
2192+
Note that traits on their own *cannot* be instantiated the same way that classes can.
2193+
2194+
.. _doc_gdscript_basics_trait_name:
2195+
2196+
Registering named traits
2197+
~~~~~~~~~~~~~~~~~~~~~~~~
2198+
2199+
Traits can be given a global name by using the ``trait_name`` keyword.
2200+
::
2201+
trait_name MyTrait
2202+
2203+
Using traits in a class
2204+
~~~~~~~~~~~~~~~~~~~~~~~
2205+
2206+
For a class to use a trait, use the ``uses`` keyword:
2207+
::
2208+
class_name MyScript
2209+
uses MyTrait
2210+
2211+
2212+
Traits may also extend classes. If a trait extends a class, then any class
2213+
that uses that trait must also have that class as an ancestor.
2214+
::
2215+
# movable.gdt
2216+
trait_name Movable
2217+
extends PhysicsBody2D
2218+
2219+
# character.gd
2220+
class_name Character
2221+
extends CharacterBody2D
2222+
uses Movable # Allowed, since CharacterBody2D inherits from PhysicsBody2D.
2223+
2224+
The ``is`` keyword can be used to determine if a given instance uses a particular trait.
2225+
::
2226+
if entity is Movable:
2227+
entity.move()
2228+
2229+
If a trait provides a method signature, but no body, then the using class must implement
2230+
a body for the method.
2231+
::
2232+
# explosive.gdt
2233+
trait_name Explosive
2234+
2235+
func explode() # Body is not defined here, so it must be defined in each class that uses it.
2236+
2237+
2238+
# exploding_barrel.gd
2239+
class_name ExplodingBarrel
2240+
extends Sprite2D
2241+
uses Explosive
2242+
2243+
func explode(): # If this definition of Explosive.explode isn't provided, we will get an error.
2244+
print("Kaboom!")
2245+
queue_free()
2246+
2247+
If a trait provides a method signature *and* a body, then the using class inherits it by default
2248+
and doesn't need to provide its own implementation. It still can override the trait's
2249+
implementation if desired, but the parameter count must stay the same, and the parameter and return
2250+
types must be compatible.
2251+
::
2252+
# damageable.gdt
2253+
trait_name Damageable
2254+
2255+
func take_damage():
2256+
print("Ouch!")
2257+
2258+
2259+
# invincible_npc.gd
2260+
class_name InvincibleNPC
2261+
extends Sprite2D
2262+
uses Damageable
2263+
2264+
# Allowed, and will run instead of Damageable's original take_damage method.
2265+
func take_damage():
2266+
print("You can't hurt me!")
2267+
2268+
..
2269+
TODO: Confirm these behaviors
2270+
2271+
Other class members have similar rules:
2272+
2273+
- Variables and constants can be overridden, as long as the type is compatible and the value is changed.
2274+
- Signals can be overriden, as long as the parameter count is maintained and the parameter types are compatible.
2275+
- Named enums can be overriden and have new enum values.
2276+
2277+
.. _doc_gdscript_basics_inner_traits:
2278+
2279+
Inner traits
2280+
~~~~~~~~~~~~
2281+
2282+
Like inner classes, a class or trait file may contain inner traits, defined with the ``trait``
2283+
keyword. Unlike inner classes, they cannot be instantiated directly, but their name can be
2284+
referenced for using or checking use of themselves.
2285+
::
2286+
# An inner trait in this class file.
2287+
trait SomeInnerTrait:
2288+
func do_something():
2289+
print("I did something!")
2290+
2291+
2292+
# An inner class in this class file, which uses the inner trait.
2293+
class SomeInnerClass:
2294+
uses SomeInnerTrait
2295+
2296+
2297+
func _init():
2298+
var c = SomeInnerClass.new()
2299+
if c is SomeInnerTrait:
2300+
c.do_something()
2301+
2302+
.. _doc_gdscript_basics_traits_as_resources:
2303+
2304+
Traits as resources
2305+
~~~~~~~~~~~~~~~~~~~
2306+
2307+
Traits stored as files are treated as :ref:`GDTraits <class_GDTrait>`, and must
2308+
be loaded similarly to classes (see `Classes as resources`_).
2309+
21242310
Exports
21252311
-------
21262312

0 commit comments

Comments
 (0)