Merge branch 'master' into 3.2

This commit is contained in:
Rémi Verschelde
2020-05-04 09:05:37 +02:00
15 changed files with 274 additions and 48 deletions

View File

@@ -0,0 +1,117 @@
# -*- coding: utf-8 -*-
"""
godot_descriptions
~~~~~~~~~~~~~~~~~~
Sphinx extension to automatically generate HTML meta description tags
for all pages. Also comes with some special support for Godot class docs.
:copyright: Copyright 2020 by The Godot Engine Community
:license: MIT.
based on the work of Takayuki Shimizukawa on OpenGraph support for Sphinx,
see: https://github.com/sphinx-contrib/ogp
"""
import re
from docutils import nodes
from sphinx import addnodes
class DescriptionGenerator:
def __init__(self, document, pagename="", n_sections_max=3, max_length=220):
self.document = document
self.text_list = []
self.max_length = max_length
self.current_length = 0
self.n_sections = 0
self.n_sections_max = n_sections_max
self.pagename = pagename
self.is_class = pagename.startswith("classes/")
self.stop_word_reached = False
def dispatch_visit(self, node):
if (
self.stop_word_reached
or self.current_length > self.max_length
or self.n_sections > self.n_sections_max
):
return
if isinstance(node, addnodes.compact_paragraph) and node.get("toctree"):
raise nodes.SkipChildren
add = True
if isinstance(node, nodes.paragraph):
text = node.astext()
if self.is_class:
# Skip OOP hierarchy info for description
if (
text.startswith("Inherits:")
or text.startswith("Inherited By:")
or text.strip() == "Example:"
):
add = False
# If we're in a class doc and reached the first table,
# stop adding to the description
if text.strip() == "Properties":
self.stop_word_reached = True
add = False
if add:
self.text_list.append(text)
self.current_length = self.current_length + len(text)
if add and isinstance(node, nodes.section):
self.n_sections += 1
def dispatch_departure(self, node):
pass
def format_description(self, desc):
# Replace newlines with spaces
desc = re.sub("\r|\n", " ", desc)
# Replace multiple spaces with single spaces
desc = re.sub("\\s+", " ", desc)
return desc
def create_description(self, cutoff_suffix="..."):
text = " ".join(self.text_list)
text = self.format_description(text)
# Cut to self.max_length, add cutoff_suffix at end
if len(text) > self.max_length:
text = text[: self.max_length - len(cutoff_suffix)].strip() + cutoff_suffix
return text
def generate_description(app, pagename, templatename, context, doctree):
if not doctree:
return
generator = DescriptionGenerator(doctree, pagename)
doctree.walkabout(generator)
description = (
'<meta name="description" content="' + generator.create_description() + '">\n'
)
context["metatags"] += description
def setup(app):
# Hook into Sphinx for all pages to
# generate meta description tag and add to meta tag list
app.connect("html-page-context", generate_description)
return {
"parallel_read_safe": True,
"parallel_write_safe": True,
}

View File

@@ -2,7 +2,9 @@
{% block linktags -%}
{% if godot_inject_language_links -%}
{% for alternate_lang in godot_docs_supported_languages -%}
<link rel="alternate" hreflang="{{ alternate_lang }}" href="{{ godot_docs_basepath }}{{ alternate_lang }}/{{ godot_canonical_version }}/{{ pagename }}{{ godot_docs_suffix }}" />
{# Convert to ISO 639-1 format, e.g. zh_CN -> zh-cn -#}
{% set alternate_lang_href = alternate_lang.lower().replace("_", "-") -%}
<link rel="alternate" hreflang="{{ alternate_lang_href }}" href="{{ godot_docs_basepath }}{{ alternate_lang }}/{{ godot_canonical_version }}/{{ pagename }}{{ godot_docs_suffix }}" />
{% endfor -%}
<link rel="alternate" hreflang="x-default" href="{{ godot_docs_basepath }}{{ godot_default_lang }}/{{ godot_canonical_version }}/{{ pagename }}{{ godot_docs_suffix }}" />
@@ -10,3 +12,7 @@
{% endif -%}
{{ super() }}
{% endblock -%}
{% block htmltitle -%}
<title>{{ godot_title_prefix }}{{ title|striptags|e }}{{ titlesuffix }}</title>
{% endblock -%}

18
conf.py
View File

@@ -14,6 +14,7 @@ needs_sphinx = "1.3"
sys.path.append(os.path.abspath("_extensions"))
extensions = [
"gdscript",
"godot_descriptions",
"sphinx_search.extension",
"sphinx_tabs.tabs",
"sphinx.ext.imgmath",
@@ -66,17 +67,6 @@ supported_languages = {
"zh_CN": "Godot Engine (%s) 简体中文文档",
}
# Some language codes used on Weblate/RTD and in the docs URL differ,
# so we need to remap them.
languages_remap = {
"pt_BR": "pt-br",
"zh_CN": "zh-cn",
}
languages_url = sorted(
[l for l in supported_languages.keys() if l not in languages_remap.keys()]
+ list(languages_remap.values())
)
language = os.getenv("READTHEDOCS_LANGUAGE", "en")
if not language in supported_languages.keys():
print("Unknown language: " + language)
@@ -109,7 +99,6 @@ highlight_language = "gdscript"
# on_rtd is whether we are on readthedocs.org, this line of code grabbed from docs.readthedocs.org
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
html_theme = "sphinx_rtd_theme"
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
if on_rtd:
@@ -133,11 +122,14 @@ html_context = {
"github_version": "master", # Version
"conf_py_path": "/", # Path in the checkout to the docs root
"godot_inject_language_links": True,
"godot_docs_supported_languages": languages_url,
"godot_docs_supported_languages": list(supported_languages.keys()),
"godot_docs_basepath": "https://docs.godotengine.org/",
"godot_docs_suffix": ".html",
"godot_default_lang": "en",
"godot_canonical_version": "stable",
# Distinguish local development website from production website.
# This prevents people from looking for changes on the production website after making local changes :)
"godot_title_prefix": "" if on_rtd else "(DEV) ",
}
html_logo = "img/docs_logo.png"

View File

@@ -72,7 +72,7 @@ Instantiating C# nodes from GDScript
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Using C# from GDScript doesn't need much work. Once loaded
(see :ref:`doc_gdscript_classes_as_resources`) the script can be instantiated
(see :ref:`doc_gdscript_classes_as_resources`), the script can be instantiated
with :ref:`new() <class_CSharpScript_method_new>`.
::
@@ -83,15 +83,15 @@ with :ref:`new() <class_CSharpScript_method_new>`.
.. warning::
When creating .cs scripts you should always keep in mind that the class
Godot will use is the one named like the .cs file itself. If that class
When creating ``.cs`` scripts, you should always keep in mind that the class
Godot will use is the one named like the ``.cs`` file itself. If that class
does not exist in the file, you'll see the following error:
``Invalid call. Nonexistent function `new` in base``.
For example, MyCoolNode.cs should contain a class named MyCoolNode.
You also need to check your .cs file is referenced in the project's .csproj
file. Otherwise, the same error will occur.
You also need to check your ``.cs`` file is referenced in the project's
``.csproj`` file. Otherwise, the same error will occur.
Instantiating GDScript nodes from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -104,7 +104,7 @@ be instantiated with :ref:`GDScript.New() <class_GDScript_method_new>`.
GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
Object myGDScriptNode = (Godot.Object) MyGDScript.New(); // This is a Godot.Object
Here we are using an :ref:`class_Object` but you can use type conversion like
Here we are using an :ref:`class_Object`, but you can use type conversion like
explained in :ref:`doc_c_sharp_features_type_conversion_and_casting`.
Accessing fields
@@ -126,8 +126,8 @@ anything to worry about.
# my_csharp_node.str2 = "BARBAR" # This line will hang and crash
Note that it doesn't matter if the field is defined as a property or an
attribute, but trying to set a value on a property that does not define a
setter will result in a crash.
attribute. However, trying to set a value on a property that does not define
a setter will result in a crash.
Accessing GDScript fields from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -158,7 +158,7 @@ Calling C# methods from GDScript
Again, calling C# methods from GDScript should be straightforward. The
marshalling process will do its best to cast your the arguments to match
function signatures.
If that's impossible you'll see the following error: ``Invalid call. Nonexistent function `FunctionName```.
If that's impossible, you'll see the following error: ``Invalid call. Nonexistent function `FunctionName```.
::
@@ -174,7 +174,7 @@ Calling GDScript methods from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To call GDScript methods from C# you'll need to use
:ref:`Object.Call() <class_Object_method_call>`. The first arguments is the
:ref:`Object.Call() <class_Object_method_call>`. The first argument is the
name of the method you want to call. The following arguments will be passed
to said method.
@@ -197,5 +197,14 @@ to said method.
As you can see, if the first argument of the called method is an array,
you'll need to cast it as ``object``.
Otherwise each element of your array will be treated as a single argument
Otherwise, each element of your array will be treated as a single argument
and the function signature won't match.
Inheritance
-----------
A GDScript file may not inherit from a C# script. Likewise, a C# script may not
inherit from a GDScript file. Due to how complex this would be to implement,
this limitation is unlikely to be lifted in the future. See
`this GitHub issue <https://github.com/godotengine/godot/issues/38352>`__
for more information.

View File

@@ -985,7 +985,6 @@ will then appear with its new icon in the editor::
# Item.gd
extends Node
class_name Item, "res://interface/icons/item.png"
.. image:: img/class_name_editor_register_example.png
@@ -998,11 +997,14 @@ Here's a class file example:
class_name Character
var health = 5
func print_health():
print(health)
func print_this_script_three_times():
print(get_script())
print(ResourceLoader.load("res://character.gd"))
@@ -1091,9 +1093,11 @@ This is better explained through examples. Consider this scenario::
var entity = null
var message = null
func _init(e=null):
entity = e
func enter(m):
message = m
@@ -1101,6 +1105,7 @@ This is better explained through examples. Consider this scenario::
# Idle.gd (inheriting class)
extends "State.gd"
func _init(e=null, m=null).(e):
# Do something with 'e'.
message = m
@@ -1136,9 +1141,12 @@ function.
# An inner class in this class file.
class SomeInnerClass:
var a = 5
func print_value_of_a():
print(a)
# This is the constructor of the class file's main class.
func _init():
var c = SomeInnerClass.new()
@@ -1160,6 +1168,7 @@ class resource is done by calling the ``new`` function on the class object::
# Preload the class only once at compile time.
const MyClass = preload("myclass.gd")
func _init():
var a = MyClass.new()
a.some_function()
@@ -1192,9 +1201,11 @@ with the new value. Vice versa, when ``variable`` is accessed, the *getter* func
var my_var setget my_var_set, my_var_get
func my_var_set(new_value):
my_var = new_value
func my_var_get():
return my_var # Getter must return a value.
@@ -1236,6 +1247,7 @@ placed at the top of the file::
tool
extends Button
func _ready():
print("Hello")
@@ -1274,6 +1286,7 @@ to. To create custom signals for a class, use the ``signal`` keyword.
extends Node
# A signal named health_depleted.
signal health_depleted
@@ -1299,6 +1312,7 @@ signal, the game node's ``_on_Character_health_depleted`` is called::
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()
@@ -1318,6 +1332,7 @@ the :ref:`Object.connect() <class_Object_method_connect>` method::
...
signal health_changed
func take_damage(amount):
var old_health = health
health -= amount
@@ -1431,6 +1446,7 @@ an example::
yield()
print("world")
func _ready():
var y = my_func()
# Function state saved in 'y'.
@@ -1452,6 +1468,7 @@ for example::
print(yield())
return "cheers!"
func _ready():
var y = my_func()
# Function state saved in 'y'.
@@ -1471,6 +1488,7 @@ Remember to save the new function state, when using multiple ``yield``\s::
print("Turn %d" % i)
yield();
func _ready():
var co = co_func();
while co is GDScriptFunction && co.is_valid():
@@ -1500,12 +1518,47 @@ into an invalid state, for example::
yield(button_func(), "completed")
print("All buttons were pressed, hurray!")
func button_func():
yield($Button0, "pressed")
yield($Button1, "pressed")
``my_func`` will only continue execution once both buttons have been pressed.
You can also get the signal's argument once it's emitted by an object:
::
# Wait for when any node is added to the scene tree.
var node = yield(get_tree(), "node_added")
If you're unsure whether a function may yield or not, or whether it may yield
multiple times, you can yield to the ``completed`` signal conditionally:
::
func generate():
var result = rand_range(-1.0, 1.0)
if result < 0.0:
yield(get_tree(), "idle_frame")
return result
func make():
var result = generate()
if result is GDScriptFunctionState: # Still working.
result = yield(result, "completed")
return result
This ensures that the function returns whatever it was supposed to return
irregardless of whether coroutines were used internally. Note that using
``while`` would be redundant here as the ``completed`` signal is only emitted
when the function didn't yield anymore.
Onready keyword
~~~~~~~~~~~~~~~
@@ -1518,6 +1571,7 @@ be obtained when a call to ``Node._ready()`` is made.
var my_label
func _ready():
my_label = get_node("MyLabel")

View File

@@ -111,10 +111,20 @@ Examples
export(Color, RGB) var col
# Color given as red-green-blue-alpha value.
export(Color, RGBA) var col
# Another node in the scene can be exported, too.
export(NodePath) var node
# Nodes
# Another node in the scene can be exported as a NodePath.
export(NodePath) var node_path
# Do take note that the node itself isn't being exported -
# there is one more step to call the true node:
var node = get_node(node_path)
# Resources
export(Resource) var resource
# In the Inspector, you can then drag and drop a resource file
# from the FileSystem dock into the variable slot.
It must be noted that even if the script is not being run while in the
editor, the exported properties are still editable. This can be used
@@ -153,6 +163,10 @@ between all instances. This means that editing them in one instance will
cause them to change in all other instances. Exported arrays can have
initializers, but they must be constant expressions.
If the exported array specifies a type which inherits from Resource, the array
values can be set in the inspector by dragging and dropping multiple files
from the FileSystem dock at once.
::
# Exported array, shared between all instances.
@@ -171,6 +185,12 @@ initializers, but they must be constant expressions.
export(Array) var b
export(Array, PackedScene) var scenes
# Arrays with specified types which inherit from resource can be set by
# drag-and-dropping multiple files from the FileSystem dock.
export(Array, Texture) var textures
export(Array, PackedScene) var scenes
# Typed arrays also work, only initialized empty:
export var vector3s = PoolVector3Array()

View File

@@ -63,7 +63,7 @@ node.
.. warning:: The target node *must* have a script attached or you'll receive
an error message.
On the right side, you can bind an arbitrary number of arguments of (possibly) different
If you toggle the Advanced menu, you'll see on the right side that you can bind an arbitrary number of arguments of (possibly) different
types. This can be useful when you have more than one signal connected to the same method,
as each signal propagation will result in different values for those extra call arguments.

View File

@@ -408,7 +408,7 @@ Inherit the Bar Scene to build the LifeBar
Go to ``Scene -> New Inherited Scene`` to create a new type of ``Bar``.
Select the Bar scene and open it. You should see a new [unsaved] tab,
that's like your ``Bar``, but with all nodes except the root in grey.
Press :kbd:`Meta + S` to save the new inherited scene and name it
Press :kbd:`Ctrl + S` (:kbd:`Cmd + S` on macOS) to save the new inherited scene and name it
``LifeBar``.
.. figure:: img/ui_gui_step_tutorial_inherited_scene_parent.png
@@ -474,7 +474,7 @@ all the resources this node uses and create unique copies for us.
.. tip::
When you duplicate a node from the Scene tree, with
:kbd:`Meta + D`, it shares its resources with the original node. You
:kbd:`Ctrl + D` (:kbd:`Cmd + D` on macOS), it shares its resources with the original node. You
need to use ``Make Sub-Resources Unique`` before you can tweak the
resources without affecting the source node.

View File

@@ -127,7 +127,7 @@ We have to add a root node before we can save the scene. Your UI's root
should be the outermost container or element. In this case it's a
``MarginContainer``. ``MarginContainer`` is a good starting point for
most interfaces, as you often need padding around the UI. Press
:kbd:`Meta + S` to save the scene to the disk. Name it *MainMenu*.
:kbd:`Ctrl + S` (:kbd:`Cmd + S` on macOS) to save the scene to the disk. Name it *MainMenu*.
Select the ``MarginContainer`` again, and head to the inspector to
define the margins' size. Scroll down the ``Control`` class, to the
@@ -152,9 +152,9 @@ Select the ``MarginContainer``, and create the UI elements as
3. the version note,
4. and the main menu's illustration.
Click the **Add Node** button or press :kbd:`Meta + A` on your keyboard.
Click the **Add Node** button or press :kbd:`Ctrl + A` (:kbd:`Cmd + A` on macOS) on your keyboard.
Start to type ``TextureRect`` to find the corresponding node and press
enter. With the new node selected, press :kbd:`Meta + D` five times to
enter. With the new node selected, press :kbd:`Ctrl + D` (:kbd:`Cmd + D` on macOS) five times to
create five extra ``TextureRect`` instances.
Click each of the nodes to select it. In the inspector, find the **Texture**
@@ -234,7 +234,7 @@ automatically.
To space out the menu options and the logo on the left, we'll use one
final container and its size flags. Select the ``VBoxContainer`` and
press :kbd:`Meta + A` to add a new node inside it. Add a second
press :kbd:`Ctrl + A` (:kbd:`Cmd + A` on macOS) to add a new node inside it. Add a second
``VBoxContainer`` and name it *MenuOptions*. Select all three menu
options, ``Continue``, ``NewGame`` and ``Options``, and drag and drop
them inside the new ``VBoxContainer``. The UI's layout should barely

View File

@@ -36,6 +36,7 @@ Supported image formats
Godot can import the following image formats:
- BMP (``.bmp``)
- No support for 16-bit per pixel images. Only 1-bit, 4-bit, 8-bit, 24-bit, and 32-bit per pixel images are supported.
- DirectDraw Surface (``.dds``)
- If mipmaps are present in the texture, they will be loaded directly.
This can be used to achieve effects using custom mipmaps.
@@ -127,6 +128,17 @@ reimported automatically.
Note that RGTC compression affects the resulting normal map image. You will have to adjust custom shaders that use the normal map to take this into account.
.. note::
Godot requires the normal map to use the X+, Y- and Z+ coordinates. In other
words, if you've imported a material made to be used with another engine, you
may have to convert the normal map so its Y axis is flipped. Otherwise, the
normal map direction may appear to be inverted on the Y axis.
More information about normal maps (including a coordinate order table for
popular engines) can be found
`here <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details>`__.
Flags
-----

View File

@@ -475,7 +475,7 @@ With that done, all we need to do is add some code to ``process_input``:
# ----------------------------------
# Grabbing and throwing objects
if Input.is_action_just_pressed("fire") and current_weapon_name == "UNARMED":
if Input.is_action_just_pressed("fire_grenade") and current_weapon_name == "UNARMED":
if grabbed_object == null:
var state = get_world().direct_space_state

View File

@@ -291,6 +291,10 @@ reach the point where the muzzle starts to flash.
.. note:: The timeline is the window where all the points in our animation are stored. Each of the little
points represents a point of animation data.
To actually preview the "Pistol_fire" animation, select the :ref:`Camera <class_Camera>` node
underneath Rotation Helper and check the "Preview" box underneath Perspective in the top-left corner.
Scrubbing the timeline means moving ourselves through the animation. So when we say "scrub the timeline
until you reach a point", what we mean is move through the animation window until you reach the point

View File

@@ -354,15 +354,27 @@ lighting in the scene.
.. image:: img/spatial_material15.png
Normalmap
~~~~~~~~~
Normal map
~~~~~~~~~~
Normal mapping allows you to set a texture that represents finer shape detail.
This does not modify geometry, only the incident angle for light. In Godot,
only the red and green channels of normal maps are used for wider compatibility.
only the red and green channels of normal maps are used for better compression
and wider compatibility.
.. image:: img/spatial_material16.png
.. note::
Godot requires the normal map to use the X+, Y- and Z+ coordinates. In other
words, if you've imported a material made to be used with another engine, you
may have to convert the normal map so its Y axis is flipped. Otherwise, the
normal map direction may appear to be inverted on the Y axis.
More information about normal maps (including a coordinate order table for
popular engines) can be found
`here <http://wiki.polycount.com/wiki/Normal_Map_Technical_Details>`__.
Rim
~~~

View File

@@ -57,7 +57,7 @@ Mid level abstraction
Before going into how we would like to synchronize a game across the network, it can be helpful to understand how the base network API for synchronization works.
Godot uses a mid-level object :ref:`NetworkedMultiplayerPeer <class_NetworkedMultiplayerPeer>`.
This object is not meant to be created directly, but is designed so that several implementations can provide it.
This object is not meant to be created directly, but is designed so that several C++ implementations can provide it.
This object extends from :ref:`PacketPeer <class_PacketPeer>`, so it inherits all the useful methods for serializing, sending and receiving data. On top of that, it adds methods to set a peer, transfer mode, etc. It also includes signals that will let you know when peers connect or disconnect.
@@ -85,7 +85,7 @@ Initializing as a server, listening on the given port, with a given maximum numb
var peer = NetworkedMultiplayerENet.new()
peer.create_server(SERVER_PORT, MAX_PLAYERS)
get_tree().set_network_peer(peer)
get_tree().network_peer = peer
Initializing as a client, connecting to a given IP and port:
@@ -93,7 +93,7 @@ Initializing as a client, connecting to a given IP and port:
var peer = NetworkedMultiplayerENet.new()
peer.create_client(SERVER_IP, SERVER_PORT)
get_tree().set_network_peer(peer)
get_tree().network_peer = peer
Get the previously set network peer:
@@ -111,7 +111,7 @@ Terminating the networking feature:
::
get_tree().set_network_peer(null)
get_tree().network_peer = null
(Although it may make sense to send a message first to let the other peers know you're going away instead of letting the connection close or timeout, depending on your game.)

View File

@@ -82,7 +82,7 @@ or all the handle related ones.
func _init():
create_material("main", Color(1, 0, 0))
create_handles_material("handles")
create_handle_material("handles")
func redraw(gizmo):
gizmo.clear()
@@ -119,7 +119,7 @@ So the final plugin would look somewhat like this:
func _init():
create_material("main", Color(1,0,0))
create_handles_material("handles")
create_handle_material("handles")
func has_gizmo(spatial):
return spatial is MyCustomSpatial
@@ -170,7 +170,7 @@ for the Spatial nodes we want to target.
func _init():
create_material("main", Color(1, 0, 0))
create_handles_material("handles")
create_handle_material("handles")
func create_gizmo(spatial):
if spatial is MyCustomSpatial: