1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Replace XML codeblock spaces with tabs

This commit is contained in:
kobewi
2025-05-17 20:00:17 +02:00
committed by Rémi Verschelde
parent 5dd76968d8
commit 13f642d959
122 changed files with 2407 additions and 2432 deletions

View File

@@ -457,8 +457,8 @@
[codeblock]
print(" (x) (fmod(x, 1.5)) (fposmod(x, 1.5))")
for i in 7:
var x = i * 0.5 - 1.5
print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
var x = i * 0.5 - 1.5
print("%4.1f %4.1f | %4.1f" % [x, fmod(x, 1.5), fposmod(x, 1.5)])
[/codeblock]
Prints:
[codeblock lang=text]
@@ -498,21 +498,21 @@
var drink = "water"
func _ready():
var id = get_instance_id()
var instance = instance_from_id(id)
print(instance.foo) # Prints "water"
var id = get_instance_id()
var instance = instance_from_id(id)
print(instance.foo) # Prints "water"
[/gdscript]
[csharp]
public partial class MyNode : Node
{
public string Drink { get; set; } = "water";
public string Drink { get; set; } = "water";
public override void _Ready()
{
ulong id = GetInstanceId();
var instance = (MyNode)InstanceFromId(Id);
GD.Print(instance.Drink); // Prints "water"
}
public override void _Ready()
{
ulong id = GetInstanceId();
var instance = (MyNode)InstanceFromId(Id);
GD.Print(instance.Drink); // Prints "water"
}
}
[/csharp]
[/codeblocks]
@@ -642,10 +642,10 @@
extends Sprite
var elapsed = 0.0
func _process(delta):
var min_angle = deg_to_rad(0.0)
var max_angle = deg_to_rad(90.0)
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
var min_angle = deg_to_rad(0.0)
var max_angle = deg_to_rad(90.0)
rotation = lerp_angle(min_angle, max_angle, elapsed)
elapsed += delta
[/codeblock]
[b]Note:[/b] This function lerps through the shortest path between [param from] and [param to]. However, when these two angles are approximately [code]PI + k * TAU[/code] apart for any integer [code]k[/code], it's not obvious which way they lerp due to floating-point precision errors. For example, [code]lerp_angle(0, PI, weight)[/code] lerps counter-clockwise, while [code]lerp_angle(0, PI + 5 * TAU, weight)[/code] lerps clockwise.
</description>
@@ -815,7 +815,7 @@
[codeblock]
print("#(i) (i % 3) (posmod(i, 3))")
for i in range(-3, 4):
print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
print("%2d %2d | %2d" % [i, i % 3, posmod(i, 3)])
[/codeblock]
Prints:
[codeblock lang=text]
@@ -1429,9 +1429,9 @@
json.parse('["a", "b", "c"]')
var result = json.get_data()
if result is Array:
print(result[0]) # Prints "a"
print(result[0]) # Prints "a"
else:
print("Unexpected result!")
print("Unexpected result!")
[/codeblock]
See also [method type_string].
</description>
@@ -1471,8 +1471,8 @@
Prints:
[codeblock lang=text]
{
"a": 1,
"b": 2
"a": 1,
"b": 2
}
[/codeblock]
[b]Note:[/b] Converting [Signal] or [Callable] is not supported and will result in an empty value for these types, regardless of their data.
@@ -2613,11 +2613,11 @@
[codeblock]
var error = method_that_returns_error()
if error != OK:
printerr("Failure!")
printerr("Failure!")
# Or, alternatively:
if error:
printerr("Still failing!")
printerr("Still failing!")
[/codeblock]
[b]Note:[/b] Many functions do not return an error code, but will print error messages to standard output.
</constant>

View File

@@ -12,30 +12,30 @@
var aes = AESContext.new()
func _ready():
var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
# Encrypt ECB
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
var encrypted = aes.update(data.to_utf8_buffer())
aes.finish()
# Decrypt ECB
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
var decrypted = aes.update(encrypted)
aes.finish()
# Check ECB
assert(decrypted == data.to_utf8_buffer())
var key = "My secret key!!!" # Key must be either 16 or 32 bytes.
var data = "My secret text!!" # Data size must be multiple of 16 bytes, apply padding if needed.
# Encrypt ECB
aes.start(AESContext.MODE_ECB_ENCRYPT, key.to_utf8_buffer())
var encrypted = aes.update(data.to_utf8_buffer())
aes.finish()
# Decrypt ECB
aes.start(AESContext.MODE_ECB_DECRYPT, key.to_utf8_buffer())
var decrypted = aes.update(encrypted)
aes.finish()
# Check ECB
assert(decrypted == data.to_utf8_buffer())
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
# Encrypt CBC
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
encrypted = aes.update(data.to_utf8_buffer())
aes.finish()
# Decrypt CBC
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
decrypted = aes.update(encrypted)
aes.finish()
# Check CBC
assert(decrypted == data.to_utf8_buffer())
var iv = "My secret iv!!!!" # IV must be of exactly 16 bytes.
# Encrypt CBC
aes.start(AESContext.MODE_CBC_ENCRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
encrypted = aes.update(data.to_utf8_buffer())
aes.finish()
# Decrypt CBC
aes.start(AESContext.MODE_CBC_DECRYPT, key.to_utf8_buffer(), iv.to_utf8_buffer())
decrypted = aes.update(encrypted)
aes.finish()
# Check CBC
assert(decrypted == data.to_utf8_buffer())
[/gdscript]
[csharp]
using Godot;
@@ -43,35 +43,35 @@
public partial class MyNode : Node
{
private AesContext _aes = new AesContext();
private AesContext _aes = new AesContext();
public override void _Ready()
{
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
// Encrypt ECB
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish();
// Decrypt ECB
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
byte[] decrypted = _aes.Update(encrypted);
_aes.Finish();
// Check ECB
Debug.Assert(decrypted == data.ToUtf8Buffer());
public override void _Ready()
{
string key = "My secret key!!!"; // Key must be either 16 or 32 bytes.
string data = "My secret text!!"; // Data size must be multiple of 16 bytes, apply padding if needed.
// Encrypt ECB
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer());
byte[] encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish();
// Decrypt ECB
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer());
byte[] decrypted = _aes.Update(encrypted);
_aes.Finish();
// Check ECB
Debug.Assert(decrypted == data.ToUtf8Buffer());
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
// Encrypt CBC
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish();
// Decrypt CBC
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
decrypted = _aes.Update(encrypted);
_aes.Finish();
// Check CBC
Debug.Assert(decrypted == data.ToUtf8Buffer());
}
string iv = "My secret iv!!!!"; // IV must be of exactly 16 bytes.
// Encrypt CBC
_aes.Start(AesContext.Mode.EcbEncrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
encrypted = _aes.Update(data.ToUtf8Buffer());
_aes.Finish();
// Decrypt CBC
_aes.Start(AesContext.Mode.EcbDecrypt, key.ToUtf8Buffer(), iv.ToUtf8Buffer());
decrypted = _aes.Update(encrypted);
_aes.Finish();
// Check CBC
Debug.Assert(decrypted == data.ToUtf8Buffer());
}
}
[/csharp]
[/codeblocks]

View File

@@ -14,14 +14,14 @@
extends AStar3D
func _compute_cost(u, v):
var u_pos = get_point_position(u)
var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
var u_pos = get_point_position(u)
var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
func _estimate_cost(u, v):
var u_pos = get_point_position(u)
var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
var u_pos = get_point_position(u)
var v_pos = get_point_position(v)
return abs(u_pos.x - v_pos.x) + abs(u_pos.y - v_pos.y) + abs(u_pos.z - v_pos.z)
[/gdscript]
[csharp]
using Godot;
@@ -29,20 +29,20 @@
[GlobalClass]
public partial class MyAStar3D : AStar3D
{
public override float _ComputeCost(long fromId, long toId)
{
Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId);
public override float _ComputeCost(long fromId, long toId)
{
Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId);
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
}
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
}
public override float _EstimateCost(long fromId, long toId)
{
Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId);
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
}
public override float _EstimateCost(long fromId, long toId)
{
Vector3 fromPoint = GetPointPosition(fromId);
Vector3 toPoint = GetPointPosition(toId);
return Mathf.Abs(fromPoint.X - toPoint.X) + Mathf.Abs(fromPoint.Y - toPoint.Y) + Mathf.Abs(fromPoint.Z - toPoint.Z);
}
}
[/csharp]
[/codeblocks]

View File

@@ -115,24 +115,24 @@
var current_rotation
func _process(delta):
if Input.is_action_just_pressed("animate"):
current_rotation = get_quaternion()
state_machine.travel("Animate")
var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
if Input.is_action_just_pressed("animate"):
current_rotation = get_quaternion()
state_machine.travel("Animate")
var velocity = current_rotation * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
[/codeblocks]
By using this in combination with [method get_root_motion_rotation_accumulator], you can apply the root motion position more correctly to account for the rotation of the node.
[codeblocks]
[gdscript]
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = (animation_tree.get_root_motion_rotation_accumulator().inverse() * get_quaternion()) * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
[/codeblocks]
If [member root_motion_local] is [code]true[/code], returns the pre-multiplied translation value with the inverted rotation.
@@ -140,12 +140,12 @@
[codeblocks]
[gdscript]
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
var velocity = get_quaternion() * animation_tree.get_root_motion_position() / delta
set_velocity(velocity)
move_and_slide()
[/gdscript]
[/codeblocks]
</description>
@@ -161,12 +161,12 @@
var prev_root_motion_position_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
transform.origin += difference
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_position_accumulator = animation_tree.get_root_motion_position_accumulator()
var difference = current_root_motion_position_accumulator - prev_root_motion_position_accumulator
prev_root_motion_position_accumulator = current_root_motion_position_accumulator
transform.origin += difference
[/gdscript]
[/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
@@ -182,9 +182,9 @@
[codeblocks]
[gdscript]
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
set_quaternion(get_quaternion() * animation_tree.get_root_motion_rotation())
[/gdscript]
[/codeblocks]
</description>
@@ -201,12 +201,12 @@
var prev_root_motion_rotation_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
transform.basis *= Basis(difference)
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_rotation_accumulator = animation_tree.get_root_motion_rotation_accumulator()
var difference = prev_root_motion_rotation_accumulator.inverse() * current_root_motion_rotation_accumulator
prev_root_motion_rotation_accumulator = current_root_motion_rotation_accumulator
transform.basis *= Basis(difference)
[/gdscript]
[/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.
@@ -225,12 +225,12 @@
var scale_accum = Vector3(1, 1, 1)
func _process(delta):
if Input.is_action_just_pressed("animate"):
current_scale = get_scale()
scale_accum = Vector3(1, 1, 1)
state_machine.travel("Animate")
scale_accum += animation_tree.get_root_motion_scale()
set_scale(current_scale * scale_accum)
if Input.is_action_just_pressed("animate"):
current_scale = get_scale()
scale_accum = Vector3(1, 1, 1)
state_machine.travel("Animate")
scale_accum += animation_tree.get_root_motion_scale()
set_scale(current_scale * scale_accum)
[/gdscript]
[/codeblocks]
</description>
@@ -245,12 +245,12 @@
var prev_root_motion_scale_accumulator
func _process(delta):
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
transform.basis = transform.basis.scaled(difference)
if Input.is_action_just_pressed("animate"):
state_machine.travel("Animate")
var current_root_motion_scale_accumulator = animation_tree.get_root_motion_scale_accumulator()
var difference = current_root_motion_scale_accumulator - prev_root_motion_scale_accumulator
prev_root_motion_scale_accumulator = current_root_motion_scale_accumulator
transform.basis = transform.basis.scaled(difference)
[/gdscript]
[/codeblocks]
However, if the animation loops, an unintended discrete change may occur, so this is only useful for some simple use cases.

View File

@@ -57,13 +57,13 @@
extends Node
class Stats:
pass
pass
func _ready():
var a = Array([], TYPE_INT, "", null) # Array[int]
var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node]
var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword]
var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats]
var a = Array([], TYPE_INT, "", null) # Array[int]
var b = Array([], TYPE_OBJECT, "Node", null) # Array[Node]
var c = Array([], TYPE_OBJECT, "Node", Sword) # Array[Sword]
var d = Array([], TYPE_OBJECT, "RefCounted", Stats) # Array[Stats]
[/codeblock]
The [param base] array's elements are converted when necessary. If this is not possible or [param base] is already typed, this constructor fails and returns an empty [Array].
In GDScript, this constructor is usually not necessary, as it is possible to create a typed array through static typing:
@@ -164,36 +164,36 @@
[codeblocks]
[gdscript]
func greater_than_5(number):
return number &gt; 5
return number &gt; 5
func _ready():
print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true).
print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true).
print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true).
print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true).
print([6, 10, 6].all(greater_than_5)) # Prints true (3/3 elements evaluate to true).
print([4, 10, 4].all(greater_than_5)) # Prints false (1/3 elements evaluate to true).
print([4, 4, 4].all(greater_than_5)) # Prints false (0/3 elements evaluate to true).
print([].all(greater_than_5)) # Prints true (0/0 elements evaluate to true).
# Same as the first line above, but using a lambda function.
print([6, 10, 6].all(func(element): return element &gt; 5)) # Prints true
# Same as the first line above, but using a lambda function.
print([6, 10, 6].all(func(element): return element &gt; 5)) # Prints true
[/gdscript]
[csharp]
private static bool GreaterThan5(int number)
{
return number &gt; 5;
return number &gt; 5;
}
public override void _Ready()
{
// Prints True (3/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(GreaterThan5));
// Prints False (1/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 10, 4 }.All(GreaterThan5));
// Prints False (0/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 4, 4 }.All(GreaterThan5));
// Prints True (0/0 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { }.All(GreaterThan5));
// Prints True (3/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(GreaterThan5));
// Prints False (1/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 10, 4 }.All(GreaterThan5));
// Prints False (0/3 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { 4, 4, 4 }.All(GreaterThan5));
// Prints True (0/0 elements evaluate to true).
GD.Print(new Godot.Collections.Array&gt;int&lt; { }.All(GreaterThan5));
// Same as the first line above, but using a lambda function.
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(element =&gt; element &gt; 5)); // Prints True
// Same as the first line above, but using a lambda function.
GD.Print(new Godot.Collections.Array&gt;int&lt; { 6, 10, 6 }.All(element =&gt; element &gt; 5)); // Prints True
}
[/csharp]
[/codeblocks]
@@ -210,16 +210,16 @@
The [param method] should take one [Variant] parameter (the current array element) and return a [bool].
[codeblock]
func greater_than_5(number):
return number &gt; 5
return number &gt; 5
func _ready():
print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true).
print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true).
print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true).
print([].any(greater_than_5)) # Prints false (0 elements evaluate to true).
print([6, 10, 6].any(greater_than_5)) # Prints true (3 elements evaluate to true).
print([4, 10, 4].any(greater_than_5)) # Prints true (1 elements evaluate to true).
print([4, 4, 4].any(greater_than_5)) # Prints false (0 elements evaluate to true).
print([].any(greater_than_5)) # Prints false (0 elements evaluate to true).
# Same as the first line above, but using a lambda function.
print([6, 10, 6].any(func(number): return number &gt; 5)) # Prints true
# Same as the first line above, but using a lambda function.
print([6, 10, 6].any(func(number): return number &gt; 5)) # Prints true
[/codeblock]
See also [method all], [method filter], [method map] and [method reduce].
[b]Note:[/b] Unlike relying on the size of an array returned by [method filter], this method will return as early as possible to improve performance (especially with large arrays).
@@ -292,23 +292,23 @@
If [param before] is [code]true[/code] (as by default), the returned index comes before all existing elements equal to [param value] in the array.
[codeblock]
func sort_by_amount(a, b):
if a[1] &lt; b[1]:
return true
return false
if a[1] &lt; b[1]:
return true
return false
func _ready():
var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]]
var my_items = [["Tomato", 2], ["Kiwi", 5], ["Rice", 9]]
var apple = ["Apple", 5]
# "Apple" is inserted before "Kiwi".
my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple)
var apple = ["Apple", 5]
# "Apple" is inserted before "Kiwi".
my_items.insert(my_items.bsearch_custom(apple, sort_by_amount, true), apple)
var banana = ["Banana", 5]
# "Banana" is inserted after "Kiwi".
my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana)
var banana = ["Banana", 5]
# "Banana" is inserted after "Kiwi".
my_items.insert(my_items.bsearch_custom(banana, sort_by_amount, false), banana)
# Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]]
print(my_items)
# Prints [["Tomato", 2], ["Apple", 5], ["Kiwi", 5], ["Banana", 5], ["Rice", 9]]
print(my_items)
[/codeblock]
[b]Note:[/b] Calling [method bsearch_custom] on an [i]unsorted[/i] array will result in unexpected behavior. Use [method sort_custom] with [param func] before calling this method.
</description>
@@ -384,13 +384,13 @@
The [param method] receives one of the array elements as an argument, and should return [code]true[/code] to add the element to the filtered array, or [code]false[/code] to exclude it.
[codeblock]
func is_even(number):
return number % 2 == 0
return number % 2 == 0
func _ready():
print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8]
print([1, 4, 5, 8].filter(is_even)) # Prints [4, 8]
# Same as above, but using a lambda function.
print([1, 4, 5, 8].filter(func(number): return number % 2 == 0))
# Same as above, but using a lambda function.
print([1, 4, 5, 8].filter(func(number): return number % 2 == 0))
[/codeblock]
See also [method any], [method all], [method map] and [method reduce].
</description>
@@ -416,10 +416,10 @@
[codeblocks]
[gdscript]
func is_even(number):
return number % 2 == 0
return number % 2 == 0
func _ready():
print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2
print([1, 3, 4, 7].find_custom(is_even.bind())) # Prints 2
[/gdscript]
[/codeblocks]
</description>
@@ -481,7 +481,7 @@
In GDScript, this is equivalent to the [code]in[/code] operator:
[codeblock]
if 4 in [2, 4, 6, 8]:
print("4 is here!") # Will be printed.
print("4 is here!") # Will be printed.
[/codeblock]
[b]Note:[/b] For performance reasons, the search is affected by the [param value]'s [enum Variant.Type]. For example, [code]7[/code] ([int]) and [code]7.0[/code] ([float]) are not considered equal for this method.
</description>
@@ -549,13 +549,13 @@
The [param method] should take one [Variant] parameter (the current array element) and can return any [Variant].
[codeblock]
func double(number):
return number * 2
return number * 2
func _ready():
print([1, 2, 3].map(double)) # Prints [2, 4, 6]
print([1, 2, 3].map(double)) # Prints [2, 4, 6]
# Same as above, but using a lambda function.
print([1, 2, 3].map(func(element): return element * 2))
# Same as above, but using a lambda function.
print([1, 2, 3].map(func(element): return element * 2))
[/codeblock]
See also [method filter], [method reduce], [method any] and [method all].
</description>
@@ -635,36 +635,36 @@
The [param method] takes two arguments: the current value of [param accum] and the current array element. If [param accum] is [code]null[/code] (as by default), the iteration will start from the second element, with the first one used as initial value of [param accum].
[codeblock]
func sum(accum, number):
return accum + number
return accum + number
func _ready():
print([1, 2, 3].reduce(sum, 0)) # Prints 6
print([1, 2, 3].reduce(sum, 10)) # Prints 16
print([1, 2, 3].reduce(sum, 0)) # Prints 6
print([1, 2, 3].reduce(sum, 10)) # Prints 16
# Same as above, but using a lambda function.
print([1, 2, 3].reduce(func(accum, number): return accum + number, 10))
# Same as above, but using a lambda function.
print([1, 2, 3].reduce(func(accum, number): return accum + number, 10))
[/codeblock]
If [method max] is not desirable, this method may also be used to implement a custom comparator:
[codeblock]
func _ready():
var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)]
var arr = [Vector2i(5, 0), Vector2i(3, 4), Vector2i(1, 2)]
var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max)
print(longest_vec) # Prints (3, 4)
var longest_vec = arr.reduce(func(max, vec): return vec if is_length_greater(vec, max) else max)
print(longest_vec) # Prints (3, 4)
func is_length_greater(a, b):
return a.length() &gt; b.length()
return a.length() &gt; b.length()
[/codeblock]
This method can also be used to count how many elements in an array satisfy a certain condition, similar to [method count]:
[codeblock]
func is_even(number):
return number % 2 == 0
return number % 2 == 0
func _ready():
var arr = [1, 2, 3, 4, 5]
# If the current element is even, increment count, otherwise leave count the same.
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
print(even_count) # Prints 2
var arr = [1, 2, 3, 4, 5]
# If the current element is even, increment count, otherwise leave count the same.
var even_count = arr.reduce(func(count, next): return count + 1 if is_even(next) else count, 0)
print(even_count) # Prints 2
[/codeblock]
See also [method map], [method filter], [method any], and [method all].
</description>
@@ -781,18 +781,18 @@
[param func] is called as many times as necessary, receiving two array elements as arguments. The function should return [code]true[/code] if the first element should be moved [i]before[/i] the second one, otherwise it should return [code]false[/code].
[codeblock]
func sort_ascending(a, b):
if a[1] &lt; b[1]:
return true
return false
if a[1] &lt; b[1]:
return true
return false
func _ready():
var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]]
my_items.sort_custom(sort_ascending)
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
var my_items = [["Tomato", 5], ["Apple", 9], ["Rice", 4]]
my_items.sort_custom(sort_ascending)
print(my_items) # Prints [["Rice", 4], ["Tomato", 5], ["Apple", 9]]
# Sort descending, using a lambda function.
my_items.sort_custom(func(a, b): return a[1] &gt; b[1])
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
# Sort descending, using a lambda function.
my_items.sort_custom(func(a, b): return a[1] &gt; b[1])
print(my_items) # Prints [["Apple", 9], ["Tomato", 5], ["Rice", 4]]
[/codeblock]
It may also be necessary to use this method to sort strings by natural order, with [method String.naturalnocasecmp_to], as in the following example:
[codeblock]

View File

@@ -27,9 +27,9 @@
[csharp]
Vector3[] vertices =
[
new Vector3(0, 1, 0),
new Vector3(1, 0, 0),
new Vector3(0, 0, 1),
new Vector3(0, 1, 0),
new Vector3(1, 0, 0),
new Vector3(0, 0, 1),
];
// Initialize the ArrayMesh.

View File

@@ -22,10 +22,10 @@
@export var strength = 4.0
func _instantiate():
var effect = CustomAudioEffectInstance.new()
effect.base = self
var effect = CustomAudioEffectInstance.new()
effect.base = self
return effect
return effect
[/codeblock]
[b]Note:[/b] It is recommended to keep a reference to the original [AudioEffect] in the new instance. Depending on the implementation this allows the effect instance to listen for changes at run-time and be modified accordingly.
</description>

View File

@@ -14,17 +14,17 @@
var phase = 0.0
func _ready():
$AudioStreamPlayer.play()
playback = $AudioStreamPlayer.get_stream_playback()
fill_buffer()
$AudioStreamPlayer.play()
playback = $AudioStreamPlayer.get_stream_playback()
fill_buffer()
func fill_buffer():
var increment = pulse_hz / sample_hz
var frames_available = playback.get_frames_available()
var increment = pulse_hz / sample_hz
var frames_available = playback.get_frames_available()
for i in range(frames_available):
playback.push_frame(Vector2.ONE * sin(phase * TAU))
phase = fmod(phase + increment, 1.0)
for i in range(frames_available):
playback.push_frame(Vector2.ONE * sin(phase * TAU))
phase = fmod(phase + increment, 1.0)
[/gdscript]
[csharp]
[Export] public AudioStreamPlayer Player { get; set; }
@@ -36,25 +36,25 @@
public override void _Ready()
{
if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate.
{
_sampleHz = generator.MixRate;
Player.Play();
_playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback();
FillBuffer();
}
if (Player.Stream is AudioStreamGenerator generator) // Type as a generator to access MixRate.
{
_sampleHz = generator.MixRate;
Player.Play();
_playback = (AudioStreamGeneratorPlayback)Player.GetStreamPlayback();
FillBuffer();
}
}
public void FillBuffer()
{
float increment = _pulseHz / _sampleHz;
int framesAvailable = _playback.GetFramesAvailable();
float increment = _pulseHz / _sampleHz;
int framesAvailable = _playback.GetFramesAvailable();
for (int i = 0; i &lt; framesAvailable; i++)
{
_playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau));
phase = Mathf.PosMod(phase + increment, 1.0);
}
for (int i = 0; i &lt; framesAvailable; i++)
{
_playback.PushFrame(Vector2.One * (float)Mathf.Sin(phase * Mathf.Tau));
phase = Mathf.PosMod(phase + increment, 1.0);
}
}
[/csharp]
[/codeblocks]

View File

@@ -32,15 +32,15 @@
@onready var audio_player = $AudioStreamPlayer
func _ready():
get_window().files_dropped.connect(_on_files_dropped)
get_window().files_dropped.connect(_on_files_dropped)
func _on_files_dropped(files):
if files[0].get_extension() == "wav":
audio_player.stream = AudioStreamWAV.load_from_file(files[0], {
"force/max_rate": true,
"force/max_rate_hz": 11025
})
audio_player.play()
if files[0].get_extension() == "wav":
audio_player.stream = AudioStreamWAV.load_from_file(files[0], {
"force/max_rate": true,
"force/max_rate_hz": 11025
})
audio_player.play()
[/codeblock]
</description>
</method>

View File

@@ -155,9 +155,9 @@
[codeblocks]
[gdscript]
var my_basis = Basis(
Vector3(2, 0, 0),
Vector3(0, 4, 0),
Vector3(0, 0, 8)
Vector3(2, 0, 0),
Vector3(0, 4, 0),
Vector3(0, 0, 8)
)
# Rotating the Basis in any way preserves its scale.
my_basis = my_basis.rotated(Vector3.UP, TAU / 2)
@@ -167,9 +167,9 @@
[/gdscript]
[csharp]
var myBasis = new Basis(
Vector3(2.0f, 0.0f, 0.0f),
Vector3(0.0f, 4.0f, 0.0f),
Vector3(0.0f, 0.0f, 8.0f)
Vector3(2.0f, 0.0f, 0.0f),
Vector3(0.0f, 4.0f, 0.0f),
Vector3(0.0f, 0.0f, 8.0f)
);
// Rotating the Basis in any way preserves its scale.
myBasis = myBasis.Rotated(Vector3.Up, Mathf.Tau / 2.0f);
@@ -227,18 +227,17 @@
[gdscript]
# Rotate this Node3D every frame.
func _process(delta):
basis = basis.rotated(Vector3.UP, TAU * delta)
basis = basis.rotated(Vector3.RIGHT, TAU * delta)
basis = basis.orthonormalized()
basis = basis.rotated(Vector3.UP, TAU * delta)
basis = basis.rotated(Vector3.RIGHT, TAU * delta)
basis = basis.orthonormalized()
[/gdscript]
[csharp]
// Rotate this Node3D every frame.
public override void _Process(double delta)
{
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
.Rotated(Vector3.Right, Mathf.Tau * (float)delta)
.Orthonormalized();
Basis = Basis.Rotated(Vector3.Up, Mathf.Tau * (float)delta)
.Rotated(Vector3.Right, Mathf.Tau * (float)delta)
.Orthonormalized();
}
[/csharp]
[/codeblocks]
@@ -280,9 +279,9 @@
[codeblocks]
[gdscript]
var my_basis = Basis(
Vector3(1, 1, 1),
Vector3(2, 2, 2),
Vector3(3, 3, 3)
Vector3(1, 1, 1),
Vector3(2, 2, 2),
Vector3(3, 3, 3)
)
my_basis = my_basis.scaled(Vector3(0, 2, -2))
@@ -292,9 +291,9 @@
[/gdscript]
[csharp]
var myBasis = new Basis(
new Vector3(1.0f, 1.0f, 1.0f),
new Vector3(2.0f, 2.0f, 2.0f),
new Vector3(3.0f, 3.0f, 3.0f)
new Vector3(1.0f, 1.0f, 1.0f),
new Vector3(2.0f, 2.0f, 2.0f),
new Vector3(3.0f, 3.0f, 3.0f)
);
myBasis = myBasis.Scaled(new Vector3(0.0f, 2.0f, -2.0f));
@@ -317,10 +316,10 @@
var target_basis = Basis.IDENTITY.rotated(Vector3.UP, TAU / 2)
func _ready():
create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)
create_tween().tween_method(interpolate, 0.0, 1.0, 5.0).set_trans(Tween.TRANS_EXPO)
func interpolate(weight):
basis = start_basis.slerp(target_basis, weight)
basis = start_basis.slerp(target_basis, weight)
[/codeblock]
</description>
</method>
@@ -355,9 +354,9 @@
[codeblocks]
[gdscript]
var my_basis = Basis(
Vector3(1, 2, 3),
Vector3(4, 5, 6),
Vector3(7, 8, 9)
Vector3(1, 2, 3),
Vector3(4, 5, 6),
Vector3(7, 8, 9)
)
my_basis = my_basis.transposed()
@@ -367,9 +366,9 @@
[/gdscript]
[csharp]
var myBasis = new Basis(
new Vector3(1.0f, 2.0f, 3.0f),
new Vector3(4.0f, 5.0f, 6.0f),
new Vector3(7.0f, 8.0f, 9.0f)
new Vector3(1.0f, 2.0f, 3.0f),
new Vector3(4.0f, 5.0f, 6.0f),
new Vector3(7.0f, 8.0f, 9.0f)
);
myBasis = myBasis.Transposed();

View File

@@ -9,26 +9,26 @@
[codeblocks]
[gdscript]
func _ready():
var button = Button.new()
button.text = "Click me"
button.pressed.connect(_button_pressed)
add_child(button)
var button = Button.new()
button.text = "Click me"
button.pressed.connect(_button_pressed)
add_child(button)
func _button_pressed():
print("Hello world!")
print("Hello world!")
[/gdscript]
[csharp]
public override void _Ready()
{
var button = new Button();
button.Text = "Click me";
button.Pressed += ButtonPressed;
AddChild(button);
var button = new Button();
button.Text = "Click me";
button.Pressed += ButtonPressed;
AddChild(button);
}
private void ButtonPressed()
{
GD.Print("Hello world!");
GD.Print("Hello world!");
}
[/csharp]
[/codeblocks]

View File

@@ -8,42 +8,42 @@
[codeblocks]
[gdscript]
func print_args(arg1, arg2, arg3 = ""):
prints(arg1, arg2, arg3)
prints(arg1, arg2, arg3)
func test():
var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ".
callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args"
callable.call("invalid") # Invalid call, should have at least 2 arguments.
var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ".
callable.call(Vector2.UP, 42, callable) # Prints "(0.0, -1.0) 42 Node(node.gd)::print_args"
callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript]
[csharp]
// Default parameter values are not supported.
public void PrintArgs(Variant arg1, Variant arg2, Variant arg3 = default)
{
GD.PrintS(arg1, arg2, arg3);
GD.PrintS(arg1, arg2, arg3);
}
public void Test()
{
// Invalid calls fail silently.
Callable callable = new Callable(this, MethodName.PrintArgs);
callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments.
callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs"
callable.Call("invalid"); // Invalid call, should have 3 arguments.
// Invalid calls fail silently.
Callable callable = new Callable(this, MethodName.PrintArgs);
callable.Call("hello", "world"); // Default parameter values are not supported, should have 3 arguments.
callable.Call(Vector2.Up, 42, callable); // Prints "(0, -1) 42 Node(Node.cs)::PrintArgs"
callable.Call("invalid"); // Invalid call, should have 3 arguments.
}
[/csharp]
[/codeblocks]
In GDScript, it's possible to create lambda functions within a method. Lambda functions are custom callables that are not associated with an [Object] instance. Optionally, lambda functions can also be named. The name will be displayed in the debugger, or when calling [method get_method].
[codeblock]
func _init():
var my_lambda = func (message):
print(message)
var my_lambda = func (message):
print(message)
# Prints "Hello everyone!"
my_lambda.call("Hello everyone!")
# Prints "Hello everyone!"
my_lambda.call("Hello everyone!")
# Prints "Attack!", when the button_pressed signal is emitted.
button_pressed.connect(func(): print("Attack!"))
# Prints "Attack!", when the button_pressed signal is emitted.
button_pressed.connect(func(): print("Attack!"))
[/codeblock]
In GDScript, you can access methods and global functions as [Callable]s:
[codeblock]
@@ -117,12 +117,12 @@
[codeblocks]
[gdscript]
func _ready():
grab_focus.call_deferred()
grab_focus.call_deferred()
[/gdscript]
[csharp]
public override void _Ready()
{
Callable.From(GrabFocus).CallDeferred();
Callable.From(GrabFocus).CallDeferred();
}
[/csharp]
[/codeblocks]
@@ -158,10 +158,10 @@
Returns the array of arguments bound via successive [method bind] or [method unbind] calls. These arguments will be added [i]after[/i] the arguments passed to the call, from which [method get_unbound_arguments_count] arguments on the right have been previously excluded.
[codeblock]
func get_effective_arguments(callable, call_args):
assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0)
var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
result.append_array(callable.get_bound_arguments())
return result
assert(call_args.size() - callable.get_unbound_arguments_count() &gt;= 0)
var result = call_args.slice(0, call_args.size() - callable.get_unbound_arguments_count())
result.append_array(callable.get_bound_arguments())
return result
[/codeblock]
</description>
</method>
@@ -254,8 +254,8 @@
[b]Note:[/b] When this method is chained with other similar methods, the order in which the argument list is modified is read from right to left.
[codeblock]
func _ready():
foo.unbind(1).call(1, 2) # Calls foo(1).
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
foo.unbind(1).call(1, 2) # Calls foo(1).
foo.bind(3, 4).unbind(1).call(1, 2) # Calls foo(1, 3, 4), note that it does not change the arguments from bind.
[/codeblock]
</description>
</method>

View File

@@ -13,13 +13,13 @@
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
void fragment() {
vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a &gt; 0.0001) {
c.rgb /= c.a;
}
if (c.a &gt; 0.0001) {
c.rgb /= c.a;
}
COLOR *= c;
COLOR *= c;
}
[/codeblock]
[b]Note:[/b] Since [CanvasGroup] and [member CanvasItem.clip_children] both utilize the backbuffer, children of a [CanvasGroup] who have their [member CanvasItem.clip_children] set to anything other than [constant CanvasItem.CLIP_CHILDREN_DISABLED] will not function correctly.

View File

@@ -73,14 +73,14 @@
[codeblocks]
[gdscript]
for i in get_slide_collision_count():
var collision = get_slide_collision(i)
print("Collided with: ", collision.get_collider().name)
var collision = get_slide_collision(i)
print("Collided with: ", collision.get_collider().name)
[/gdscript]
[csharp]
for (int i = 0; i &lt; GetSlideCollisionCount(); i++)
{
KinematicCollision2D collision = GetSlideCollision(i);
GD.Print("Collided with: ", (collision.GetCollider() as Node).Name);
KinematicCollision2D collision = GetSlideCollision(i);
GD.Print("Collided with: ", (collision.GetCollider() as Node).Name);
}
[/csharp]
[/codeblocks]

View File

@@ -60,12 +60,12 @@
The raw normal and roughness buffer is stored in an optimized format, different than the one available in Spatial shaders. When sampling the buffer, a conversion function must be applied. Use this function, copied from [url=https://github.com/godotengine/godot/blob/da5f39889f155658cef7f7ec3cc1abb94e17d815/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl#L334-L341]here[/url]:
[codeblock]
vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
float roughness = p_normal_roughness.w;
if (roughness &gt; 0.5) {
roughness = 1.0 - roughness;
}
roughness /= (127.0 / 255.0);
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
float roughness = p_normal_roughness.w;
if (roughness &gt; 0.5) {
roughness = 1.0 - roughness;
}
roughness /= (127.0 / 255.0);
return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
}
[/codeblock]
</member>

View File

@@ -52,14 +52,14 @@
# If the file didn't load, ignore it.
if err != OK:
return
return
# Iterate over all sections.
for player in config.get_sections():
# Fetch the data for each section.
var player_name = config.get_value(player, "player_name")
var player_score = config.get_value(player, "best_score")
score_data[player_name] = player_score
# Fetch the data for each section.
var player_name = config.get_value(player, "player_name")
var player_score = config.get_value(player, "best_score")
score_data[player_name] = player_score
[/gdscript]
[csharp]
var score_data = new Godot.Collections.Dictionary();
@@ -71,16 +71,16 @@
// If the file didn't load, ignore it.
if (err != Error.Ok)
{
return;
return;
}
// Iterate over all sections.
foreach (String player in config.GetSections())
{
// Fetch the data for each section.
var player_name = (String)config.GetValue(player, "player_name");
var player_score = (int)config.GetValue(player, "best_score");
score_data[player_name] = player_score;
// Fetch the data for each section.
var player_name = (String)config.GetValue(player, "player_name");
var player_score = (int)config.GetValue(player, "best_score");
score_data[player_name] = player_score;
}
[/csharp]
[/codeblocks]

View File

@@ -41,16 +41,16 @@
[codeblocks]
[gdscript]
func _can_drop_data(position, data):
# Check position if it is relevant to you
# Otherwise, just check data
return typeof(data) == TYPE_DICTIONARY and data.has("expected")
# Check position if it is relevant to you
# Otherwise, just check data
return typeof(data) == TYPE_DICTIONARY and data.has("expected")
[/gdscript]
[csharp]
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
// Check position if it is relevant to you
// Otherwise, just check data
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("expected");
// Check position if it is relevant to you
// Otherwise, just check data
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("expected");
}
[/csharp]
[/codeblocks]
@@ -66,20 +66,20 @@
[codeblocks]
[gdscript]
func _can_drop_data(position, data):
return typeof(data) == TYPE_DICTIONARY and data.has("color")
return typeof(data) == TYPE_DICTIONARY and data.has("color")
func _drop_data(position, data):
var color = data["color"]
var color = data["color"]
[/gdscript]
[csharp]
public override bool _CanDropData(Vector2 atPosition, Variant data)
{
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("color");
return data.VariantType == Variant.Type.Dictionary &amp;&amp; data.AsGodotDictionary().ContainsKey("color");
}
public override void _DropData(Vector2 atPosition, Variant data)
{
Color color = data.AsGodotDictionary()["color"].AsColor();
Color color = data.AsGodotDictionary()["color"].AsColor();
}
[/csharp]
[/codeblocks]
@@ -95,16 +95,16 @@
[codeblocks]
[gdscript]
func _get_drag_data(position):
var mydata = make_data() # This is your custom method generating the drag data.
set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
return mydata
var mydata = make_data() # This is your custom method generating the drag data.
set_drag_preview(make_preview(mydata)) # This is your custom method generating the preview of the drag data.
return mydata
[/gdscript]
[csharp]
public override Variant _GetDragData(Vector2 atPosition)
{
var myData = MakeData(); // This is your custom method generating the drag data.
SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data.
return myData;
var myData = MakeData(); // This is your custom method generating the drag data.
SetDragPreview(MakePreview(myData)); // This is your custom method generating the preview of the drag data.
return myData;
}
[/csharp]
[/codeblocks]
@@ -135,20 +135,20 @@
[codeblocks]
[gdscript]
func _gui_input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
print("I've been clicked D:")
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
print("I've been clicked D:")
[/gdscript]
[csharp]
public override void _GuiInput(InputEvent @event)
{
if (@event is InputEventMouseButton mb)
{
if (mb.ButtonIndex == MouseButton.Left &amp;&amp; mb.Pressed)
{
GD.Print("I've been clicked D:");
}
}
if (@event is InputEventMouseButton mb)
{
if (mb.ButtonIndex == MouseButton.Left &amp;&amp; mb.Pressed)
{
GD.Print("I've been clicked D:");
}
}
}
[/csharp]
[/codeblocks]
@@ -184,16 +184,16 @@
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
var label = Label.new()
label.text = for_text
return label
var label = Label.new()
label.text = for_text
return label
[/gdscript]
[csharp]
public override Control _MakeCustomTooltip(string forText)
{
var label = new Label();
label.Text = forText;
return label;
var label = new Label();
label.Text = forText;
return label;
}
[/csharp]
[/codeblocks]
@@ -201,16 +201,16 @@
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
tooltip.get_node("Label").text = for_text
return tooltip
var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
tooltip.get_node("Label").text = for_text
return tooltip
[/gdscript]
[csharp]
public override Control _MakeCustomTooltip(string forText)
{
Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate();
tooltip.GetNode&lt;Label&gt;("Label").Text = forText;
return tooltip;
Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate();
tooltip.GetNode&lt;Label&gt;("Label").Text = forText;
return tooltip;
}
[/csharp]
[/codeblocks]
@@ -499,18 +499,18 @@
[codeblocks]
[gdscript]
func _ready():
# Get the font color defined for the current Control's class, if it exists.
modulate = get_theme_color("font_color")
# Get the font color defined for the Button class.
modulate = get_theme_color("font_color", "Button")
# Get the font color defined for the current Control's class, if it exists.
modulate = get_theme_color("font_color")
# Get the font color defined for the Button class.
modulate = get_theme_color("font_color", "Button")
[/gdscript]
[csharp]
public override void _Ready()
{
// Get the font color defined for the current Control's class, if it exists.
Modulate = GetThemeColor("font_color");
// Get the font color defined for the Button class.
Modulate = GetThemeColor("font_color", "Button");
// Get the font color defined for the current Control's class, if it exists.
Modulate = GetThemeColor("font_color");
// Get the font color defined for the Button class.
Modulate = GetThemeColor("font_color", "Button");
}
[/csharp]
[/codeblocks]
@@ -598,12 +598,12 @@
[codeblocks]
[gdscript]
func _process(delta):
grab_click_focus() # When clicking another Control node, this node will be clicked instead.
grab_click_focus() # When clicking another Control node, this node will be clicked instead.
[/gdscript]
[csharp]
public override void _Process(double delta)
{
GrabClickFocus(); // When clicking another Control node, this node will be clicked instead.
GrabClickFocus(); // When clicking another Control node, this node will be clicked instead.
}
[/csharp]
[/codeblocks]
@@ -861,12 +861,12 @@
@export var color = Color(1, 0, 0, 1)
func _get_drag_data(position):
# Use a control that is not in the tree
var cpb = ColorPickerButton.new()
cpb.color = color
cpb.size = Vector2(50, 50)
set_drag_preview(cpb)
return color
# Use a control that is not in the tree
var cpb = ColorPickerButton.new()
cpb.color = color
cpb.size = Vector2(50, 50)
set_drag_preview(cpb)
return color
[/gdscript]
[csharp]
[Export]
@@ -874,12 +874,12 @@
public override Variant _GetDragData(Vector2 atPosition)
{
// Use a control that is not in the tree
var cpb = new ColorPickerButton();
cpb.Color = _color;
cpb.Size = new Vector2(50, 50);
SetDragPreview(cpb);
return _color;
// Use a control that is not in the tree
var cpb = new ColorPickerButton();
cpb.Color = _color;
cpb.Size = new Vector2(50, 50);
SetDragPreview(cpb);
return _color;
}
[/csharp]
[/codeblocks]
@@ -1164,8 +1164,8 @@
[b]Note:[/b] If you want to check whether the mouse truly left the area, ignoring any top nodes, you can use code like this:
[codeblock]
func _on_mouse_exited():
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
# Not hovering over area.
if not Rect2(Vector2(), size).has_point(get_local_mouse_position()):
# Not hovering over area.
[/codeblock]
</description>
</signal>
@@ -1255,10 +1255,10 @@
[b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready].
[codeblock]
func _notification(what):
if what == NOTIFICATION_THEME_CHANGED:
if not is_node_ready():
await ready # Wait until ready signal.
$Label.add_theme_color_override("font_color", Color.YELLOW)
if what == NOTIFICATION_THEME_CHANGED:
if not is_node_ready():
await ready # Wait until ready signal.
$Label.add_theme_color_override("font_color", Color.YELLOW)
[/codeblock]
</constant>
<constant name="NOTIFICATION_SCROLL_BEGIN" value="47">

View File

@@ -20,10 +20,10 @@
uniform float exposure : hint_range(0, 128) = 1.0;
void sky() {
// If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below
// by replacing it with `-EYEDIR`.
vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z);
COLOR = texture(source_panorama, eyedir).rgb * exposure;
// If importing a cubemap from another engine, you may need to flip one of the `EYEDIR` components below
// by replacing it with `-EYEDIR`.
vec3 eyedir = vec3(EYEDIR.x, EYEDIR.y, EYEDIR.z);
COLOR = texture(source_panorama, eyedir).rgb * exposure;
}
[/codeblock]
After replacing the shader code and saving, specify the imported Cubemap resource in the Shader Parameters section of the ShaderMaterial in the inspector.

View File

@@ -16,26 +16,26 @@
var peers = []
func _ready():
server.listen(4242)
var key = load("key.key") # Your private key.
var cert = load("cert.crt") # Your X509 certificate.
dtls.setup(TlsOptions.server(key, cert))
server.listen(4242)
var key = load("key.key") # Your private key.
var cert = load("cert.crt") # Your X509 certificate.
dtls.setup(TlsOptions.server(key, cert))
func _process(delta):
while server.is_connection_available():
var peer = server.take_connection()
var dtls_peer = dtls.take_connection(peer)
if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
continue # It is normal that 50% of the connections fails due to cookie exchange.
print("Peer connected!")
peers.append(dtls_peer)
while server.is_connection_available():
var peer = server.take_connection()
var dtls_peer = dtls.take_connection(peer)
if dtls_peer.get_status() != PacketPeerDTLS.STATUS_HANDSHAKING:
continue # It is normal that 50% of the connections fails due to cookie exchange.
print("Peer connected!")
peers.append(dtls_peer)
for p in peers:
p.poll() # Must poll to update the state.
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
while p.get_available_packet_count() &gt; 0:
print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
p.put_packet("Hello DTLS client".to_utf8_buffer())
for p in peers:
p.poll() # Must poll to update the state.
if p.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
while p.get_available_packet_count() &gt; 0:
print("Received message from client: %s" % p.get_packet().get_string_from_utf8())
p.put_packet("Hello DTLS client".to_utf8_buffer())
[/gdscript]
[csharp]
// ServerNode.cs
@@ -43,45 +43,45 @@
public partial class ServerNode : Node
{
private DtlsServer _dtls = new DtlsServer();
private UdpServer _server = new UdpServer();
private Godot.Collections.Array&lt;PacketPeerDtls&gt; _peers = [];
private DtlsServer _dtls = new DtlsServer();
private UdpServer _server = new UdpServer();
private Godot.Collections.Array&lt;PacketPeerDtls&gt; _peers = [];
public override void _Ready()
{
_server.Listen(4242);
var key = GD.Load&lt;CryptoKey&gt;("key.key"); // Your private key.
var cert = GD.Load&lt;X509Certificate&gt;("cert.crt"); // Your X509 certificate.
_dtls.Setup(TlsOptions.Server(key, cert));
}
public override void _Ready()
{
_server.Listen(4242);
var key = GD.Load&lt;CryptoKey&gt;("key.key"); // Your private key.
var cert = GD.Load&lt;X509Certificate&gt;("cert.crt"); // Your X509 certificate.
_dtls.Setup(TlsOptions.Server(key, cert));
}
public override void _Process(double delta)
{
while (_server.IsConnectionAvailable())
{
PacketPeerUdp peer = _server.TakeConnection();
PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer);
if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
{
continue; // It is normal that 50% of the connections fails due to cookie exchange.
}
GD.Print("Peer connected!");
_peers.Add(dtlsPeer);
}
public override void _Process(double delta)
{
while (_server.IsConnectionAvailable())
{
PacketPeerUdp peer = _server.TakeConnection();
PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer);
if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking)
{
continue; // It is normal that 50% of the connections fails due to cookie exchange.
}
GD.Print("Peer connected!");
_peers.Add(dtlsPeer);
}
foreach (var p in _peers)
{
p.Poll(); // Must poll to update the state.
if (p.GetStatus() == PacketPeerDtls.Status.Connected)
{
while (p.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
}
}
}
}
foreach (var p in _peers)
{
p.Poll(); // Must poll to update the state.
if (p.GetStatus() == PacketPeerDtls.Status.Connected)
{
while (p.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Received Message From Client: {p.GetPacket().GetStringFromUtf8()}");
p.PutPacket("Hello DTLS Client".ToUtf8Buffer());
}
}
}
}
}
[/csharp]
[/codeblocks]
@@ -95,18 +95,18 @@
var connected = false
func _ready():
udp.connect_to_host("127.0.0.1", 4242)
dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!
udp.connect_to_host("127.0.0.1", 4242)
dtls.connect_to_peer(udp, false) # Use true in production for certificate validation!
func _process(delta):
dtls.poll()
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
if !connected:
# Try to contact server
dtls.put_packet("The answer is... 42!".to_utf8_buffer())
while dtls.get_available_packet_count() &gt; 0:
print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
connected = true
dtls.poll()
if dtls.get_status() == PacketPeerDTLS.STATUS_CONNECTED:
if !connected:
# Try to contact server
dtls.put_packet("The answer is... 42!".to_utf8_buffer())
while dtls.get_available_packet_count() &gt; 0:
print("Connected: %s" % dtls.get_packet().get_string_from_utf8())
connected = true
[/gdscript]
[csharp]
// ClientNode.cs
@@ -115,33 +115,33 @@
public partial class ClientNode : Node
{
private PacketPeerDtls _dtls = new PacketPeerDtls();
private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false;
private PacketPeerDtls _dtls = new PacketPeerDtls();
private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false;
public override void _Ready()
{
_udp.ConnectToHost("127.0.0.1", 4242);
_dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
}
public override void _Ready()
{
_udp.ConnectToHost("127.0.0.1", 4242);
_dtls.ConnectToPeer(_udp, validateCerts: false); // Use true in production for certificate validation!
}
public override void _Process(double delta)
{
_dtls.Poll();
if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
{
if (!_connected)
{
// Try to contact server
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
}
while (_dtls.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
_connected = true;
}
}
}
public override void _Process(double delta)
{
_dtls.Poll();
if (_dtls.GetStatus() == PacketPeerDtls.Status.Connected)
{
if (!_connected)
{
// Try to contact server
_dtls.PutPacket("The Answer Is..42!".ToUtf8Buffer());
}
while (_dtls.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Connected: {_dtls.GetPacket().GetStringFromUtf8()}");
_connected = true;
}
}
}
}
[/csharp]
[/codeblocks]

View File

@@ -24,12 +24,12 @@
[codeblocks]
[gdscript]
for i in Decal.TEXTURE_MAX:
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
[/gdscript]
[csharp]
for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++)
{
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
}
[/csharp]
[/codeblocks]
@@ -46,12 +46,12 @@
[codeblocks]
[gdscript]
for i in Decal.TEXTURE_MAX:
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
$NewDecal.set_texture(i, $OldDecal.get_texture(i))
[/gdscript]
[csharp]
for (int i = 0; i &lt; (int)Decal.DecalTexture.Max; i++)
{
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
GetNode&lt;Decal&gt;("NewDecal").SetTexture(i, GetNode&lt;Decal&gt;("OldDecal").GetTexture(i));
}
[/csharp]
[/codeblocks]

View File

@@ -14,8 +14,8 @@
var dict_variable_key = "Another key name"
var dict_variable_value = "value2"
var another_dict = {
"Some key name": "value1",
dict_variable_key: dict_variable_value,
"Some key name": "value1",
dict_variable_key: dict_variable_value,
}
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
@@ -25,16 +25,16 @@
# Additionally, key names must start with a letter or an underscore.
# Here, `some_key` is a string literal, not a variable!
another_dict = {
some_key = 42,
some_key = 42,
}
[/gdscript]
[csharp]
var myDict = new Godot.Collections.Dictionary(); // Creates an empty dictionary.
var pointsDict = new Godot.Collections.Dictionary
{
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
};
[/csharp]
[/codeblocks]
@@ -44,22 +44,22 @@
@export_enum("White", "Yellow", "Orange") var my_color: String
var points_dict = {"White": 50, "Yellow": 75, "Orange": 100}
func _ready():
# We can't use dot syntax here as `my_color` is a variable.
var points = points_dict[my_color]
# We can't use dot syntax here as `my_color` is a variable.
var points = points_dict[my_color]
[/gdscript]
[csharp]
[Export(PropertyHint.Enum, "White,Yellow,Orange")]
public string MyColor { get; set; }
private Godot.Collections.Dictionary _pointsDict = new Godot.Collections.Dictionary
{
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
};
public override void _Ready()
{
int points = (int)_pointsDict[MyColor];
int points = (int)_pointsDict[MyColor];
}
[/csharp]
[/codeblocks]
@@ -68,13 +68,13 @@
[codeblocks]
[gdscript]
var my_dict = {
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
"First Array": [1, 2, 3, 4] # Assigns an Array to a String key.
}
[/gdscript]
[csharp]
var myDict = new Godot.Collections.Dictionary
{
{"First Array", new Godot.Collections.Array{1, 2, 3, 4}}
{"First Array", new Godot.Collections.Array{1, 2, 3, 4}}
};
[/csharp]
[/codeblocks]
@@ -87,9 +87,9 @@
[csharp]
var pointsDict = new Godot.Collections.Dictionary
{
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
{"White", 50},
{"Yellow", 75},
{"Orange", 100}
};
pointsDict["Blue"] = 150; // Add "Blue" as a key and assign 150 as its value.
[/csharp]
@@ -101,20 +101,20 @@
# To access the string "Nested value" below, use `my_dict.sub_dict.sub_key` or `my_dict["sub_dict"]["sub_key"]`.
# Indexing styles can be mixed and matched depending on your needs.
var my_dict = {
"String Key": 5,
4: [1, 2, 3],
7: "Hello",
"sub_dict": {"sub_key": "Nested value"},
"String Key": 5,
4: [1, 2, 3],
7: "Hello",
"sub_dict": {"sub_key": "Nested value"},
}
[/gdscript]
[csharp]
// This is a valid dictionary.
// To access the string "Nested value" below, use `((Godot.Collections.Dictionary)myDict["sub_dict"])["sub_key"]`.
var myDict = new Godot.Collections.Dictionary {
{"String Key", 5},
{4, new Godot.Collections.Array{1,2,3}},
{7, "Hello"},
{"sub_dict", new Godot.Collections.Dictionary{{"sub_key", "Nested value"}}}
{"String Key", 5},
{4, new Godot.Collections.Array{1,2,3}},
{7, "Hello"},
{"sub_dict", new Godot.Collections.Dictionary{{"sub_key", "Nested value"}}}
};
[/csharp]
[/codeblocks]
@@ -123,13 +123,13 @@
[gdscript]
var groceries = {"Orange": 20, "Apple": 2, "Banana": 4}
for fruit in groceries:
var amount = groceries[fruit]
var amount = groceries[fruit]
[/gdscript]
[csharp]
var groceries = new Godot.Collections.Dictionary{{"Orange", 20}, {"Apple", 2}, {"Banana", 4}};
foreach (var (fruit, amount) in groceries)
{
// `fruit` is the key, `amount` is the value.
// `fruit` is the key, `amount` is the value.
}
[/csharp]
[/codeblocks]
@@ -276,8 +276,8 @@
[codeblocks]
[gdscript]
var my_dict = {
"Godot" : 4,
210 : null,
"Godot" : 4,
210 : null,
}
print(my_dict.has("Godot")) # Prints true
@@ -287,8 +287,8 @@
[csharp]
var myDict = new Godot.Collections.Dictionary
{
{ "Godot", 4 },
{ 210, default },
{ "Godot", 4 },
{ 210, default },
};
GD.Print(myDict.ContainsKey("Godot")); // Prints True
@@ -299,7 +299,7 @@
In GDScript, this is equivalent to the [code]in[/code] operator:
[codeblock]
if "Godot" in {"Godot": 4}:
print("The key is here!") # Will be printed.
print("The key is here!") # Will be printed.
[/codeblock]
[b]Note:[/b] This method returns [code]true[/code] as long as the [param key] exists, even if its corresponding value is [code]null[/code].
</description>
@@ -423,14 +423,14 @@
[csharp]
var dict = new Godot.Collections.Dictionary
{
["item"] = "sword",
["quantity"] = 2,
["item"] = "sword",
["quantity"] = 2,
};
var otherDict = new Godot.Collections.Dictionary
{
["quantity"] = 15,
["color"] = "silver",
["quantity"] = 15,
["color"] = "silver",
};
// Overwriting of existing keys is disabled by default.

View File

@@ -19,44 +19,44 @@
[codeblocks]
[gdscript]
func dir_contents(path):
var dir = DirAccess.open(path)
if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
print("Found directory: " + file_name)
else:
print("Found file: " + file_name)
file_name = dir.get_next()
else:
print("An error occurred when trying to access the path.")
var dir = DirAccess.open(path)
if dir:
dir.list_dir_begin()
var file_name = dir.get_next()
while file_name != "":
if dir.current_is_dir():
print("Found directory: " + file_name)
else:
print("Found file: " + file_name)
file_name = dir.get_next()
else:
print("An error occurred when trying to access the path.")
[/gdscript]
[csharp]
public void DirContents(string path)
{
using var dir = DirAccess.Open(path);
if (dir != null)
{
dir.ListDirBegin();
string fileName = dir.GetNext();
while (fileName != "")
{
if (dir.CurrentIsDir())
{
GD.Print($"Found directory: {fileName}");
}
else
{
GD.Print($"Found file: {fileName}");
}
fileName = dir.GetNext();
}
}
else
{
GD.Print("An error occurred when trying to access the path.");
}
using var dir = DirAccess.Open(path);
if (dir != null)
{
dir.ListDirBegin();
string fileName = dir.GetNext();
while (fileName != "")
{
if (dir.CurrentIsDir())
{
GD.Print($"Found directory: {fileName}");
}
else
{
GD.Print($"Found file: {fileName}");
}
fileName = dir.GetNext();
}
}
else
{
GD.Print("An error occurred when trying to access the path.");
}
}
[/csharp]
[/codeblocks]

View File

@@ -1783,7 +1783,7 @@
[codeblock]
var refresh_rate = DisplayServer.screen_get_refresh_rate()
if refresh_rate &lt; 0:
refresh_rate = 60.0
refresh_rate = 60.0
[/codeblock]
[b]Note:[/b] One of the following constants can be used as [param screen]: [constant SCREEN_OF_MAIN_WINDOW], [constant SCREEN_PRIMARY], [constant SCREEN_WITH_MOUSE_FOCUS], or [constant SCREEN_WITH_KEYBOARD_FOCUS].
[b]Note:[/b] This method is implemented on Android, iOS, macOS, Linux (X11 and Wayland), and Windows. On other platforms, this method always returns [code]-1.0[/code].

View File

@@ -26,7 +26,7 @@
Add custom option to the context menu of the plugin's specified slot. When the option is activated, [param callback] will be called. Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock]
func _popup_menu(paths):
add_context_menu_item("File Custom options", handle, ICON)
add_context_menu_item("File Custom options", handle, ICON)
[/codeblock]
If you want to assign shortcut to the menu item, use [method add_context_menu_item_from_shortcut] instead.
</description>
@@ -40,10 +40,10 @@
Add custom option to the context menu of the plugin's specified slot. The option will have the [param shortcut] assigned and reuse its callback. The shortcut has to be registered beforehand with [method add_menu_shortcut].
[codeblock]
func _init():
add_menu_shortcut(SHORTCUT, handle)
add_menu_shortcut(SHORTCUT, handle)
func _popup_menu(paths):
add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
add_context_menu_item_from_shortcut("File Custom options", SHORTCUT, ICON)
[/codeblock]
</description>
</method>
@@ -56,12 +56,12 @@
Add a submenu to the context menu of the plugin's specified slot. The submenu is not automatically handled, you need to connect to its signals yourself. Also the submenu is freed on every popup, so provide a new [PopupMenu] every time.
[codeblock]
func _popup_menu(paths):
var popup_menu = PopupMenu.new()
popup_menu.add_item("Blue")
popup_menu.add_item("White")
popup_menu.id_pressed.connect(_on_color_submenu_option)
var popup_menu = PopupMenu.new()
popup_menu.add_item("Blue")
popup_menu.add_item("White")
popup_menu.id_pressed.connect(_on_color_submenu_option)
add_context_submenu_item("Set Node Color", popup_menu)
add_context_submenu_item("Set Node Color", popup_menu)
[/codeblock]
</description>
</method>
@@ -73,7 +73,7 @@
Registers a shortcut associated with the plugin's context menu. This method should be called once (e.g. in plugin's [method Object._init]). [param callback] will be called when user presses the specified [param shortcut] while the menu's context is in effect (e.g. FileSystem dock is focused). Callback should take single [Array] argument; array contents depend on context menu slot.
[codeblock]
func _init():
add_menu_shortcut(SHORTCUT, handle)
add_menu_shortcut(SHORTCUT, handle)
[/codeblock]
</description>
</method>
@@ -95,7 +95,7 @@
Context menu of Script editor's code editor. [method _popup_menu] will be called with the path to the [CodeEdit] node. You can fetch it using this code:
[codeblock]
func _popup_menu(paths):
var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
var code_edit = Engine.get_main_loop().root.get_node(paths[0]);
[/codeblock]
The option callback will receive reference to that node. You can use [CodeEdit] methods to perform symbol lookups etc.
</constant>
@@ -106,7 +106,7 @@
Context menu of 2D editor's basic right-click menu. [method _popup_menu] will be called with paths to all [CanvasItem] nodes under the cursor. You can fetch them using this code:
[codeblock]
func _popup_menu(paths):
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
var canvas_item = Engine.get_main_loop().root.get_node(paths[0]); # Replace 0 with the desired index.
[/codeblock]
The paths array is empty if there weren't any nodes under cursor. The option callback will receive a typed array of [CanvasItem] nodes.
</constant>

View File

@@ -15,34 +15,34 @@
class ExampleEditorDebugger extends EditorDebuggerPlugin:
func _has_capture(capture):
# Return true if you wish to handle messages with the prefix "my_plugin:".
return capture == "my_plugin"
func _has_capture(capture):
# Return true if you wish to handle messages with the prefix "my_plugin:".
return capture == "my_plugin"
func _capture(message, data, session_id):
if message == "my_plugin:ping":
get_session(session_id).send_message("my_plugin:echo", data)
return true
return false
func _capture(message, data, session_id):
if message == "my_plugin:ping":
get_session(session_id).send_message("my_plugin:echo", data)
return true
return false
func _setup_session(session_id):
# Add a new tab in the debugger session UI containing a label.
var label = Label.new()
label.name = "Example plugin" # Will be used as the tab title.
label.text = "Example plugin"
var session = get_session(session_id)
# Listens to the session started and stopped signals.
session.started.connect(func (): print("Session started"))
session.stopped.connect(func (): print("Session stopped"))
session.add_session_tab(label)
func _setup_session(session_id):
# Add a new tab in the debugger session UI containing a label.
var label = Label.new()
label.name = "Example plugin" # Will be used as the tab title.
label.text = "Example plugin"
var session = get_session(session_id)
# Listens to the session started and stopped signals.
session.started.connect(func (): print("Session started"))
session.stopped.connect(func (): print("Session stopped"))
session.add_session_tab(label)
var debugger = ExampleEditorDebugger.new()
func _enter_tree():
add_debugger_plugin(debugger)
add_debugger_plugin(debugger)
func _exit_tree():
remove_debugger_plugin(debugger)
remove_debugger_plugin(debugger)
[/gdscript]
[/codeblocks]
To connect on the running game side, use the [EngineDebugger] singleton:
@@ -51,15 +51,15 @@
extends Node
func _ready():
EngineDebugger.register_message_capture("my_plugin", _capture)
EngineDebugger.send_message("my_plugin:ping", ["test"])
EngineDebugger.register_message_capture("my_plugin", _capture)
EngineDebugger.send_message("my_plugin:ping", ["test"])
func _capture(message, data):
# Note that the "my_plugin:" prefix is not used here.
if message == "echo":
prints("Echo received:", data)
return true
return false
# Note that the "my_plugin:" prefix is not used here.
if message == "echo":
prints("Echo received:", data)
return true
return false
[/gdscript]
[/codeblocks]
[b]Note:[/b] While the game is running, [method @GlobalScope.print] and similar functions [i]called in the editor[/i] do not print anything, the Output Log prints only game messages.

View File

@@ -202,20 +202,20 @@
Return a [Dictionary] of override values for export options, that will be used instead of user-provided values. Overridden options will be hidden from the user interface.
[codeblock]
class MyExportPlugin extends EditorExportPlugin:
func _get_name() -&gt; String:
return "MyExportPlugin"
func _get_name() -&gt; String:
return "MyExportPlugin"
func _supports_platform(platform) -&gt; bool:
if platform is EditorExportPlatformPC:
# Run on all desktop platforms including Windows, MacOS and Linux.
return true
return false
func _supports_platform(platform) -&gt; bool:
if platform is EditorExportPlatformPC:
# Run on all desktop platforms including Windows, MacOS and Linux.
return true
return false
func _get_export_options_overrides(platform) -&gt; Dictionary:
# Override "Embed PCK" to always be enabled.
return {
"binary_format/embed_pck": true,
}
func _get_export_options_overrides(platform) -&gt; Dictionary:
# Override "Embed PCK" to always be enabled.
return {
"binary_format/embed_pck": true,
}
[/codeblock]
</description>
</method>

View File

@@ -13,104 +13,104 @@
extends EditorImportPlugin
func _get_importer_name():
return "my.special.plugin"
return "my.special.plugin"
func _get_visible_name():
return "Special Mesh"
return "Special Mesh"
func _get_recognized_extensions():
return ["special", "spec"]
return ["special", "spec"]
func _get_save_extension():
return "mesh"
return "mesh"
func _get_resource_type():
return "Mesh"
return "Mesh"
func _get_preset_count():
return 1
return 1
func _get_preset_name(preset_index):
return "Default"
return "Default"
func _get_import_options(path, preset_index):
return [{"name": "my_option", "default_value": false}]
return [{"name": "my_option", "default_value": false}]
func _import(source_file, save_path, options, platform_variants, gen_files):
var file = FileAccess.open(source_file, FileAccess.READ)
if file == null:
return FAILED
var mesh = ArrayMesh.new()
# Fill the Mesh with data read in "file", left as an exercise to the reader.
var file = FileAccess.open(source_file, FileAccess.READ)
if file == null:
return FAILED
var mesh = ArrayMesh.new()
# Fill the Mesh with data read in "file", left as an exercise to the reader.
var filename = save_path + "." + _get_save_extension()
return ResourceSaver.save(mesh, filename)
var filename = save_path + "." + _get_save_extension()
return ResourceSaver.save(mesh, filename)
[/gdscript]
[csharp]
using Godot;
public partial class MySpecialPlugin : EditorImportPlugin
{
public override string _GetImporterName()
{
return "my.special.plugin";
}
public override string _GetImporterName()
{
return "my.special.plugin";
}
public override string _GetVisibleName()
{
return "Special Mesh";
}
public override string _GetVisibleName()
{
return "Special Mesh";
}
public override string[] _GetRecognizedExtensions()
{
return ["special", "spec"];
}
public override string[] _GetRecognizedExtensions()
{
return ["special", "spec"];
}
public override string _GetSaveExtension()
{
return "mesh";
}
public override string _GetSaveExtension()
{
return "mesh";
}
public override string _GetResourceType()
{
return "Mesh";
}
public override string _GetResourceType()
{
return "Mesh";
}
public override int _GetPresetCount()
{
return 1;
}
public override int _GetPresetCount()
{
return 1;
}
public override string _GetPresetName(int presetIndex)
{
return "Default";
}
public override string _GetPresetName(int presetIndex)
{
return "Default";
}
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetImportOptions(string path, int presetIndex)
{
return
[
new Godot.Collections.Dictionary
{
{ "name", "myOption" },
{ "default_value", false },
},
];
}
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetImportOptions(string path, int presetIndex)
{
return
[
new Godot.Collections.Dictionary
{
{ "name", "myOption" },
{ "default_value", false },
},
];
}
public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array&lt;string&gt; platformVariants, Godot.Collections.Array&lt;string&gt; genFiles)
{
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
if (file.GetError() != Error.Ok)
{
return Error.Failed;
}
public override Error _Import(string sourceFile, string savePath, Godot.Collections.Dictionary options, Godot.Collections.Array&lt;string&gt; platformVariants, Godot.Collections.Array&lt;string&gt; genFiles)
{
using var file = FileAccess.Open(sourceFile, FileAccess.ModeFlags.Read);
if (file.GetError() != Error.Ok)
{
return Error.Failed;
}
var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader.
string filename = $"{savePath}.{_GetSaveExtension()}";
return ResourceSaver.Save(mesh, filename);
}
var mesh = new ArrayMesh();
// Fill the Mesh with data read in "file", left as an exercise to the reader.
string filename = $"{savePath}.{_GetSaveExtension()}";
return ResourceSaver.Save(mesh, filename);
}
}
[/csharp]
[/codeblocks]
@@ -164,22 +164,22 @@
[codeblocks]
[gdscript]
func _get_option_visibility(option, options):
# Only show the lossy quality setting if the compression mode is set to "Lossy".
if option == "compress/lossy_quality" and options.has("compress/mode"):
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
# Only show the lossy quality setting if the compression mode is set to "Lossy".
if option == "compress/lossy_quality" and options.has("compress/mode"):
return int(options["compress/mode"]) == COMPRESS_LOSSY # This is a constant that you set
return true
return true
[/gdscript]
[csharp]
public void _GetOptionVisibility(string option, Godot.Collections.Dictionary options)
{
// Only show the lossy quality setting if the compression mode is set to "Lossy".
if (option == "compress/lossy_quality" &amp;&amp; options.ContainsKey("compress/mode"))
{
return (int)options["compress/mode"] == CompressLossy; // This is a constant you set
}
// Only show the lossy quality setting if the compression mode is set to "Lossy".
if (option == "compress/lossy_quality" &amp;&amp; options.ContainsKey("compress/mode"))
{
return (int)options["compress/mode"] == CompressLossy; // This is a constant you set
}
return true;
return true;
}
[/csharp]
[/codeblocks]

View File

@@ -356,14 +356,14 @@
[b]Example:[/b] Display the node selection dialog as soon as this node is added to the tree for the first time:
[codeblock]
func _ready():
if Engine.is_editor_hint():
EditorInterface.popup_node_selector(_on_node_selected, ["Button"])
if Engine.is_editor_hint():
EditorInterface.popup_node_selector(_on_node_selected, ["Button"])
func _on_node_selected(node_path):
if node_path.is_empty():
print("node selection canceled")
else:
print("selected ", node_path)
if node_path.is_empty():
print("node selection canceled")
else:
print("selected ", node_path)
[/codeblock]
</description>
</method>
@@ -377,14 +377,14 @@
Pops up an editor dialog for selecting properties from [param object]. The [param callback] must take a single argument of type [NodePath]. It is called on the selected property path (see [method NodePath.get_as_property_path]) or the empty path [code]^""[/code] if the dialog is canceled. If [param type_filter] is provided, the dialog will only show properties that match one of the listed [enum Variant.Type] values. If [param current_value] is provided, the property will be selected automatically in the property list, if it exists.
[codeblock]
func _ready():
if Engine.is_editor_hint():
EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT])
if Engine.is_editor_hint():
EditorInterface.popup_property_selector(this, _on_property_selected, [TYPE_INT])
func _on_property_selected(property_path):
if property_path.is_empty():
print("property selection canceled")
else:
print("selected ", property_path)
if property_path.is_empty():
print("property selection canceled")
else:
print("selected ", property_path)
[/codeblock]
</description>
</method>

View File

@@ -59,32 +59,32 @@
[codeblocks]
[gdscript]
func _forward_3d_draw_over_viewport(overlay):
# Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
# Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_3d_gui_input(camera, event):
if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved.
update_overlays()
return EditorPlugin.AFTER_GUI_INPUT_STOP
return EditorPlugin.AFTER_GUI_INPUT_PASS
if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved.
update_overlays()
return EditorPlugin.AFTER_GUI_INPUT_STOP
return EditorPlugin.AFTER_GUI_INPUT_PASS
[/gdscript]
[csharp]
public override void _Forward3DDrawOverViewport(Control viewportControl)
{
// Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
// Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
}
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D viewportCamera, InputEvent @event)
{
if (@event is InputEventMouseMotion)
{
// Redraw the viewport when the cursor is moved.
UpdateOverlays();
return EditorPlugin.AfterGuiInput.Stop;
}
return EditorPlugin.AfterGuiInput.Pass;
if (@event is InputEventMouseMotion)
{
// Redraw the viewport when the cursor is moved.
UpdateOverlays();
return EditorPlugin.AfterGuiInput.Stop;
}
return EditorPlugin.AfterGuiInput.Pass;
}
[/csharp]
[/codeblocks]
@@ -108,13 +108,13 @@
[gdscript]
# Prevents the InputEvent from reaching other Editor classes.
func _forward_3d_gui_input(camera, event):
return EditorPlugin.AFTER_GUI_INPUT_STOP
return EditorPlugin.AFTER_GUI_INPUT_STOP
[/gdscript]
[csharp]
// Prevents the InputEvent from reaching other Editor classes.
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
{
return EditorPlugin.AfterGuiInput.Stop;
return EditorPlugin.AfterGuiInput.Stop;
}
[/csharp]
[/codeblocks]
@@ -123,13 +123,13 @@
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
func _forward_3d_gui_input(camera, event):
return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS
return EditorPlugin.AFTER_GUI_INPUT_STOP if event is InputEventMouseMotion else EditorPlugin.AFTER_GUI_INPUT_PASS
[/gdscript]
[csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types.
public override EditorPlugin.AfterGuiInput _Forward3DGuiInput(Camera3D camera, InputEvent @event)
{
return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass;
return @event is InputEventMouseMotion ? EditorPlugin.AfterGuiInput.Stop : EditorPlugin.AfterGuiInput.Pass;
}
[/csharp]
[/codeblocks]
@@ -143,32 +143,32 @@
[codeblocks]
[gdscript]
func _forward_canvas_draw_over_viewport(overlay):
# Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
# Draw a circle at the cursor's position.
overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved.
update_overlays()
return true
return false
if event is InputEventMouseMotion:
# Redraw the viewport when the cursor is moved.
update_overlays()
return true
return false
[/gdscript]
[csharp]
public override void _ForwardCanvasDrawOverViewport(Control viewportControl)
{
// Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
// Draw a circle at the cursor's position.
viewportControl.DrawCircle(viewportControl.GetLocalMousePosition(), 64, Colors.White);
}
public override bool _ForwardCanvasGuiInput(InputEvent @event)
{
if (@event is InputEventMouseMotion)
{
// Redraw the viewport when the cursor is moved.
UpdateOverlays();
return true;
}
return false;
if (@event is InputEventMouseMotion)
{
// Redraw the viewport when the cursor is moved.
UpdateOverlays();
return true;
}
return false;
}
[/csharp]
[/codeblocks]
@@ -191,13 +191,13 @@
[gdscript]
# Prevents the InputEvent from reaching other Editor classes.
func _forward_canvas_gui_input(event):
return true
return true
[/gdscript]
[csharp]
// Prevents the InputEvent from reaching other Editor classes.
public override bool ForwardCanvasGuiInput(InputEvent @event)
{
return true;
return true;
}
[/csharp]
[/codeblocks]
@@ -206,19 +206,19 @@
[gdscript]
# Consumes InputEventMouseMotion and forwards other InputEvent types.
func _forward_canvas_gui_input(event):
if (event is InputEventMouseMotion):
return true
return false
if (event is InputEventMouseMotion):
return true
return false
[/gdscript]
[csharp]
// Consumes InputEventMouseMotion and forwards other InputEvent types.
public override bool _ForwardCanvasGuiInput(InputEvent @event)
{
if (@event is InputEventMouseMotion)
{
return true;
}
return false;
if (@event is InputEventMouseMotion)
{
return true;
}
return false;
}
[/csharp]
[/codeblocks]
@@ -239,18 +239,18 @@
[codeblocks]
[gdscript]
func _get_plugin_icon():
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/gdscript]
[csharp]
public override Texture2D _GetPluginIcon()
{
// You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon:
return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
// You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon:
return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
}
[/csharp]
[/codeblocks]
@@ -272,8 +272,8 @@
[b]Note:[/b] You must implement [method _get_plugin_name] for the state to be stored and restored correctly.
[codeblock]
func _get_state():
var state = {"zoom": zoom, "preferred_color": my_color}
return state
var state = {"zoom": zoom, "preferred_color": my_color}
return state
[/codeblock]
</description>
</method>
@@ -286,22 +286,22 @@
If the user confirms saving, [method _save_external_data] will be called, before closing the editor.
[codeblock]
func _get_unsaved_status(for_scene):
if not unsaved:
return ""
if not unsaved:
return ""
if for_scene.is_empty():
return "Save changes in MyCustomPlugin before closing?"
else:
return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
if for_scene.is_empty():
return "Save changes in MyCustomPlugin before closing?"
else:
return "Scene %s has changes from MyCustomPlugin. Save before closing?" % for_scene.get_file()
func _save_external_data():
unsaved = false
unsaved = false
[/codeblock]
If the plugin has no scene-specific changes, you can ignore the calls when closing scenes:
[codeblock]
func _get_unsaved_status(for_scene):
if not for_scene.is_empty():
return ""
if not for_scene.is_empty():
return ""
[/codeblock]
</description>
</method>
@@ -313,8 +313,8 @@
Use [method _set_window_layout] to restore your saved layout.
[codeblock]
func _get_window_layout(configuration):
configuration.set_value("MyPlugin", "window_position", $Window.position)
configuration.set_value("MyPlugin", "icon_color", $Icon.modulate)
configuration.set_value("MyPlugin", "window_position", $Window.position)
configuration.set_value("MyPlugin", "icon_color", $Icon.modulate)
[/codeblock]
</description>
</method>
@@ -336,21 +336,21 @@
var plugin_control
func _enter_tree():
plugin_control = preload("my_plugin_control.tscn").instantiate()
EditorInterface.get_editor_main_screen().add_child(plugin_control)
plugin_control.hide()
plugin_control = preload("my_plugin_control.tscn").instantiate()
EditorInterface.get_editor_main_screen().add_child(plugin_control)
plugin_control.hide()
func _has_main_screen():
return true
return true
func _make_visible(visible):
plugin_control.visible = visible
plugin_control.visible = visible
func _get_plugin_name():
return "My Super Cool Plugin 3000"
return "My Super Cool Plugin 3000"
func _get_plugin_icon():
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/codeblock]
</description>
</method>
@@ -376,8 +376,8 @@
[b]Note:[/b] Your plugin must implement [method _get_plugin_name], otherwise it will not be recognized and this method will not be called.
[codeblock]
func _set_state(data):
zoom = data.get("zoom", 1.0)
preferred_color = data.get("my_color", Color.WHITE)
zoom = data.get("zoom", 1.0)
preferred_color = data.get("my_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -388,8 +388,8 @@
Restore the plugin GUI layout and data saved by [method _get_window_layout]. This method is called for every plugin on editor startup. Use the provided [param configuration] file to read your saved data.
[codeblock]
func _set_window_layout(configuration):
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
$Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
$Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -502,10 +502,10 @@
var inspector_plugin = MyInspectorPlugin.new()
func _enter_tree():
add_inspector_plugin(inspector_plugin)
add_inspector_plugin(inspector_plugin)
func _exit_tree():
remove_inspector_plugin(inspector_plugin)
remove_inspector_plugin(inspector_plugin)
[/gdscript]
[/codeblocks]
</description>

View File

@@ -11,15 +11,15 @@
extends EditorResourceConversionPlugin
func _handles(resource: Resource):
return resource is ImageTexture
return resource is ImageTexture
func _converts_to():
return "PortableCompressedTexture2D"
return "PortableCompressedTexture2D"
func _convert(itex: Resource):
var ptex = PortableCompressedTexture2D.new()
ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
return ptex
var ptex = PortableCompressedTexture2D.new()
ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
return ptex
[/gdscript]
[/codeblocks]
To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.

View File

@@ -30,10 +30,10 @@
[b]Note:[/b] If you decide to discard the [param base], make sure to call [method Node.queue_free], because it's not freed automatically.
[codeblock]
func _make_tooltip_for_path(path, metadata, base):
var t_rect = TextureRect.new()
request_thumbnail(path, t_rect)
base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip.
return base
var t_rect = TextureRect.new()
request_thumbnail(path, t_rect)
base.add_child(t_rect) # The TextureRect will appear at the bottom of the tooltip.
return base
[/codeblock]
</description>
</method>

View File

@@ -14,15 +14,15 @@
# This sample changes all node names.
# Called right after the scene is imported and gets the root node.
func _post_import(scene):
# Change all node names to "modified_[oldnodename]"
iterate(scene)
return scene # Remember to return the imported scene
# Change all node names to "modified_[oldnodename]"
iterate(scene)
return scene # Remember to return the imported scene
func iterate(node):
if node != null:
node.name = "modified_" + node.name
for child in node.get_children():
iterate(child)
if node != null:
node.name = "modified_" + node.name
for child in node.get_children():
iterate(child)
[/gdscript]
[csharp]
using Godot;
@@ -32,24 +32,24 @@
[Tool]
public partial class NodeRenamer : EditorScenePostImport
{
public override GodotObject _PostImport(Node scene)
{
// Change all node names to "modified_[oldnodename]"
Iterate(scene);
return scene; // Remember to return the imported scene
}
public override GodotObject _PostImport(Node scene)
{
// Change all node names to "modified_[oldnodename]"
Iterate(scene);
return scene; // Remember to return the imported scene
}
public void Iterate(Node node)
{
if (node != null)
{
node.Name = $"modified_{node.Name}";
foreach (Node child in node.GetChildren())
{
Iterate(child);
}
}
}
public void Iterate(Node node)
{
if (node != null)
{
node.Name = $"modified_{node.Name}";
foreach (Node child in node.GetChildren())
{
Iterate(child);
}
}
}
}
[/csharp]
[/codeblocks]

View File

@@ -14,7 +14,7 @@
extends EditorScript
func _run():
print("Hello from the Godot Editor!")
print("Hello from the Godot Editor!")
[/gdscript]
[csharp]
using Godot;
@@ -22,10 +22,10 @@
[Tool]
public partial class HelloEditor : EditorScript
{
public override void _Run()
{
GD.Print("Hello from the Godot Editor!");
}
public override void _Run()
{
GD.Print("Hello from the Godot Editor!");
}
}
[/csharp]
[/codeblocks]

View File

@@ -44,10 +44,10 @@
settings.set("category/property_name", 0)
var property_info = {
"name": "category/property_name",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three"
"name": "category/property_name",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three"
}
settings.add_property_info(property_info)
@@ -58,10 +58,10 @@
var propertyInfo = new Godot.Collections.Dictionary
{
{"name", "category/propertyName"},
{"type", Variant.Type.Int},
{"hint", PropertyHint.Enum},
{"hint_string", "one,two,three"}
{"name", "category/propertyName"},
{"type", Variant.Type.Int},
{"hint", PropertyHint.Enum},
{"hint_string", "one,two,three"}
};
settings.AddPropertyInfo(propertyInfo);

View File

@@ -14,18 +14,18 @@
extends EditorTranslationParserPlugin
func _parse_file(path):
var ret: Array[PackedStringArray] = []
var file = FileAccess.open(path, FileAccess.READ)
var text = file.get_as_text()
var split_strs = text.split(",", false)
for s in split_strs:
ret.append(PackedStringArray([s]))
#print("Extracted string: " + s)
var ret: Array[PackedStringArray] = []
var file = FileAccess.open(path, FileAccess.READ)
var text = file.get_as_text()
var split_strs = text.split(",", false)
for s in split_strs:
ret.append(PackedStringArray([s]))
#print("Extracted string: " + s)
return ret
return ret
func _get_recognized_extensions():
return ["csv"]
return ["csv"]
[/gdscript]
[csharp]
using Godot;
@@ -33,24 +33,24 @@
[Tool]
public partial class CustomParser : EditorTranslationParserPlugin
{
public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path)
{
Godot.Collections.Array&lt;string[]&gt; ret;
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
string text = file.GetAsText();
string[] splitStrs = text.Split(",", allowEmpty: false);
foreach (string s in splitStrs)
{
ret.Add([s]);
//GD.Print($"Extracted string: {s}");
}
return ret;
}
public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path)
{
Godot.Collections.Array&lt;string[]&gt; ret;
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
string text = file.GetAsText();
string[] splitStrs = text.Split(",", allowEmpty: false);
foreach (string s in splitStrs)
{
ret.Add([s]);
//GD.Print($"Extracted string: {s}");
}
return ret;
}
public override string[] _GetRecognizedExtensions()
{
return ["csv"];
}
public override string[] _GetRecognizedExtensions()
{
return ["csv"];
}
}
[/csharp]
[/codeblocks]
@@ -77,24 +77,24 @@
[codeblocks]
[gdscript]
func _parse_file(path):
var res = ResourceLoader.load(path, "Script")
var text = res.source_code
# Parsing logic.
var res = ResourceLoader.load(path, "Script")
var text = res.source_code
# Parsing logic.
func _get_recognized_extensions():
return ["gd"]
return ["gd"]
[/gdscript]
[csharp]
public override Godot.Collections.Array&lt;string[]&gt; _ParseFile(string path)
{
var res = ResourceLoader.Load&lt;Script&gt;(path, "Script");
string text = res.SourceCode;
// Parsing logic.
var res = ResourceLoader.Load&lt;Script&gt;(path, "Script");
string text = res.SourceCode;
// Parsing logic.
}
public override string[] _GetRecognizedExtensions()
{
return ["gd"];
return ["gd"];
}
[/csharp]
[/codeblocks]

View File

@@ -90,18 +90,18 @@
[codeblocks]
[gdscript]
func _physics_process(_delta):
if Engine.get_physics_frames() % 2 == 0:
pass # Run expensive logic only once every 2 physics frames here.
if Engine.get_physics_frames() % 2 == 0:
pass # Run expensive logic only once every 2 physics frames here.
[/gdscript]
[csharp]
public override void _PhysicsProcess(double delta)
{
base._PhysicsProcess(delta);
base._PhysicsProcess(delta);
if (Engine.GetPhysicsFrames() % 2 == 0)
{
// Run expensive logic only once every 2 physics frames here.
}
if (Engine.GetPhysicsFrames() % 2 == 0)
{
// Run expensive logic only once every 2 physics frames here.
}
}
[/csharp]
[/codeblocks]
@@ -121,18 +121,18 @@
[codeblocks]
[gdscript]
func _process(_delta):
if Engine.get_process_frames() % 5 == 0:
pass # Run expensive logic only once every 5 process (render) frames here.
if Engine.get_process_frames() % 5 == 0:
pass # Run expensive logic only once every 5 process (render) frames here.
[/gdscript]
[csharp]
public override void _Process(double delta)
{
base._Process(delta);
base._Process(delta);
if (Engine.GetProcessFrames() % 5 == 0)
{
// Run expensive logic only once every 5 process (render) frames here.
}
if (Engine.GetProcessFrames() % 5 == 0)
{
// Run expensive logic only once every 5 process (render) frames here.
}
}
[/csharp]
[/codeblocks]
@@ -183,18 +183,18 @@
[codeblocks]
[gdscript]
if Engine.get_version_info().hex &gt;= 0x040100:
pass # Do things specific to version 4.1 or later.
pass # Do things specific to version 4.1 or later.
else:
pass # Do things specific to versions before 4.1.
pass # Do things specific to versions before 4.1.
[/gdscript]
[csharp]
if ((int)Engine.GetVersionInfo()["hex"] &gt;= 0x040100)
{
// Do things specific to version 4.1 or later.
// Do things specific to version 4.1 or later.
}
else
{
// Do things specific to versions before 4.1.
// Do things specific to versions before 4.1.
}
[/csharp]
[/codeblocks]
@@ -235,15 +235,15 @@
[codeblocks]
[gdscript]
if Engine.is_editor_hint():
draw_gizmos()
draw_gizmos()
else:
simulate_physics()
simulate_physics()
[/gdscript]
[csharp]
if (Engine.IsEditorHint())
DrawGizmos();
DrawGizmos();
else
SimulatePhysics();
SimulatePhysics();
[/csharp]
[/codeblocks]
See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url] in the documentation for more information.
@@ -262,15 +262,15 @@
Returns [code]true[/code] if the engine is inside the fixed physics process step of the main loop.
[codeblock]
func _enter_tree():
# Depending on when the node is added to the tree,
# prints either "true" or "false".
print(Engine.is_in_physics_frame())
# Depending on when the node is added to the tree,
# prints either "true" or "false".
print(Engine.is_in_physics_frame())
func _process(delta):
print(Engine.is_in_physics_frame()) # Prints false
print(Engine.is_in_physics_frame()) # Prints false
func _physics_process(delta):
print(Engine.is_in_physics_frame()) # Prints true
print(Engine.is_in_physics_frame()) # Prints true
[/codeblock]
</description>
</method>

View File

@@ -12,38 +12,38 @@
var expression = Expression.new()
func _ready():
$LineEdit.text_submitted.connect(self._on_text_submitted)
$LineEdit.text_submitted.connect(self._on_text_submitted)
func _on_text_submitted(command):
var error = expression.parse(command)
if error != OK:
print(expression.get_error_text())
return
var result = expression.execute()
if not expression.has_execute_failed():
$LineEdit.text = str(result)
var error = expression.parse(command)
if error != OK:
print(expression.get_error_text())
return
var result = expression.execute()
if not expression.has_execute_failed():
$LineEdit.text = str(result)
[/gdscript]
[csharp]
private Expression _expression = new Expression();
public override void _Ready()
{
GetNode&lt;LineEdit&gt;("LineEdit").TextSubmitted += OnTextEntered;
GetNode&lt;LineEdit&gt;("LineEdit").TextSubmitted += OnTextEntered;
}
private void OnTextEntered(string command)
{
Error error = _expression.Parse(command);
if (error != Error.Ok)
{
GD.Print(_expression.GetErrorText());
return;
}
Variant result = _expression.Execute();
if (!_expression.HasExecuteFailed())
{
GetNode&lt;LineEdit&gt;("LineEdit").Text = result.ToString();
}
Error error = _expression.Parse(command);
if (error != Error.Ok)
{
GD.Print(_expression.GetErrorText());
return;
}
Variant result = _expression.Execute();
if (!_expression.HasExecuteFailed())
{
GetNode&lt;LineEdit&gt;("LineEdit").Text = result.ToString();
}
}
[/csharp]
[/codeblocks]

View File

@@ -9,26 +9,26 @@
[codeblocks]
[gdscript]
func save_to_file(content):
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_string(content)
var file = FileAccess.open("user://save_game.dat", FileAccess.WRITE)
file.store_string(content)
func load_from_file():
var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
var content = file.get_as_text()
return content
var file = FileAccess.open("user://save_game.dat", FileAccess.READ)
var content = file.get_as_text()
return content
[/gdscript]
[csharp]
public void SaveToFile(string content)
{
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write);
file.StoreString(content);
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Write);
file.StoreString(content);
}
public string LoadFromFile()
{
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read);
string content = file.GetAsText();
return content;
using var file = FileAccess.Open("user://save_game.dat", FileAccess.ModeFlags.Read);
string content = file.GetAsText();
return content;
}
[/csharp]
[/codeblocks]
@@ -71,12 +71,12 @@
[codeblocks]
[gdscript]
while file.get_position() &lt; file.get_length():
# Read data
# Read data
[/gdscript]
[csharp]
while (file.GetPosition() &lt; file.GetLength())
{
// Read data
// Read data
}
[/csharp]
[/codeblocks]
@@ -431,29 +431,29 @@
const MAX_16B = 1 &lt;&lt; 16
func unsigned16_to_signed(unsigned):
return (unsigned + MAX_15B) % MAX_16B - MAX_15B
return (unsigned + MAX_15B) % MAX_16B - MAX_15B
func _ready():
var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ)
f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42).
f.store_16(121) # In bounds, will store 121.
f.seek(0) # Go back to start to read the stored value.
var read1 = f.get_16() # 65494
var read2 = f.get_16() # 121
var converted1 = unsigned16_to_signed(read1) # -42
var converted2 = unsigned16_to_signed(read2) # 121
var f = FileAccess.open("user://file.dat", FileAccess.WRITE_READ)
f.store_16(-42) # This wraps around and stores 65494 (2^16 - 42).
f.store_16(121) # In bounds, will store 121.
f.seek(0) # Go back to start to read the stored value.
var read1 = f.get_16() # 65494
var read2 = f.get_16() # 121
var converted1 = unsigned16_to_signed(read1) # -42
var converted2 = unsigned16_to_signed(read2) # 121
[/gdscript]
[csharp]
public override void _Ready()
{
using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead);
f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42).
f.Store16(121); // In bounds, will store 121.
f.Seek(0); // Go back to start to read the stored value.
ushort read1 = f.Get16(); // 65494
ushort read2 = f.Get16(); // 121
short converted1 = (short)read1; // -42
short converted2 = (short)read2; // 121
using var f = FileAccess.Open("user://file.dat", FileAccess.ModeFlags.WriteRead);
f.Store16(unchecked((ushort)-42)); // This wraps around and stores 65494 (2^16 - 42).
f.Store16(121); // In bounds, will store 121.
f.Seek(0); // Go back to start to read the stored value.
ushort read1 = f.Get16(); // 65494
ushort read2 = f.Get16(); // 121
short converted1 = (short)read1; // -42
short converted2 = (short)read2; // 121
}
[/csharp]
[/codeblocks]

View File

@@ -288,9 +288,9 @@
fv.base_font = load("res://RobotoFlex.ttf")
var variation_list = fv.get_supported_variation_list()
for tag in variation_list:
var name = TextServerManager.get_primary_interface().tag_to_name(tag)
var values = variation_list[tag]
print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
var name = TextServerManager.get_primary_interface().tag_to_name(tag)
var values = variation_list[tag]
print("variation axis: %s (%d)\n\tmin, max, default: %s" % [name, tag, values])
[/codeblock]
[b]Note:[/b] To set and get variation coordinates of a [FontVariation], use [member FontVariation.variation_opentype].
</description>

View File

@@ -18,8 +18,8 @@
Example code to draw a line between two [Marker2D] nodes using a series of [method CanvasItem.draw_rect] calls:
[codeblock]
func _draw():
for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position):
draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE)
for pixel in Geometry2D.bresenham_line($MarkerA.position, $MarkerB.position):
draw_rect(Rect2(pixel, Vector2.ONE), Color.WHITE)
[/codeblock]
</description>
</method>

View File

@@ -31,11 +31,11 @@
Below is a sample code to help get started:
[codeblock]
func _is_in_input_hotzone(in_node, in_port, mouse_position):
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_input_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position)
return rect.has_point(mouse_position)
[/codeblock]
</description>
</method>
@@ -49,11 +49,11 @@
Below is a sample code to help get started:
[codeblock]
func _is_in_output_hotzone(in_node, in_port, mouse_position):
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
var port_size = Vector2(get_theme_constant("port_grab_distance_horizontal"), get_theme_constant("port_grab_distance_vertical"))
var port_pos = in_node.get_position() + in_node.get_output_port_position(in_port) - port_size / 2
var rect = Rect2(port_pos, port_size)
return rect.has_point(mouse_position)
return rect.has_point(mouse_position)
[/codeblock]
</description>
</method>
@@ -70,12 +70,12 @@
[codeblocks]
[gdscript]
func _is_node_hover_valid(from, from_port, to, to_port):
return from != to
return from != to
[/gdscript]
[csharp]
public override bool _IsNodeHoverValid(StringName fromNode, int fromPort, StringName toNode, int toPort)
{
return fromNode != toNode;
return fromNode != toNode;
}
[/csharp]
[/codeblocks]
@@ -177,11 +177,11 @@
A connection is represented as a [Dictionary] in the form of:
[codeblock]
{
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
}
[/codeblock]
For example, getting a connection at a given mouse position can be achieved like this:
@@ -216,11 +216,11 @@
A connection is represented as a [Dictionary] in the form of:
[codeblock]
{
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
}
[/codeblock]
</description>
@@ -233,11 +233,11 @@
A connection is represented as a [Dictionary] in the form of:
[codeblock]
{
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
}
[/codeblock]
</description>
@@ -333,11 +333,11 @@
A connection is represented as a [Dictionary] in the form of:
[codeblock]
{
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
from_node: StringName,
from_port: int,
to_node: StringName,
to_port: int,
keep_alive: bool
}
[/codeblock]
Connections with [code]keep_alive[/code] set to [code]false[/code] may be deleted automatically if invalid during a redraw.

View File

@@ -11,17 +11,17 @@
var ctx = HMACContext.new()
func _ready():
var key = "supersecret".to_utf8_buffer()
var err = ctx.start(HashingContext.HASH_SHA256, key)
assert(err == OK)
var msg1 = "this is ".to_utf8_buffer()
var msg2 = "super duper secret".to_utf8_buffer()
err = ctx.update(msg1)
assert(err == OK)
err = ctx.update(msg2)
assert(err == OK)
var hmac = ctx.finish()
print(hmac.hex_encode())
var key = "supersecret".to_utf8_buffer()
var err = ctx.start(HashingContext.HASH_SHA256, key)
assert(err == OK)
var msg1 = "this is ".to_utf8_buffer()
var msg2 = "super duper secret".to_utf8_buffer()
err = ctx.update(msg1)
assert(err == OK)
err = ctx.update(msg2)
assert(err == OK)
var hmac = ctx.finish()
print(hmac.hex_encode())
[/gdscript]
[csharp]
@@ -30,22 +30,22 @@
public partial class MyNode : Node
{
private HmacContext _ctx = new HmacContext();
private HmacContext _ctx = new HmacContext();
public override void _Ready()
{
byte[] key = "supersecret".ToUtf8Buffer();
Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
Debug.Assert(err == Error.Ok);
byte[] msg1 = "this is ".ToUtf8Buffer();
byte[] msg2 = "super duper secret".ToUtf8Buffer();
err = _ctx.Update(msg1);
Debug.Assert(err == Error.Ok);
err = _ctx.Update(msg2);
Debug.Assert(err == Error.Ok);
byte[] hmac = _ctx.Finish();
GD.Print(hmac.HexEncode());
}
public override void _Ready()
{
byte[] key = "supersecret".ToUtf8Buffer();
Error err = _ctx.Start(HashingContext.HashType.Sha256, key);
Debug.Assert(err == Error.Ok);
byte[] msg1 = "this is ".ToUtf8Buffer();
byte[] msg2 = "super duper secret".ToUtf8Buffer();
err = _ctx.Update(msg1);
Debug.Assert(err == Error.Ok);
err = _ctx.Update(msg2);
Debug.Assert(err == Error.Ok);
byte[] hmac = _ctx.Finish();
GD.Print(hmac.HexEncode());
}
}
[/csharp]
[/codeblocks]

View File

@@ -62,8 +62,8 @@
Returns all response headers as a [Dictionary]. Each entry is composed by the header name, and a [String] containing the values separated by [code]"; "[/code]. The casing is kept the same as the headers were received.
[codeblock]
{
"content-length": 12,
"Content-Type": "application/json; charset=UTF-8",
"content-length": 12,
"Content-Type": "application/json; charset=UTF-8",
}
[/codeblock]
</description>
@@ -119,9 +119,9 @@
[csharp]
var fields = new Godot.Collections.Dictionary
{
{ "single", 123 },
{ "notValued", default },
{ "multiple", new Godot.Collections.Array { 22, 33, 44 } },
{ "single", 123 },
{ "notValued", default },
{ "multiple", new Godot.Collections.Array { 22, 33, 44 } },
};
string queryString = httpClient.QueryStringFromDict(fields);
// Returns "single=123&amp;not_valued&amp;multiple=22&amp;multiple=33&amp;multiple=44"

View File

@@ -12,71 +12,71 @@
[codeblocks]
[gdscript]
func _ready():
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(self._http_request_completed)
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(self._http_request_completed)
# Perform a GET request. The URL below returns JSON as of writing.
var error = http_request.request("https://httpbin.org/get")
if error != OK:
push_error("An error occurred in the HTTP request.")
# Perform a GET request. The URL below returns JSON as of writing.
var error = http_request.request("https://httpbin.org/get")
if error != OK:
push_error("An error occurred in the HTTP request.")
# Perform a POST request. The URL below returns JSON as of writing.
# Note: Don't make simultaneous requests using a single HTTPRequest node.
# The snippet below is provided for reference only.
var body = JSON.new().stringify({"name": "Godette"})
error = http_request.request("https://httpbin.org/post", [], HTTPClient.METHOD_POST, body)
if error != OK:
push_error("An error occurred in the HTTP request.")
# Perform a POST request. The URL below returns JSON as of writing.
# Note: Don't make simultaneous requests using a single HTTPRequest node.
# The snippet below is provided for reference only.
var body = JSON.new().stringify({"name": "Godette"})
error = http_request.request("https://httpbin.org/post", [], HTTPClient.METHOD_POST, body)
if error != OK:
push_error("An error occurred in the HTTP request.")
# Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body):
var json = JSON.new()
json.parse(body.get_string_from_utf8())
var response = json.get_data()
var json = JSON.new()
json.parse(body.get_string_from_utf8())
var response = json.get_data()
# Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
print(response.headers["User-Agent"])
# Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
print(response.headers["User-Agent"])
[/gdscript]
[csharp]
public override void _Ready()
{
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest();
AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted;
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest();
AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform a GET request. The URL below returns JSON as of writing.
Error error = httpRequest.Request("https://httpbin.org/get");
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
// Perform a GET request. The URL below returns JSON as of writing.
Error error = httpRequest.Request("https://httpbin.org/get");
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
// Perform a POST request. The URL below returns JSON as of writing.
// Note: Don't make simultaneous requests using a single HTTPRequest node.
// The snippet below is provided for reference only.
string body = new Json().Stringify(new Godot.Collections.Dictionary
{
{ "name", "Godette" }
});
error = httpRequest.Request("https://httpbin.org/post", null, HttpClient.Method.Post, body);
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
// Perform a POST request. The URL below returns JSON as of writing.
// Note: Don't make simultaneous requests using a single HTTPRequest node.
// The snippet below is provided for reference only.
string body = new Json().Stringify(new Godot.Collections.Dictionary
{
{ "name", "Godette" }
});
error = httpRequest.Request("https://httpbin.org/post", null, HttpClient.Method.Post, body);
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
}
// Called when the HTTP request is completed.
private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{
var json = new Json();
json.Parse(body.GetStringFromUtf8());
var response = json.GetData().AsGodotDictionary();
var json = new Json();
json.Parse(body.GetStringFromUtf8());
var response = json.GetData().AsGodotDictionary();
// Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
GD.Print((response["headers"].AsGodotDictionary())["User-Agent"]);
// Will print the user agent string used by the HTTPRequest node (as recognized by httpbin.org).
GD.Print((response["headers"].AsGodotDictionary())["User-Agent"]);
}
[/csharp]
[/codeblocks]
@@ -84,69 +84,69 @@
[codeblocks]
[gdscript]
func _ready():
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(self._http_request_completed)
# Create an HTTP request node and connect its completion signal.
var http_request = HTTPRequest.new()
add_child(http_request)
http_request.request_completed.connect(self._http_request_completed)
# Perform the HTTP request. The URL below returns a PNG image as of writing.
var error = http_request.request("https://placehold.co/512")
if error != OK:
push_error("An error occurred in the HTTP request.")
# Perform the HTTP request. The URL below returns a PNG image as of writing.
var error = http_request.request("https://placehold.co/512")
if error != OK:
push_error("An error occurred in the HTTP request.")
# Called when the HTTP request is completed.
func _http_request_completed(result, response_code, headers, body):
if result != HTTPRequest.RESULT_SUCCESS:
push_error("Image couldn't be downloaded. Try a different image.")
if result != HTTPRequest.RESULT_SUCCESS:
push_error("Image couldn't be downloaded. Try a different image.")
var image = Image.new()
var error = image.load_png_from_buffer(body)
if error != OK:
push_error("Couldn't load the image.")
var image = Image.new()
var error = image.load_png_from_buffer(body)
if error != OK:
push_error("Couldn't load the image.")
var texture = ImageTexture.create_from_image(image)
var texture = ImageTexture.create_from_image(image)
# Display the image in a TextureRect node.
var texture_rect = TextureRect.new()
add_child(texture_rect)
texture_rect.texture = texture
# Display the image in a TextureRect node.
var texture_rect = TextureRect.new()
add_child(texture_rect)
texture_rect.texture = texture
[/gdscript]
[csharp]
public override void _Ready()
{
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest();
AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted;
// Create an HTTP request node and connect its completion signal.
var httpRequest = new HttpRequest();
AddChild(httpRequest);
httpRequest.RequestCompleted += HttpRequestCompleted;
// Perform the HTTP request. The URL below returns a PNG image as of writing.
Error error = httpRequest.Request("https://placehold.co/512");
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
// Perform the HTTP request. The URL below returns a PNG image as of writing.
Error error = httpRequest.Request("https://placehold.co/512");
if (error != Error.Ok)
{
GD.PushError("An error occurred in the HTTP request.");
}
}
// Called when the HTTP request is completed.
private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{
if (result != (long)HttpRequest.Result.Success)
{
GD.PushError("Image couldn't be downloaded. Try a different image.");
}
var image = new Image();
Error error = image.LoadPngFromBuffer(body);
if (error != Error.Ok)
{
GD.PushError("Couldn't load the image.");
}
if (result != (long)HttpRequest.Result.Success)
{
GD.PushError("Image couldn't be downloaded. Try a different image.");
}
var image = new Image();
Error error = image.LoadPngFromBuffer(body);
if (error != Error.Ok)
{
GD.PushError("Couldn't load the image.");
}
var texture = ImageTexture.CreateFromImage(image);
var texture = ImageTexture.CreateFromImage(image);
// Display the image in a TextureRect node.
var textureRect = new TextureRect();
AddChild(textureRect);
textureRect.Texture = texture;
// Display the image in a TextureRect node.
var textureRect = new TextureRect();
AddChild(textureRect);
textureRect.Texture = texture;
}
[/csharp]
[/codeblocks]

View File

@@ -11,48 +11,48 @@
const CHUNK_SIZE = 1024
func hash_file(path):
# Check that file exists.
if not FileAccess.file_exists(path):
return
# Start an SHA-256 context.
var ctx = HashingContext.new()
ctx.start(HashingContext.HASH_SHA256)
# Open the file to hash.
var file = FileAccess.open(path, FileAccess.READ)
# Update the context after reading each chunk.
while file.get_position() &lt; file.get_length():
var remaining = file.get_length() - file.get_position()
ctx.update(file.get_buffer(min(remaining, CHUNK_SIZE)))
# Get the computed hash.
var res = ctx.finish()
# Print the result as hex string and array.
printt(res.hex_encode(), Array(res))
# Check that file exists.
if not FileAccess.file_exists(path):
return
# Start an SHA-256 context.
var ctx = HashingContext.new()
ctx.start(HashingContext.HASH_SHA256)
# Open the file to hash.
var file = FileAccess.open(path, FileAccess.READ)
# Update the context after reading each chunk.
while file.get_position() &lt; file.get_length():
var remaining = file.get_length() - file.get_position()
ctx.update(file.get_buffer(min(remaining, CHUNK_SIZE)))
# Get the computed hash.
var res = ctx.finish()
# Print the result as hex string and array.
printt(res.hex_encode(), Array(res))
[/gdscript]
[csharp]
public const int ChunkSize = 1024;
public void HashFile(string path)
{
// Check that file exists.
if (!FileAccess.FileExists(path))
{
return;
}
// Start an SHA-256 context.
var ctx = new HashingContext();
ctx.Start(HashingContext.HashType.Sha256);
// Open the file to hash.
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
// Update the context after reading each chunk.
while (file.GetPosition() &lt; file.GetLength())
{
int remaining = (int)(file.GetLength() - file.GetPosition());
ctx.Update(file.GetBuffer(Mathf.Min(remaining, ChunkSize)));
}
// Get the computed hash.
byte[] res = ctx.Finish();
// Print the result as hex string and array.
GD.PrintT(res.HexEncode(), (Variant)res);
// Check that file exists.
if (!FileAccess.FileExists(path))
{
return;
}
// Start an SHA-256 context.
var ctx = new HashingContext();
ctx.Start(HashingContext.HashType.Sha256);
// Open the file to hash.
using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
// Update the context after reading each chunk.
while (file.GetPosition() &lt; file.GetLength())
{
int remaining = (int)(file.GetLength() - file.GetPosition());
ctx.Update(file.GetBuffer(Mathf.Min(remaining, ChunkSize)));
}
// Get the computed hash.
byte[] res = ctx.Finish();
// Print the result as hex string and array.
GD.PrintT(res.HexEncode(), (Variant)res);
}
[/csharp]
[/codeblocks]

View File

@@ -36,10 +36,10 @@
Each adapter is a dictionary of the form:
[codeblock]
{
"index": "1", # Interface index.
"name": "eth0", # Interface name.
"friendly": "Ethernet One", # A friendly name (might be empty).
"addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface.
"index": "1", # Interface index.
"name": "eth0", # Interface name.
"friendly": "Ethernet One", # A friendly name (might be empty).
"addresses": ["192.168.1.101"], # An array of IP addresses associated to this interface.
}
[/codeblock]
</description>

View File

@@ -20,14 +20,14 @@
var images = []
const LAYERS = 6
for i in LAYERS:
var image = Image.create_empty(128, 128, false, Image.FORMAT_RGB8)
if i % 3 == 0:
image.fill(Color.RED)
elif i % 3 == 1:
image.fill(Color.GREEN)
else:
image.fill(Color.BLUE)
images.push_back(image)
var image = Image.create_empty(128, 128, false, Image.FORMAT_RGB8)
if i % 3 == 0:
image.fill(Color.RED)
elif i % 3 == 1:
image.fill(Color.GREEN)
else:
image.fill(Color.BLUE)
images.push_back(image)
# Create and save a 2D texture array. The array of images must have at least 1 Image.
var texture_2d_array = Texture2DArray.new()

View File

@@ -68,20 +68,20 @@
For keyboard layouts with a single label on the key, it is equivalent to [member keycode].
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.key_label)[/code] where [code]event[/code] is the [InputEventKey].
[codeblock lang=text]
+-----+ +-----+
| Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+
+-----+ +-----+
| Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+
[/codeblock]
</member>
<member name="keycode" type="int" setter="set_keycode" getter="get_keycode" enum="Key" default="0">
Latin label printed on the key in the current keyboard layout, which corresponds to one of the [enum Key] constants.
To get a human-readable representation of the [InputEventKey], use [code]OS.get_keycode_string(event.keycode)[/code] where [code]event[/code] is the [InputEventKey].
[codeblock lang=text]
+-----+ +-----+
| Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+
+-----+ +-----+
| Q | | Q | - "Q" - keycode
| Й | | ض | - "Й" and "ض" - key_label
+-----+ +-----+
[/codeblock]
</member>
<member name="location" type="int" setter="set_location" getter="get_location" enum="KeyLocation" default="0">
@@ -93,18 +93,18 @@
[codeblocks]
[gdscript]
func _input(event):
if event is InputEventKey:
var keycode = DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode)
print(OS.get_keycode_string(keycode))
if event is InputEventKey:
var keycode = DisplayServer.keyboard_get_keycode_from_physical(event.physical_keycode)
print(OS.get_keycode_string(keycode))
[/gdscript]
[csharp]
public override void _Input(InputEvent @event)
{
if (@event is InputEventKey inputEventKey)
{
var keycode = DisplayServer.KeyboardGetKeycodeFromPhysical(inputEventKey.PhysicalKeycode);
GD.Print(OS.GetKeycodeString(keycode));
}
if (@event is InputEventKey inputEventKey)
{
var keycode = DisplayServer.KeyboardGetKeycodeFromPhysical(inputEventKey.PhysicalKeycode);
GD.Print(OS.GetKeycodeString(keycode));
}
}
[/csharp]
[/codeblocks]

View File

@@ -10,50 +10,50 @@
[codeblocks]
[gdscript]
func _ready():
OS.open_midi_inputs()
print(OS.get_connected_midi_inputs())
OS.open_midi_inputs()
print(OS.get_connected_midi_inputs())
func _input(input_event):
if input_event is InputEventMIDI:
_print_midi_info(input_event)
if input_event is InputEventMIDI:
_print_midi_info(input_event)
func _print_midi_info(midi_event):
print(midi_event)
print("Channel ", midi_event.channel)
print("Message ", midi_event.message)
print("Pitch ", midi_event.pitch)
print("Velocity ", midi_event.velocity)
print("Instrument ", midi_event.instrument)
print("Pressure ", midi_event.pressure)
print("Controller number: ", midi_event.controller_number)
print("Controller value: ", midi_event.controller_value)
print(midi_event)
print("Channel ", midi_event.channel)
print("Message ", midi_event.message)
print("Pitch ", midi_event.pitch)
print("Velocity ", midi_event.velocity)
print("Instrument ", midi_event.instrument)
print("Pressure ", midi_event.pressure)
print("Controller number: ", midi_event.controller_number)
print("Controller value: ", midi_event.controller_value)
[/gdscript]
[csharp]
public override void _Ready()
{
OS.OpenMidiInputs();
GD.Print(OS.GetConnectedMidiInputs());
OS.OpenMidiInputs();
GD.Print(OS.GetConnectedMidiInputs());
}
public override void _Input(InputEvent inputEvent)
{
if (inputEvent is InputEventMidi midiEvent)
{
PrintMIDIInfo(midiEvent);
}
if (inputEvent is InputEventMidi midiEvent)
{
PrintMIDIInfo(midiEvent);
}
}
private void PrintMIDIInfo(InputEventMidi midiEvent)
{
GD.Print(midiEvent);
GD.Print($"Channel {midiEvent.Channel}");
GD.Print($"Message {midiEvent.Message}");
GD.Print($"Pitch {midiEvent.Pitch}");
GD.Print($"Velocity {midiEvent.Velocity}");
GD.Print($"Instrument {midiEvent.Instrument}");
GD.Print($"Pressure {midiEvent.Pressure}");
GD.Print($"Controller number: {midiEvent.ControllerNumber}");
GD.Print($"Controller value: {midiEvent.ControllerValue}");
GD.Print(midiEvent);
GD.Print($"Channel {midiEvent.Channel}");
GD.Print($"Message {midiEvent.Message}");
GD.Print($"Pitch {midiEvent.Pitch}");
GD.Print($"Velocity {midiEvent.Velocity}");
GD.Print($"Instrument {midiEvent.Instrument}");
GD.Print($"Pressure {midiEvent.Pressure}");
GD.Print($"Controller number: {midiEvent.ControllerNumber}");
GD.Print($"Controller value: {midiEvent.ControllerValue}");
}
[/csharp]
[/codeblocks]
@@ -96,9 +96,9 @@
[b]Note:[/b] Some MIDI devices may send a [constant MIDI_MESSAGE_NOTE_ON] message with [code]0[/code] velocity and expect it to be treated the same as a [constant MIDI_MESSAGE_NOTE_OFF] message. If necessary, this can be handled with a few lines of code:
[codeblock]
func _input(event):
if event is InputEventMIDI:
if event.message == MIDI_MESSAGE_NOTE_ON and event.velocity &gt; 0:
print("Note pressed!")
if event is InputEventMIDI:
if event.message == MIDI_MESSAGE_NOTE_ON and event.velocity &gt; 0:
print("Note pressed!")
[/codeblock]
</member>
</members>

View File

@@ -16,13 +16,13 @@
var json = JSON.new()
var error = json.parse(json_string)
if error == OK:
var data_received = json.data
if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints the array.
else:
print("Unexpected data")
var data_received = json.data
if typeof(data_received) == TYPE_ARRAY:
print(data_received) # Prints the array.
else:
print("Unexpected data")
else:
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
print("JSON Parse Error: ", json.get_error_message(), " in ", json_string, " at line ", json.get_error_line())
[/codeblock]
Alternatively, you can parse strings using the static [method parse_string] method, but it doesn't handle errors.
[codeblock]
@@ -47,7 +47,7 @@
You can convert a native value to a JSON string like this:
[codeblock]
func encode_data(value, full_objects = false):
return JSON.stringify(JSON.from_native(value, full_objects))
return JSON.stringify(JSON.from_native(value, full_objects))
[/codeblock]
</description>
</method>
@@ -105,18 +105,18 @@
## JSON.stringify(my_dictionary, "\t")
{
"name": "my_dictionary",
"version": "1.0.0",
"entities": [
{
"name": "entity_0",
"value": "value_0"
},
{
"name": "entity_1",
"value": "value_1"
}
]
"name": "my_dictionary",
"version": "1.0.0",
"entities": [
{
"name": "entity_0",
"value": "value_0"
},
{
"name": "entity_1",
"value": "value_1"
}
]
}
## JSON.stringify(my_dictionary, "...")
@@ -147,7 +147,7 @@
You can convert a JSON string back to a native value like this:
[codeblock]
func decode_data(string, allow_objects = false):
return JSON.to_native(JSON.parse_string(string), allow_objects)
return JSON.to_native(JSON.parse_string(string), allow_objects)
[/codeblock]
</description>
</method>

View File

@@ -12,25 +12,25 @@
var console = JavaScriptBridge.get_interface("console")
func _init():
var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
print(buf) # Prints [JavaScriptObject:OBJECT_ID]
var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf)
uint8arr[1] = 255
prints(uint8arr[1], uint8arr.byteLength) # Prints "255 10"
var buf = JavaScriptBridge.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
print(buf) # Prints [JavaScriptObject:OBJECT_ID]
var uint8arr = JavaScriptBridge.create_object("Uint8Array", buf) # new Uint8Array(buf)
uint8arr[1] = 255
prints(uint8arr[1], uint8arr.byteLength) # Prints "255 10"
# Prints "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" in the browser's console.
console.log(uint8arr)
# Prints "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]" in the browser's console.
console.log(uint8arr)
# Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback)
JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
# Equivalent of JavaScriptBridge: Array.from(uint8arr).forEach(myCallback)
JavaScriptBridge.get_interface("Array").from(uint8arr).forEach(_my_js_callback)
func myCallback(args):
# Will be called with the parameters passed to the "forEach" callback
# [0, 0, [JavaScriptObject:1173]]
# [255, 1, [JavaScriptObject:1173]]
# ...
# [0, 9, [JavaScriptObject:1180]]
print(args)
# Will be called with the parameters passed to the "forEach" callback
# [0, 0, [JavaScriptObject:1173]]
# [255, 1, [JavaScriptObject:1173]]
# ...
# [0, 9, [JavaScriptObject:1180]]
print(args)
[/codeblock]
[b]Note:[/b] Only available in the Web platform.
</description>

View File

@@ -95,38 +95,38 @@
[codeblocks]
[gdscript]
func _ready():
var menu = get_menu()
# Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items.
menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
var menu = get_menu()
# Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items.
menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id):
if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system())
if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system())
[/gdscript]
[csharp]
public override void _Ready()
{
var menu = GetMenu();
// Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(LineEdit.MenuItems.Redo) + 1;
// Add custom items.
menu.AddSeparator();
menu.AddItem("Insert Date", LineEdit.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
var menu = GetMenu();
// Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(LineEdit.MenuItems.Redo) + 1;
// Add custom items.
menu.AddSeparator();
menu.AddItem("Insert Date", LineEdit.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
}
public void OnItemPressed(int id)
{
if (id == LineEdit.MenuItems.Max + 1)
{
InsertTextAtCaret(Time.GetDateStringFromSystem());
}
if (id == LineEdit.MenuItems.Max + 1)
{
InsertTextAtCaret(Time.GetDateStringFromSystem());
}
}
[/csharp]
[/codeblocks]

View File

@@ -15,17 +15,17 @@
var time_elapsed = 0
func _initialize():
print("Initialized:")
print(" Starting time: %s" % str(time_elapsed))
print("Initialized:")
print(" Starting time: %s" % str(time_elapsed))
func _process(delta):
time_elapsed += delta
# Return true to end the main loop.
return Input.get_mouse_button_mask() != 0 || Input.is_key_pressed(KEY_ESCAPE)
time_elapsed += delta
# Return true to end the main loop.
return Input.get_mouse_button_mask() != 0 || Input.is_key_pressed(KEY_ESCAPE)
func _finalize():
print("Finalized:")
print(" End time: %s" % str(time_elapsed))
print("Finalized:")
print(" End time: %s" % str(time_elapsed))
[/gdscript]
[csharp]
using Godot;
@@ -33,26 +33,26 @@
[GlobalClass]
public partial class CustomMainLoop : MainLoop
{
private double _timeElapsed = 0;
private double _timeElapsed = 0;
public override void _Initialize()
{
GD.Print("Initialized:");
GD.Print($" Starting Time: {_timeElapsed}");
}
public override void _Initialize()
{
GD.Print("Initialized:");
GD.Print($" Starting Time: {_timeElapsed}");
}
public override bool _Process(double delta)
{
_timeElapsed += delta;
// Return true to end the main loop.
return Input.GetMouseButtonMask() != 0 || Input.IsKeyPressed(Key.Escape);
}
public override bool _Process(double delta)
{
_timeElapsed += delta;
// Return true to end the main loop.
return Input.GetMouseButtonMask() != 0 || Input.IsKeyPressed(Key.Escape);
}
private void _Finalize()
{
GD.Print("Finalized:");
GD.Print($" End Time: {_timeElapsed}");
}
private void _Finalize()
{
GD.Print("Finalized:");
GD.Print($" End Time: {_timeElapsed}");
}
}
[/csharp]
[/codeblocks]

View File

@@ -14,11 +14,11 @@
var mdt = MeshDataTool.new()
mdt.create_from_surface(mesh, 0)
for i in range(mdt.get_vertex_count()):
var vertex = mdt.get_vertex(i)
# In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.get_vertex_normal(i)
# Save your change.
mdt.set_vertex(i, vertex)
var vertex = mdt.get_vertex(i)
# In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.get_vertex_normal(i)
# Save your change.
mdt.set_vertex(i, vertex)
mesh.clear_surfaces()
mdt.commit_to_surface(mesh)
var mi = MeshInstance.new()
@@ -32,11 +32,11 @@
mdt.CreateFromSurface(mesh, 0);
for (var i = 0; i &lt; mdt.GetVertexCount(); i++)
{
Vector3 vertex = mdt.GetVertex(i);
// In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.GetVertexNormal(i);
// Save your change.
mdt.SetVertex(i, vertex);
Vector3 vertex = mdt.GetVertex(i);
// In this example we extend the mesh by one unit, which results in separated faces as it is flat shaded.
vertex += mdt.GetVertexNormal(i);
// Save your change.
mdt.SetVertex(i, vertex);
}
mesh.ClearSurfaces();
mdt.CommitToSurface(mesh);

View File

@@ -35,9 +35,9 @@
Called when the engine determines whether this [MovieWriter] is able to handle the file at [param path]. Must return [code]true[/code] if this [MovieWriter] is able to handle the given file path, [code]false[/code] otherwise. Typically, [method _handles_file] is overridden as follows to allow the user to record a file at any path with a given file extension:
[codeblock]
func _handles_file(path):
# Allows specifying an output file with a `.mkv` file extension (case-insensitive),
# either in the Project Settings or with the `--write-movie &lt;path&gt;` command line argument.
return path.get_extension().to_lower() == "mkv"
# Allows specifying an output file with a `.mkv` file extension (case-insensitive),
# either in the Project Settings or with the `--write-movie &lt;path&gt;` command line argument.
return path.get_extension().to_lower() == "mkv"
[/codeblock]
</description>
</method>

View File

@@ -15,57 +15,57 @@
var base_multiplayer = SceneMultiplayer.new()
func _init():
# Just passthrough base signals (copied to var to avoid cyclic reference)
var cts = connected_to_server
var cf = connection_failed
var sd = server_disconnected
var pc = peer_connected
var pd = peer_disconnected
base_multiplayer.connected_to_server.connect(func(): cts.emit())
base_multiplayer.connection_failed.connect(func(): cf.emit())
base_multiplayer.server_disconnected.connect(func(): sd.emit())
base_multiplayer.peer_connected.connect(func(id): pc.emit(id))
base_multiplayer.peer_disconnected.connect(func(id): pd.emit(id))
# Just passthrough base signals (copied to var to avoid cyclic reference)
var cts = connected_to_server
var cf = connection_failed
var sd = server_disconnected
var pc = peer_connected
var pd = peer_disconnected
base_multiplayer.connected_to_server.connect(func(): cts.emit())
base_multiplayer.connection_failed.connect(func(): cf.emit())
base_multiplayer.server_disconnected.connect(func(): sd.emit())
base_multiplayer.peer_connected.connect(func(id): pc.emit(id))
base_multiplayer.peer_disconnected.connect(func(id): pd.emit(id))
func _poll():
return base_multiplayer.poll()
return base_multiplayer.poll()
# Log RPC being made and forward it to the default multiplayer.
func _rpc(peer: int, object: Object, method: StringName, args: Array) -&gt; Error:
print("Got RPC for %d: %s::%s(%s)" % [peer, object, method, args])
return base_multiplayer.rpc(peer, object, method, args)
print("Got RPC for %d: %s::%s(%s)" % [peer, object, method, args])
return base_multiplayer.rpc(peer, object, method, args)
# Log configuration add. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom.
func _object_configuration_add(object, config: Variant) -&gt; Error:
if config is MultiplayerSynchronizer:
print("Adding synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner:
print("Adding node %s to the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_add(object, config)
if config is MultiplayerSynchronizer:
print("Adding synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner:
print("Adding node %s to the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_add(object, config)
# Log configuration remove. E.g. root path (nullptr, NodePath), replication (Node, Spawner|Synchronizer), custom.
func _object_configuration_remove(object, config: Variant) -&gt; Error:
if config is MultiplayerSynchronizer:
print("Removing synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner:
print("Removing node %s from the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_remove(object, config)
if config is MultiplayerSynchronizer:
print("Removing synchronization configuration for %s. Synchronizer: %s" % [object, config])
elif config is MultiplayerSpawner:
print("Removing node %s from the spawn list. Spawner: %s" % [object, config])
return base_multiplayer.object_configuration_remove(object, config)
# These can be optional, but in our case we want to extend SceneMultiplayer, so forward everything.
func _set_multiplayer_peer(p_peer: MultiplayerPeer):
base_multiplayer.multiplayer_peer = p_peer
base_multiplayer.multiplayer_peer = p_peer
func _get_multiplayer_peer() -&gt; MultiplayerPeer:
return base_multiplayer.multiplayer_peer
return base_multiplayer.multiplayer_peer
func _get_unique_id() -&gt; int:
return base_multiplayer.get_unique_id()
return base_multiplayer.get_unique_id()
func _get_remote_sender_id() -&gt; int:
return base_multiplayer.get_remote_sender_id()
return base_multiplayer.get_remote_sender_id()
func _get_peer_ids() -&gt; PackedInt32Array:
return base_multiplayer.get_peers()
return base_multiplayer.get_peers()
[/gdscript]
[/codeblocks]
Then in your main scene or in an autoload call [method SceneTree.set_multiplayer] to start using your custom [MultiplayerAPI]:
@@ -73,8 +73,8 @@
[gdscript]
# autoload.gd
func _enter_tree():
# Sets our custom multiplayer as the main one in SceneTree.
get_tree().set_multiplayer(LogMultiplayer.new())
# Sets our custom multiplayer as the main one in SceneTree.
get_tree().set_multiplayer(LogMultiplayer.new())
[/gdscript]
[/codeblocks]
Native extensions can alternatively use the [method MultiplayerAPI.set_default_interface] method during initialization to configure themselves as the default implementation.

View File

@@ -11,28 +11,28 @@
var menu
func _menu_callback(item_id):
if item_id == "ITEM_CUT":
cut()
elif item_id == "ITEM_COPY":
copy()
elif item_id == "ITEM_PASTE":
paste()
if item_id == "ITEM_CUT":
cut()
elif item_id == "ITEM_COPY":
copy()
elif item_id == "ITEM_PASTE":
paste()
func _enter_tree():
# Create new menu and add items:
menu = NativeMenu.create_menu()
NativeMenu.add_item(menu, "Cut", _menu_callback, Callable(), "ITEM_CUT")
NativeMenu.add_item(menu, "Copy", _menu_callback, Callable(), "ITEM_COPY")
NativeMenu.add_separator(menu)
NativeMenu.add_item(menu, "Paste", _menu_callback, Callable(), "ITEM_PASTE")
# Create new menu and add items:
menu = NativeMenu.create_menu()
NativeMenu.add_item(menu, "Cut", _menu_callback, Callable(), "ITEM_CUT")
NativeMenu.add_item(menu, "Copy", _menu_callback, Callable(), "ITEM_COPY")
NativeMenu.add_separator(menu)
NativeMenu.add_item(menu, "Paste", _menu_callback, Callable(), "ITEM_PASTE")
func _on_button_pressed():
# Show popup menu at mouse position:
NativeMenu.popup(menu, DisplayServer.mouse_get_position())
# Show popup menu at mouse position:
NativeMenu.popup(menu, DisplayServer.mouse_get_position())
func _exit_tree():
# Remove menu when it's no longer needed:
NativeMenu.free_menu(menu)
# Remove menu when it's no longer needed:
NativeMenu.free_menu(menu)
[/codeblock]
</description>
<tutorials>

View File

@@ -58,15 +58,15 @@
Call [method update_configuration_warnings] when the warnings need to be updated for this node.
[codeblock]
@export var energy = 0:
set(value):
energy = value
update_configuration_warnings()
set(value):
energy = value
update_configuration_warnings()
func _get_configuration_warnings():
if energy &lt; 0:
return ["Energy must be 0 or greater."]
else:
return []
if energy &lt; 0:
return ["Energy must be 0 or greater."]
else:
return []
[/codeblock]
</description>
</method>
@@ -168,14 +168,14 @@
[gdscript]
var child_node = get_child(0)
if child_node.get_parent():
child_node.get_parent().remove_child(child_node)
child_node.get_parent().remove_child(child_node)
add_child(child_node)
[/gdscript]
[csharp]
Node childNode = GetChild(0);
if (childNode.GetParent() != null)
{
childNode.GetParent().RemoveChild(childNode);
childNode.GetParent().RemoveChild(childNode);
}
AddChild(childNode);
[/csharp]
@@ -372,16 +372,16 @@
# Stores the node's non-internal groups only (as an array of StringNames).
var non_internal_groups = []
for group in get_groups():
if not str(group).begins_with("_"):
non_internal_groups.push_back(group)
if not str(group).begins_with("_"):
non_internal_groups.push_back(group)
[/gdscript]
[csharp]
// Stores the node's non-internal groups only (as a List of StringNames).
List&lt;string&gt; nonInternalGroups = new List&lt;string&gt;();
foreach (string group in GetGroups())
{
if (!group.BeginsWith("_"))
nonInternalGroups.Add(group);
if (!group.BeginsWith("_"))
nonInternalGroups.Add(group);
}
[/csharp]
[/codeblocks]
@@ -1300,10 +1300,10 @@
[b]Note:[/b] This notification is received alongside [constant NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup translations for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method is_node_ready].
[codeblock]
func _notification(what):
if what == NOTIFICATION_TRANSLATION_CHANGED:
if not is_node_ready():
await ready # Wait until ready signal.
$Label.text = atr("%d Bananas") % banana_counter
if what == NOTIFICATION_TRANSLATION_CHANGED:
if not is_node_ready():
await ready # Wait until ready signal.
$Label.text = atr("%d Bananas") % banana_counter
[/codeblock]
</constant>
<constant name="NOTIFICATION_WM_ABOUT" value="2011">

View File

@@ -196,29 +196,29 @@
[gdscript]
var arguments = {}
for argument in OS.get_cmdline_args():
if argument.contains("="):
var key_value = argument.split("=")
arguments[key_value[0].trim_prefix("--")] = key_value[1]
else:
# Options without an argument will be present in the dictionary,
# with the value set to an empty string.
arguments[argument.trim_prefix("--")] = ""
if argument.contains("="):
var key_value = argument.split("=")
arguments[key_value[0].trim_prefix("--")] = key_value[1]
else:
# Options without an argument will be present in the dictionary,
# with the value set to an empty string.
arguments[argument.trim_prefix("--")] = ""
[/gdscript]
[csharp]
var arguments = new Dictionary&lt;string, string&gt;();
foreach (var argument in OS.GetCmdlineArgs())
{
if (argument.Contains('='))
{
string[] keyValue = argument.Split("=");
arguments[keyValue[0].TrimPrefix("--")] = keyValue[1];
}
else
{
// Options without an argument will be present in the dictionary,
// with the value set to an empty string.
arguments[argument.TrimPrefix("--")] = "";
}
if (argument.Contains('='))
{
string[] keyValue = argument.Split("=");
arguments[keyValue[0].TrimPrefix("--")] = keyValue[1];
}
else
{
// Options without an argument will be present in the dictionary,
// with the value set to an empty string.
arguments[argument.TrimPrefix("--")] = "";
}
}
[/csharp]
[/codeblocks]
@@ -383,44 +383,44 @@
[codeblocks]
[gdscript]
match OS.get_name():
"Windows":
print("Welcome to Windows!")
"macOS":
print("Welcome to macOS!")
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD":
print("Welcome to Linux/BSD!")
"Android":
print("Welcome to Android!")
"iOS":
print("Welcome to iOS!")
"Web":
print("Welcome to the Web!")
"Windows":
print("Welcome to Windows!")
"macOS":
print("Welcome to macOS!")
"Linux", "FreeBSD", "NetBSD", "OpenBSD", "BSD":
print("Welcome to Linux/BSD!")
"Android":
print("Welcome to Android!")
"iOS":
print("Welcome to iOS!")
"Web":
print("Welcome to the Web!")
[/gdscript]
[csharp]
switch (OS.GetName())
{
case "Windows":
GD.Print("Welcome to Windows");
break;
case "macOS":
GD.Print("Welcome to macOS!");
break;
case "Linux":
case "FreeBSD":
case "NetBSD":
case "OpenBSD":
case "BSD":
GD.Print("Welcome to Linux/BSD!");
break;
case "Android":
GD.Print("Welcome to Android!");
break;
case "iOS":
GD.Print("Welcome to iOS!");
break;
case "Web":
GD.Print("Welcome to the Web!");
break;
case "Windows":
GD.Print("Welcome to Windows");
break;
case "macOS":
GD.Print("Welcome to macOS!");
break;
case "Linux":
case "FreeBSD":
case "NetBSD":
case "OpenBSD":
case "BSD":
GD.Print("Welcome to Linux/BSD!");
break;
case "Android":
GD.Print("Welcome to Android!");
break;
case "iOS":
GD.Print("Welcome to iOS!");
break;
case "Web":
GD.Print("Welcome to the Web!");
break;
}
[/csharp]
[/codeblocks]

View File

@@ -39,36 +39,36 @@
[codeblocks]
[gdscript]
func _get(property):
if property == "fake_property":
print("Getting my property!")
return 4
if property == "fake_property":
print("Getting my property!")
return 4
func _get_property_list():
return [
{ "name": "fake_property", "type": TYPE_INT }
]
return [
{ "name": "fake_property", "type": TYPE_INT }
]
[/gdscript]
[csharp]
public override Variant _Get(StringName property)
{
if (property == "FakeProperty")
{
GD.Print("Getting my property!");
return 4;
}
return default;
if (property == "FakeProperty")
{
GD.Print("Getting my property!");
return 4;
}
return default;
}
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{
return
[
new Godot.Collections.Dictionary()
{
{ "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int },
},
];
return
[
new Godot.Collections.Dictionary()
{
{ "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int },
},
];
}
[/csharp]
[/codeblocks]
@@ -87,98 +87,98 @@
extends Node
@export var number_count = 3:
set(nc):
number_count = nc
numbers.resize(number_count)
notify_property_list_changed()
set(nc):
number_count = nc
numbers.resize(number_count)
notify_property_list_changed()
var numbers = PackedInt32Array([0, 0, 0])
func _get_property_list():
var properties = []
var properties = []
for i in range(number_count):
properties.append({
"name": "number_%d" % i,
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "ZERO,ONE,TWO,THREE,FOUR,FIVE",
})
for i in range(number_count):
properties.append({
"name": "number_%d" % i,
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "ZERO,ONE,TWO,THREE,FOUR,FIVE",
})
return properties
return properties
func _get(property):
if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int()
return numbers[index]
if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int()
return numbers[index]
func _set(property, value):
if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int()
numbers[index] = value
return true
return false
if property.begins_with("number_"):
var index = property.get_slice("_", 1).to_int()
numbers[index] = value
return true
return false
[/gdscript]
[csharp]
[Tool]
public partial class MyNode : Node
{
private int _numberCount;
private int _numberCount;
[Export]
public int NumberCount
{
get =&gt; _numberCount;
set
{
_numberCount = value;
_numbers.Resize(_numberCount);
NotifyPropertyListChanged();
}
}
[Export]
public int NumberCount
{
get =&gt; _numberCount;
set
{
_numberCount = value;
_numbers.Resize(_numberCount);
NotifyPropertyListChanged();
}
}
private Godot.Collections.Array&lt;int&gt; _numbers = [];
private Godot.Collections.Array&lt;int&gt; _numbers = [];
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{
Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; properties = [];
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{
Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; properties = [];
for (int i = 0; i &lt; _numberCount; i++)
{
properties.Add(new Godot.Collections.Dictionary()
{
{ "name", $"number_{i}" },
{ "type", (int)Variant.Type.Int },
{ "hint", (int)PropertyHint.Enum },
{ "hint_string", "Zero,One,Two,Three,Four,Five" },
});
}
for (int i = 0; i &lt; _numberCount; i++)
{
properties.Add(new Godot.Collections.Dictionary()
{
{ "name", $"number_{i}" },
{ "type", (int)Variant.Type.Int },
{ "hint", (int)PropertyHint.Enum },
{ "hint_string", "Zero,One,Two,Three,Four,Five" },
});
}
return properties;
}
return properties;
}
public override Variant _Get(StringName property)
{
string propertyName = property.ToString();
if (propertyName.StartsWith("number_"))
{
int index = int.Parse(propertyName.Substring("number_".Length));
return _numbers[index];
}
return default;
}
public override Variant _Get(StringName property)
{
string propertyName = property.ToString();
if (propertyName.StartsWith("number_"))
{
int index = int.Parse(propertyName.Substring("number_".Length));
return _numbers[index];
}
return default;
}
public override bool _Set(StringName property, Variant value)
{
string propertyName = property.ToString();
if (propertyName.StartsWith("number_"))
{
int index = int.Parse(propertyName.Substring("number_".Length));
_numbers[index] = value.As&lt;int&gt;();
return true;
}
return false;
}
public override bool _Set(StringName property, Variant value)
{
string propertyName = property.ToString();
if (propertyName.StartsWith("number_"))
{
int index = int.Parse(propertyName.Substring("number_".Length));
_numbers[index] = value.As&lt;int&gt;();
return true;
}
return false;
}
}
[/csharp]
[/codeblocks]
@@ -208,29 +208,29 @@
Initializes the iterator. [param iter] stores the iteration state. Since GDScript does not support passing arguments by reference, a single-element array is used as a wrapper. Returns [code]true[/code] so long as the iterator has not reached the end.
[codeblock]
class MyRange:
var _from
var _to
var _from
var _to
func _init(from, to):
assert(from &lt;= to)
_from = from
_to = to
func _init(from, to):
assert(from &lt;= to)
_from = from
_to = to
func _iter_init(iter):
iter[0] = _from
return iter[0] &lt; _to
func _iter_init(iter):
iter[0] = _from
return iter[0] &lt; _to
func _iter_next(iter):
iter[0] += 1
return iter[0] &lt; _to
func _iter_next(iter):
iter[0] += 1
return iter[0] &lt; _to
func _iter_get(iter):
return iter
func _iter_get(iter):
return iter
func _ready():
var my_range = MyRange.new(2, 5)
for x in my_range:
print(x) # Prints 2, 3, 4.
var my_range = MyRange.new(2, 5)
for x in my_range:
print(x) # Prints 2, 3, 4.
[/codeblock]
[b]Note:[/b] Alternatively, you can ignore [param iter] and use the object's state instead, see [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_advanced.html#custom-iterators]online docs[/url] for an example. Note that in this case you will not be able to reuse the same iterator instance in nested loops. Also, make sure you reset the iterator state in this method if you want to reuse the same instance multiple times.
</description>
@@ -250,16 +250,16 @@
[codeblocks]
[gdscript]
func _notification(what):
if what == NOTIFICATION_PREDELETE:
print("Goodbye!")
if what == NOTIFICATION_PREDELETE:
print("Goodbye!")
[/gdscript]
[csharp]
public override void _Notification(int what)
{
if (what == NotificationPredelete)
{
GD.Print("Goodbye!");
}
if (what == NotificationPredelete)
{
GD.Print("Goodbye!");
}
}
[/csharp]
[/codeblocks]
@@ -294,42 +294,42 @@
var internal_data = {}
func _set(property, value):
if property == "fake_property":
# Storing the value in the fake property.
internal_data["fake_property"] = value
return true
return false
if property == "fake_property":
# Storing the value in the fake property.
internal_data["fake_property"] = value
return true
return false
func _get_property_list():
return [
{ "name": "fake_property", "type": TYPE_INT }
]
return [
{ "name": "fake_property", "type": TYPE_INT }
]
[/gdscript]
[csharp]
private Godot.Collections.Dictionary _internalData = new Godot.Collections.Dictionary();
public override bool _Set(StringName property, Variant value)
{
if (property == "FakeProperty")
{
// Storing the value in the fake property.
_internalData["FakeProperty"] = value;
return true;
}
if (property == "FakeProperty")
{
// Storing the value in the fake property.
_internalData["FakeProperty"] = value;
return true;
}
return false;
return false;
}
public override Godot.Collections.Array&lt;Godot.Collections.Dictionary&gt; _GetPropertyList()
{
return
[
new Godot.Collections.Dictionary()
{
{ "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int },
},
];
return
[
new Godot.Collections.Dictionary()
{
{ "name", "FakeProperty" },
{ "type", (int)Variant.Type.Int },
},
];
}
[/csharp]
[/codeblocks]
@@ -341,11 +341,11 @@
Override this method to customize the return value of [method to_string], and therefore the object's representation as a [String].
[codeblock]
func _to_string():
return "Welcome to Godot 4!"
return "Welcome to Godot 4!"
func _init():
print(self) # Prints "Welcome to Godot 4!"
var a = str(self) # a is "Welcome to Godot 4!"
print(self) # Prints "Welcome to Godot 4!"
var a = str(self) # a is "Welcome to Godot 4!"
[/codeblock]
</description>
</method>
@@ -360,43 +360,43 @@
extends Node
@export var is_number_editable: bool:
set(value):
is_number_editable = value
notify_property_list_changed()
set(value):
is_number_editable = value
notify_property_list_changed()
@export var number: int
func _validate_property(property: Dictionary):
if property.name == "number" and not is_number_editable:
property.usage |= PROPERTY_USAGE_READ_ONLY
if property.name == "number" and not is_number_editable:
property.usage |= PROPERTY_USAGE_READ_ONLY
[/gdscript]
[csharp]
[Tool]
public partial class MyNode : Node
{
private bool _isNumberEditable;
private bool _isNumberEditable;
[Export]
public bool IsNumberEditable
{
get =&gt; _isNumberEditable;
set
{
_isNumberEditable = value;
NotifyPropertyListChanged();
}
}
[Export]
public bool IsNumberEditable
{
get =&gt; _isNumberEditable;
set
{
_isNumberEditable = value;
NotifyPropertyListChanged();
}
}
[Export]
public int Number { get; set; }
[Export]
public int Number { get; set; }
public override void _ValidateProperty(Godot.Collections.Dictionary property)
{
if (property["name"].AsStringName() == PropertyName.Number &amp;&amp; !IsNumberEditable)
{
var usage = property["usage"].As&lt;PropertyUsageFlags&gt;() | PropertyUsageFlags.ReadOnly;
property["usage"] = (int)usage;
}
}
public override void _ValidateProperty(Godot.Collections.Dictionary property)
{
if (property["name"].AsStringName() == PropertyName.Number &amp;&amp; !IsNumberEditable)
{
var usage = property["usage"].As&lt;PropertyUsageFlags&gt;() | PropertyUsageFlags.ReadOnly;
property["usage"] = (int)usage;
}
}
}
[/csharp]
[/codeblocks]
@@ -411,23 +411,23 @@
[codeblocks]
[gdscript]
add_user_signal("hurt", [
{ "name": "damage", "type": TYPE_INT },
{ "name": "source", "type": TYPE_OBJECT }
{ "name": "damage", "type": TYPE_INT },
{ "name": "source", "type": TYPE_OBJECT }
])
[/gdscript]
[csharp]
AddUserSignal("Hurt",
[
new Godot.Collections.Dictionary()
{
{ "name", "damage" },
{ "type", (int)Variant.Type.Int },
},
new Godot.Collections.Dictionary()
{
{ "name", "source" },
{ "type", (int)Variant.Type.Object },
},
new Godot.Collections.Dictionary()
{
{ "name", "damage" },
{ "type", (int)Variant.Type.Int },
},
new Godot.Collections.Dictionary()
{
{ "name", "source" },
{ "type", (int)Variant.Type.Object },
},
]);
[/csharp]
[/codeblocks]

View File

@@ -15,7 +15,7 @@
[codeblock]
var container = load("packed_data.res")
for key in container:
prints(key, container[key])
prints(key, container[key])
[/codeblock]
Prints:
[codeblock lang=text]

View File

@@ -10,11 +10,11 @@
packed.pack([1, 2, 3, ["nested1", "nested2"], 4, 5, 6])
for element in packed:
if element is PackedDataContainerRef:
for subelement in element:
print("::", subelement)
else:
print(element)
if element is PackedDataContainerRef:
for subelement in element:
print("::", subelement)
else:
print(element)
[/codeblock]
Prints:
[codeblock lang=text]

View File

@@ -41,9 +41,9 @@
# Only `node` and `body` are now packed.
var result = scene.pack(node)
if result == OK:
var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..."
if error != OK:
push_error("An error occurred while saving the scene to disk.")
var error = ResourceSaver.save(scene, "res://path/name.tscn") # Or "user://..."
if error != OK:
push_error("An error occurred while saving the scene to disk.")
[/gdscript]
[csharp]
// Create the objects.
@@ -63,11 +63,11 @@
Error result = scene.Pack(node);
if (result == Error.Ok)
{
Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..."
if (error != Error.Ok)
{
GD.PushError("An error occurred while saving the scene to disk.");
}
Error error = ResourceSaver.Save(scene, "res://path/name.tscn"); // Or "user://..."
if (error != Error.Ok)
{
GD.PushError("An error occurred while saving the scene to disk.");
}
}
[/csharp]
[/codeblocks]

View File

@@ -20,15 +20,15 @@
var peer
func _ready():
peer = PacketPeerUDP.new()
peer.bind(4433)
peer = PacketPeerUDP.new()
peer.bind(4433)
func _process(_delta):
if peer.get_available_packet_count() &gt; 0:
var array_bytes = peer.get_packet()
var packet_string = array_bytes.get_string_from_ascii()
print("Received message: ", packet_string)
if peer.get_available_packet_count() &gt; 0:
var array_bytes = peer.get_packet()
var packet_string = array_bytes.get_string_from_ascii()
print("Received message: ", packet_string)
[/codeblock]
[b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
@@ -141,9 +141,9 @@
# Client
while socket.wait() == OK:
var data = socket.get_packet().get_string_from_ascii()
if data == "Time to stop":
return
var data = socket.get_packet().get_string_from_ascii()
if data == "Time to stop":
return
[/gdscript]
[csharp]
var socket = new PacketPeerUdp();
@@ -154,11 +154,11 @@
// Client
while (socket.Wait() == OK)
{
string data = socket.GetPacket().GetStringFromASCII();
if (data == "Time to stop")
{
return;
}
string data = socket.GetPacket().GetStringFromASCII();
if (data == "Time to stop")
{
return;
}
}
[/csharp]
[/codeblocks]

View File

@@ -23,47 +23,47 @@
[codeblocks]
[gdscript]
func _ready():
var monitor_value = Callable(self, "get_monitor_value")
var monitor_value = Callable(self, "get_monitor_value")
# Adds monitor with name "MyName" to category "MyCategory".
Performance.add_custom_monitor("MyCategory/MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "MyCategory".
Performance.add_custom_monitor("MyCategory/MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom".
# Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different IDs, so the code is valid.
Performance.add_custom_monitor("MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom".
# Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different IDs, so the code is valid.
Performance.add_custom_monitor("MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom".
# Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different IDs, so the code is valid.
Performance.add_custom_monitor("Custom/MyMonitor", monitor_value)
# Adds monitor with name "MyName" to category "Custom".
# Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different IDs, so the code is valid.
Performance.add_custom_monitor("Custom/MyMonitor", monitor_value)
# Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitor_value)
# Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.add_custom_monitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitor_value)
func get_monitor_value():
return randi() % 25
return randi() % 25
[/gdscript]
[csharp]
public override void _Ready()
{
var monitorValue = new Callable(this, MethodName.GetMonitorValue);
var monitorValue = new Callable(this, MethodName.GetMonitorValue);
// Adds monitor with name "MyName" to category "MyCategory".
Performance.AddCustomMonitor("MyCategory/MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom".
// Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid.
Performance.AddCustomMonitor("MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "MyCategory".
Performance.AddCustomMonitor("MyCategory/MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom".
// Note: "MyCategory/MyMonitor" and "MyMonitor" have same name but different ids so the code is valid.
Performance.AddCustomMonitor("MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom".
// Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid.
Performance.AddCustomMonitor("Custom/MyMonitor", monitorValue);
// Adds monitor with name "MyName" to category "Custom".
// Note: "MyMonitor" and "Custom/MyMonitor" have same name and same category but different ids so the code is valid.
Performance.AddCustomMonitor("Custom/MyMonitor", monitorValue);
// Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.AddCustomMonitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitorValue);
// Adds monitor with name "MyCategoryOne/MyCategoryTwo/MyMonitor" to category "Custom".
Performance.AddCustomMonitor("MyCategoryOne/MyCategoryTwo/MyMonitor", monitorValue);
}
public int GetMonitorValue()
{
return GD.Randi() % 25;
return GD.Randi() % 25;
}
[/csharp]
[/codeblocks]

View File

@@ -33,34 +33,34 @@
</member>
<member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()">
The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API:
[codeblocks]
[gdscript]
var shape_rid = PhysicsServer2D.circle_shape_create()
var radius = 64
PhysicsServer2D.shape_set_data(shape_rid, radius)
[codeblocks]
[gdscript]
var shape_rid = PhysicsServer2D.circle_shape_create()
var radius = 64
PhysicsServer2D.shape_set_data(shape_rid, radius)
var params = PhysicsShapeQueryParameters2D.new()
params.shape_rid = shape_rid
var params = PhysicsShapeQueryParameters2D.new()
params.shape_rid = shape_rid
# Execute physics queries here...
# Execute physics queries here...
# Release the shape when done with physics queries.
PhysicsServer2D.free_rid(shape_rid)
[/gdscript]
[csharp]
RID shapeRid = PhysicsServer2D.CircleShapeCreate();
int radius = 64;
PhysicsServer2D.ShapeSetData(shapeRid, radius);
# Release the shape when done with physics queries.
PhysicsServer2D.free_rid(shape_rid)
[/gdscript]
[csharp]
RID shapeRid = PhysicsServer2D.CircleShapeCreate();
int radius = 64;
PhysicsServer2D.ShapeSetData(shapeRid, radius);
var params = new PhysicsShapeQueryParameters2D();
params.ShapeRid = shapeRid;
var params = new PhysicsShapeQueryParameters2D();
params.ShapeRid = shapeRid;
// Execute physics queries here...
// Execute physics queries here...
// Release the shape when done with physics queries.
PhysicsServer2D.FreeRid(shapeRid);
[/csharp]
[/codeblocks]
// Release the shape when done with physics queries.
PhysicsServer2D.FreeRid(shapeRid);
[/csharp]
[/codeblocks]
</member>
<member name="transform" type="Transform2D" setter="set_transform" getter="get_transform" default="Transform2D(1, 0, 0, 1, 0, 0)">
The queried shape's transform matrix.

View File

@@ -33,34 +33,34 @@
</member>
<member name="shape_rid" type="RID" setter="set_shape_rid" getter="get_shape_rid" default="RID()">
The queried shape's [RID] that will be used for collision/intersection queries. Use this over [member shape] if you want to optimize for performance using the Servers API:
[codeblocks]
[gdscript]
var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE)
var radius = 2.0
PhysicsServer3D.shape_set_data(shape_rid, radius)
[codeblocks]
[gdscript]
var shape_rid = PhysicsServer3D.shape_create(PhysicsServer3D.SHAPE_SPHERE)
var radius = 2.0
PhysicsServer3D.shape_set_data(shape_rid, radius)
var params = PhysicsShapeQueryParameters3D.new()
params.shape_rid = shape_rid
var params = PhysicsShapeQueryParameters3D.new()
params.shape_rid = shape_rid
# Execute physics queries here...
# Execute physics queries here...
# Release the shape when done with physics queries.
PhysicsServer3D.free_rid(shape_rid)
[/gdscript]
[csharp]
RID shapeRid = PhysicsServer3D.ShapeCreate(PhysicsServer3D.ShapeType.Sphere);
float radius = 2.0f;
PhysicsServer3D.ShapeSetData(shapeRid, radius);
# Release the shape when done with physics queries.
PhysicsServer3D.free_rid(shape_rid)
[/gdscript]
[csharp]
RID shapeRid = PhysicsServer3D.ShapeCreate(PhysicsServer3D.ShapeType.Sphere);
float radius = 2.0f;
PhysicsServer3D.ShapeSetData(shapeRid, radius);
var params = new PhysicsShapeQueryParameters3D();
params.ShapeRid = shapeRid;
var params = new PhysicsShapeQueryParameters3D();
params.ShapeRid = shapeRid;
// Execute physics queries here...
// Execute physics queries here...
// Release the shape when done with physics queries.
PhysicsServer3D.FreeRid(shapeRid);
[/csharp]
[/codeblocks]
// Release the shape when done with physics queries.
PhysicsServer3D.FreeRid(shapeRid);
[/csharp]
[/codeblocks]
</member>
<member name="transform" type="Transform3D" setter="set_transform" getter="get_transform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
The queried shape's transform matrix.

View File

@@ -56,9 +56,9 @@
var polygonPathFinder = new PolygonPathFinder();
Vector2[] points =
[
new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f)
new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f)
];
int[] connections = [0, 1, 1, 2, 2, 0];
polygonPathFinder.Setup(points, connections);
@@ -93,9 +93,9 @@
var polygonPathFinder = new PolygonPathFinder();
Vector2[] points =
[
new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f)
new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f)
];
int[] connections = [0, 1, 1, 2, 2, 0];
polygonPathFinder.Setup(points, connections);

View File

@@ -137,18 +137,18 @@
An [param id] can optionally be provided, as well as an accelerator ([param accel]). If no [param id] is provided, one will be created from the index. If no [param accel] is provided, then the default value of 0 (corresponding to [constant @GlobalScope.KEY_NONE]) will be assigned to the item (which means it won't have any accelerator). See [method get_item_accelerator] for more info on accelerators.
[codeblock]
func _ready():
add_multistate_item("Item", 3, 0)
add_multistate_item("Item", 3, 0)
index_pressed.connect(func(index: int):
toggle_item_multistate(index)
match get_item_multistate(index):
0:
print("First state")
1:
print("Second state")
2:
print("Third state")
)
index_pressed.connect(func(index: int):
toggle_item_multistate(index)
match get_item_multistate(index):
0:
print("First state")
1:
print("Second state")
2:
print("Third state")
)
[/codeblock]
[b]Note:[/b] Multistate items don't update their state automatically and must be done manually. See [method toggle_item_multistate], [method set_item_multistate] and [method get_item_multistate] for more info on how to control it.
</description>

View File

@@ -29,10 +29,10 @@
ProjectSettings.set("category/property_name", 0)
var property_info = {
"name": "category/property_name",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three"
"name": "category/property_name",
"type": TYPE_INT,
"hint": PROPERTY_HINT_ENUM,
"hint_string": "one,two,three"
}
ProjectSettings.add_property_info(property_info)
@@ -42,10 +42,10 @@
var propertyInfo = new Godot.Collections.Dictionary
{
{"name", "category/propertyName"},
{"type", (int)Variant.Type.Int},
{"hint", (int)PropertyHint.Enum},
{"hint_string", "one,two,three"},
{"name", "category/propertyName"},
{"type", (int)Variant.Type.Int},
{"hint", (int)PropertyHint.Enum},
{"hint_string", "one,two,three"},
};
ProjectSettings.AddPropertyInfo(propertyInfo);
@@ -133,15 +133,15 @@
[codeblock]
var path = ""
if OS.has_feature("editor"):
# Running from an editor binary.
# `path` will contain the absolute path to `hello.txt` located in the project root.
path = ProjectSettings.globalize_path("res://hello.txt")
# Running from an editor binary.
# `path` will contain the absolute path to `hello.txt` located in the project root.
path = ProjectSettings.globalize_path("res://hello.txt")
else:
# Running from an exported project.
# `path` will contain the absolute path to `hello.txt` next to the executable.
# This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
# but is close enough in spirit.
path = OS.get_executable_path().get_base_dir().path_join("hello.txt")
# Running from an exported project.
# `path` will contain the absolute path to `hello.txt` next to the executable.
# This is *not* identical to using `ProjectSettings.globalize_path()` with a `res://` path,
# but is close enough in spirit.
path = OS.get_executable_path().get_base_dir().path_join("hello.txt")
[/codeblock]
</description>
</method>
@@ -215,10 +215,10 @@
const SETTING_DEFAULT = 10.0
func _enter_tree():
if not ProjectSettings.has_setting(SETTING_NAME):
ProjectSettings.set_setting(SETTING_NAME, SETTING_DEFAULT)
if not ProjectSettings.has_setting(SETTING_NAME):
ProjectSettings.set_setting(SETTING_NAME, SETTING_DEFAULT)
ProjectSettings.set_initial_value(SETTING_NAME, SETTING_DEFAULT)
ProjectSettings.set_initial_value(SETTING_NAME, SETTING_DEFAULT)
[/codeblock]
If you have a project setting defined by an [EditorPlugin], but want to use it in a running project, you will need a similar code at runtime.
</description>

View File

@@ -72,12 +72,12 @@
@export var curve: Curve
func _ready():
var tween = create_tween()
# Interpolate the value using a custom curve.
tween.tween_property(self, "position:x", 300, 1).as_relative().set_custom_interpolator(tween_curve)
var tween = create_tween()
# Interpolate the value using a custom curve.
tween.tween_property(self, "position:x", 300, 1).as_relative().set_custom_interpolator(tween_curve)
func tween_curve(v):
return curve.sample_baked(v)
return curve.sample_baked(v)
[/gdscript]
[csharp]
[Export]
@@ -85,15 +85,15 @@
public override void _Ready()
{
Tween tween = CreateTween();
// Interpolate the value using a custom curve.
Callable tweenCurveCallable = Callable.From&lt;float, float&gt;(TweenCurve);
tween.TweenProperty(this, "position:x", 300.0f, 1.0f).AsRelative().SetCustomInterpolator(tweenCurveCallable);
Tween tween = CreateTween();
// Interpolate the value using a custom curve.
Callable tweenCurveCallable = Callable.From&lt;float, float&gt;(TweenCurve);
tween.TweenProperty(this, "position:x", 300.0f, 1.0f).AsRelative().SetCustomInterpolator(tweenCurveCallable);
}
private float TweenCurve(float value)
{
return Curve.SampleBaked(value);
return Curve.SampleBaked(value);
}
[/csharp]
[/codeblocks]

View File

@@ -10,7 +10,7 @@
[codeblock]
var rng = RandomNumberGenerator.new()
func _ready():
var my_random_number = rng.randf_range(-10.0, 10.0)
var my_random_number = rng.randf_range(-10.0, 10.0)
[/codeblock]
</description>
<tutorials>

View File

@@ -73,7 +73,7 @@
[b]Note:[/b] Downloading large buffers can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
[codeblock]
func _buffer_get_data_callback(array):
value = array.decode_u32(0)
value = array.decode_u32(0)
...
@@ -132,9 +132,9 @@
rd.compute_list_bind_uniform_set(compute_list, dilate_uniform_set, 1)
for i in atlas_slices:
rd.compute_list_set_push_constant(compute_list, push_constant, push_constant.size())
rd.compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z)
# No barrier, let them run all together.
rd.compute_list_set_push_constant(compute_list, push_constant, push_constant.size())
rd.compute_list_dispatch(compute_list, group_size.x, group_size.y, group_size.z)
# No barrier, let them run all together.
rd.compute_list_end()
[/codeblock]
@@ -981,7 +981,7 @@
[b]Note:[/b] Downloading large textures can have a prohibitive cost for real-time even when using the asynchronous method due to hardware bandwidth limitations. When dealing with large resources, you can adjust settings such as [member ProjectSettings.rendering/rendering_device/staging_buffer/texture_download_region_size_px] and [member ProjectSettings.rendering/rendering_device/staging_buffer/block_size_kb] to improve the transfer speed at the cost of extra memory.
[codeblock]
func _texture_get_data_callback(array):
value = array.decode_u32(0)
value = array.decode_u32(0)
...
@@ -2101,8 +2101,8 @@
rd = RenderingServer.get_rendering_device()
if rd.has_feature(RenderingDevice.SUPPORTS_BUFFER_DEVICE_ADDRESS):
storage_buffer = rd.storage_buffer_create(bytes.size(), bytes, RenderingDevice.STORAGE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS):
storage_buffer_address = rd.buffer_get_device_address(storage_buffer)
storage_buffer = rd.storage_buffer_create(bytes.size(), bytes, RenderingDevice.STORAGE_BUFFER_USAGE_SHADER_DEVICE_ADDRESS)
storage_buffer_address = rd.buffer_get_device_address(storage_buffer)
[/gdscript]
[/codeblocks]
</constant>
@@ -2164,7 +2164,7 @@
</constant>
<constant name="RENDER_PRIMITIVE_TRIANGLES_WITH_ADJACENCY" value="6" enum="RenderPrimitive">
[url=https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#drawing-triangle-lists-with-adjacency]Triangle list rendering primitive with adjacency.[/url]
[b]Note:[/b] Adjacency is only useful with geometry shaders, which Godot does not expose.
[b]Note:[/b] Adjacency is only useful with geometry shaders, which Godot does not expose.
</constant>
<constant name="RENDER_PRIMITIVE_TRIANGLE_STRIPS" value="7" enum="RenderPrimitive">
Triangle strip rendering primitive. Triangles drawn are connected to the previous triangle.

View File

@@ -93,12 +93,12 @@
The normalization factor can be calculated from exposure value (EV100) as follows:
[codeblock]
func get_exposure_normalization(ev100: float):
return 1.0 / (pow(2.0, ev100) * 1.2)
return 1.0 / (pow(2.0, ev100) * 1.2)
[/codeblock]
The exposure value can be calculated from aperture (in f-stops), shutter speed (in seconds), and sensitivity (in ISO) as follows:
[codeblock]
func get_exposure(aperture: float, shutter_speed: float, sensitivity: float):
return log((aperture * aperture) / shutter_speed * (100.0 / sensitivity)) / log(2)
return log((aperture * aperture) / shutter_speed * (100.0 / sensitivity)) / log(2)
[/codeblock]
</description>
</method>
@@ -1634,10 +1634,10 @@
[b]Note:[/b] Rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method get_rendering_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following:
[codeblock]
func _ready():
for _i in 2:
await get_tree().process_frame
for _i in 2:
await get_tree().process_frame
print(RenderingServer.get_rendering_info(RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME))
print(RenderingServer.get_rendering_info(RENDERING_INFO_TOTAL_DRAW_CALLS_IN_FRAME))
[/codeblock]
</description>
</method>
@@ -3858,8 +3858,8 @@
[codeblocks]
[gdscript]
func _ready():
RenderingServer.viewport_attach_to_screen(get_viewport().get_viewport_rid(), Rect2())
RenderingServer.viewport_attach_to_screen($Viewport.get_viewport_rid(), Rect2(0, 0, 600, 600))
RenderingServer.viewport_attach_to_screen(get_viewport().get_viewport_rid(), Rect2())
RenderingServer.viewport_attach_to_screen($Viewport.get_viewport_rid(), Rect2(0, 0, 600, 600))
[/gdscript]
[/codeblocks]
Using this can result in significant optimization, especially on lower-end devices. However, it comes at the cost of having to manage your viewports manually. For further optimization, see [method viewport_set_render_direct_to_screen].
@@ -3901,14 +3901,14 @@
[b]Note:[/b] Viewport rendering information is not available until at least 2 frames have been rendered by the engine. If rendering information is not available, [method viewport_get_render_info] returns [code]0[/code]. To print rendering information in [code]_ready()[/code] successfully, use the following:
[codeblock]
func _ready():
for _i in 2:
await get_tree().process_frame
for _i in 2:
await get_tree().process_frame
print(
RenderingServer.viewport_get_render_info(get_viewport().get_viewport_rid(),
RenderingServer.VIEWPORT_RENDER_INFO_TYPE_VISIBLE,
RenderingServer.VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME)
)
print(
RenderingServer.viewport_get_render_info(get_viewport().get_viewport_rid(),
RenderingServer.VIEWPORT_RENDER_INFO_TYPE_VISIBLE,
RenderingServer.VIEWPORT_RENDER_INFO_DRAW_CALLS_IN_FRAME)
)
[/codeblock]
</description>
</method>

View File

@@ -44,7 +44,7 @@
var damage = 0
func _setup_local_to_scene():
damage = randi_range(10, 40)
damage = randi_range(10, 40)
[/codeblock]
</description>
</method>
@@ -77,10 +77,10 @@
[b]Note:[/b] For custom resources, it's recommended to call this method whenever a meaningful change occurs, such as a modified property. This ensures that custom [Object]s depending on the resource are properly updated.
[codeblock]
var damage:
set(new_value):
if damage != new_value:
damage = new_value
emit_changed()
set(new_value):
if damage != new_value:
damage = new_value
emit_changed()
[/codeblock]
</description>
</method>

View File

@@ -17,13 +17,13 @@
Called when the engine compilation profile editor wants to check what build options an imported resource needs. For example, [ResourceImporterDynamicFont] has a property called [member ResourceImporterDynamicFont.multichannel_signed_distance_field], that depends on the engine to be build with the "msdfgen" module. If that resource happened to be a custom one, it would be handled like this:
[codeblock]
func _get_build_dependencies(path):
var resource = load(path)
var dependencies = PackedStringArray()
var resource = load(path)
var dependencies = PackedStringArray()
if resource.multichannel_signed_distance_field:
dependencies.push_back("module_msdfgen_enabled")
if resource.multichannel_signed_distance_field:
dependencies.push_back("module_msdfgen_enabled")
return dependencies
return dependencies
[/codeblock]
</description>
</method>

View File

@@ -48,8 +48,8 @@
[b]Note:[/b] The dependencies are returned with slices separated by [code]::[/code]. You can use [method String.get_slice] to get their components.
[codeblock]
for dependency in ResourceLoader.get_dependencies(path):
print(dependency.get_slice("::", 0)) # Prints the UID.
print(dependency.get_slice("::", 2)) # Prints the path.
print(dependency.get_slice("::", 0)) # Prints the UID.
print(dependency.get_slice("::", 2)) # Prints the path.
[/codeblock]
</description>
</method>

View File

@@ -147,38 +147,38 @@
[codeblocks]
[gdscript]
func _ready():
var menu = get_menu()
# Remove "Select All" item.
menu.remove_item(MENU_SELECT_ALL)
# Add custom items.
menu.add_separator()
menu.add_item("Duplicate Text", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
var menu = get_menu()
# Remove "Select All" item.
menu.remove_item(MENU_SELECT_ALL)
# Add custom items.
menu.add_separator()
menu.add_item("Duplicate Text", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id):
if id == MENU_MAX + 1:
add_text("\n" + get_parsed_text())
if id == MENU_MAX + 1:
add_text("\n" + get_parsed_text())
[/gdscript]
[csharp]
public override void _Ready()
{
var menu = GetMenu();
// Remove "Select All" item.
menu.RemoveItem(RichTextLabel.MenuItems.SelectAll);
// Add custom items.
menu.AddSeparator();
menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
var menu = GetMenu();
// Remove "Select All" item.
menu.RemoveItem(RichTextLabel.MenuItems.SelectAll);
// Add custom items.
menu.AddSeparator();
menu.AddItem("Duplicate Text", RichTextLabel.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
}
public void OnItemPressed(int id)
{
if (id == TextEdit.MenuItems.Max + 1)
{
AddText("\n" + GetParsedText());
}
if (id == TextEdit.MenuItems.Max + 1)
{
AddText("\n" + GetParsedText());
}
}
[/csharp]
[/codeblocks]
@@ -277,10 +277,10 @@
extends RichTextLabel
func _ready():
install_effect(MyCustomEffect.new())
install_effect(MyCustomEffect.new())
# Alternatively, if not using `class_name` in the script that extends RichTextEffect:
install_effect(preload("res://effect.gd").new())
# Alternatively, if not using `class_name` in the script that extends RichTextEffect:
install_effect(preload("res://effect.gd").new())
[/codeblock]
</description>
</method>
@@ -773,8 +773,8 @@
# This assumes RichTextLabel's `meta_clicked` signal was connected to
# the function below using the signal connection dialog.
func _richtextlabel_on_meta_clicked(meta):
# `meta` is of Variant type, so convert it to a String to avoid script errors at run-time.
OS.shell_open(str(meta))
# `meta` is of Variant type, so convert it to a String to avoid script errors at run-time.
OS.shell_open(str(meta))
[/gdscript]
[/codeblocks]
</description>

View File

@@ -183,19 +183,19 @@
@onready var ball = $Ball
func get_ball_inertia():
return 1.0 / PhysicsServer2D.body_get_direct_state(ball.get_rid()).inverse_inertia
return 1.0 / PhysicsServer2D.body_get_direct_state(ball.get_rid()).inverse_inertia
[/gdscript]
[csharp]
private RigidBody2D _ball;
public override void _Ready()
{
_ball = GetNode&lt;RigidBody2D&gt;("Ball");
_ball = GetNode&lt;RigidBody2D&gt;("Ball");
}
private float GetBallInertia()
{
return 1.0f / PhysicsServer2D.BodyGetDirectState(_ball.GetRid()).InverseInertia;
return 1.0f / PhysicsServer2D.BodyGetDirectState(_ball.GetRid()).InverseInertia;
}
[/csharp]
[/codeblocks]

View File

@@ -190,19 +190,19 @@
@onready var ball = $Ball
func get_ball_inertia():
return PhysicsServer3D.body_get_direct_state(ball.get_rid()).inverse_inertia.inverse()
return PhysicsServer3D.body_get_direct_state(ball.get_rid()).inverse_inertia.inverse()
[/gdscript]
[csharp]
private RigidBody3D _ball;
public override void _Ready()
{
_ball = GetNode&lt;RigidBody3D&gt;("Ball");
_ball = GetNode&lt;RigidBody3D&gt;("Ball");
}
private Vector3 GetBallInertia()
{
return PhysicsServer3D.BodyGetDirectState(_ball.GetRid()).InverseInertia.Inverse();
return PhysicsServer3D.BodyGetDirectState(_ball.GetRid()).InverseInertia.Inverse();
}
[/csharp]
[/codeblocks]

View File

@@ -33,8 +33,8 @@
[codeblock]
# Calls "hide" to all nodes of the "enemies" group, at the end of the frame and in reverse tree order.
get_tree().call_group_flags(
SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE,
"enemies", "hide")
SceneTree.GROUP_CALL_DEFERRED | SceneTree.GROUP_CALL_REVERSE,
"enemies", "hide")
[/codeblock]
[b]Note:[/b] In C#, [param method] must be in snake_case when referring to built-in Godot methods. Prefer using the names exposed in the [code]MethodName[/code] class to avoid allocating a new [StringName] on each call.
</description>
@@ -76,16 +76,16 @@
[codeblocks]
[gdscript]
func some_function():
print("start")
await get_tree().create_timer(1.0).timeout
print("end")
print("start")
await get_tree().create_timer(1.0).timeout
print("end")
[/gdscript]
[csharp]
public async Task SomeFunction()
{
GD.Print("start");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("end");
GD.Print("start");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("end");
}
[/csharp]
[/codeblocks]

View File

@@ -9,16 +9,16 @@
[codeblocks]
[gdscript]
func some_function():
print("Timer started.")
await get_tree().create_timer(1.0).timeout
print("Timer ended.")
print("Timer started.")
await get_tree().create_timer(1.0).timeout
print("Timer ended.")
[/gdscript]
[csharp]
public async Task SomeFunction()
{
GD.Print("Timer started.");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("Timer ended.");
GD.Print("Timer started.");
await ToSignal(GetTree().CreateTimer(1.0f), SceneTreeTimer.SignalName.Timeout);
GD.Print("Timer ended.");
}
[/csharp]
[/codeblocks]

View File

@@ -8,18 +8,18 @@
[codeblocks]
[gdscript]
func _ready():
var dialog = ScriptCreateDialog.new();
dialog.config("Node", "res://new_node.gd") # For in-engine types.
dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types.
dialog.popup_centered()
var dialog = ScriptCreateDialog.new();
dialog.config("Node", "res://new_node.gd") # For in-engine types.
dialog.config("\"res://base_node.gd\"", "res://derived_node.gd") # For script types.
dialog.popup_centered()
[/gdscript]
[csharp]
public override void _Ready()
{
var dialog = new ScriptCreateDialog();
dialog.Config("Node", "res://NewNode.cs"); // For in-engine types.
dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types.
dialog.PopupCentered();
var dialog = new ScriptCreateDialog();
dialog.Config("Node", "res://NewNode.cs"); // For in-engine types.
dialog.Config("\"res://BaseNode.cs\"", "res://DerivedNode.cs"); // For script types.
dialog.PopupCentered();
}
[/csharp]
[/codeblocks]

View File

@@ -57,7 +57,7 @@
[b]Note:[/b] If you are setting this value in the [method Node._ready] function or earlier, it needs to be wrapped with [method Object.set_deferred], since scroll bar's [member Range.max_value] is not initialized yet.
[codeblock]
func _ready():
set_deferred("scroll_horizontal", 600)
set_deferred("scroll_horizontal", 600)
[/codeblock]
</member>
<member name="scroll_horizontal_custom_step" type="float" setter="set_horizontal_custom_step" getter="get_horizontal_custom_step" default="-1.0">
@@ -68,7 +68,7 @@
[b]Note:[/b] Setting it early needs to be deferred, just like in [member scroll_horizontal].
[codeblock]
func _ready():
set_deferred("scroll_vertical", 600)
set_deferred("scroll_vertical", 600)
[/codeblock]
</member>
<member name="scroll_vertical_custom_step" type="float" setter="set_vertical_custom_step" getter="get_vertical_custom_step" default="-1.0">

View File

@@ -28,44 +28,44 @@
[codeblocks]
[gdscript]
func _ready():
var button = Button.new()
# `button_down` here is a Signal Variant type. We therefore call the Signal.connect() method, not Object.connect().
# See discussion below for a more in-depth overview of the API.
button.button_down.connect(_on_button_down)
var button = Button.new()
# `button_down` here is a Signal Variant type. We therefore call the Signal.connect() method, not Object.connect().
# See discussion below for a more in-depth overview of the API.
button.button_down.connect(_on_button_down)
# This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new()
# We use Signal.connect() again, and we also use the Callable.bind() method,
# which returns a new Callable with the parameter binds.
player.hit.connect(_on_player_hit.bind("sword", 100))
# This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new()
# We use Signal.connect() again, and we also use the Callable.bind() method,
# which returns a new Callable with the parameter binds.
player.hit.connect(_on_player_hit.bind("sword", 100))
func _on_button_down():
print("Button down!")
print("Button down!")
func _on_player_hit(weapon_type, damage):
print("Hit with weapon %s for %d damage." % [weapon_type, damage])
print("Hit with weapon %s for %d damage." % [weapon_type, damage])
[/gdscript]
[csharp]
public override void _Ready()
{
var button = new Button();
// C# supports passing signals as events, so we can use this idiomatic construct:
button.ButtonDown += OnButtonDown;
var button = new Button();
// C# supports passing signals as events, so we can use this idiomatic construct:
button.ButtonDown += OnButtonDown;
// This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player();
// We can use lambdas when we need to bind additional parameters.
player.Hit += () =&gt; OnPlayerHit("sword", 100);
// This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player();
// We can use lambdas when we need to bind additional parameters.
player.Hit += () =&gt; OnPlayerHit("sword", 100);
}
private void OnButtonDown()
{
GD.Print("Button down!");
GD.Print("Button down!");
}
private void OnPlayerHit(string weaponType, int damage)
{
GD.Print($"Hit with weapon {weaponType} for {damage} damage.");
GD.Print($"Hit with weapon {weaponType} for {damage} damage.");
}
[/csharp]
[/codeblocks]
@@ -74,34 +74,34 @@
[codeblocks]
[gdscript]
func _ready():
var button = Button.new()
# Option 1: Object.connect() with an implicit Callable for the defined function.
button.connect("button_down", _on_button_down)
# Option 2: Object.connect() with a constructed Callable using a target object and method name.
button.connect("button_down", Callable(self, "_on_button_down"))
# Option 3: Signal.connect() with an implicit Callable for the defined function.
button.button_down.connect(_on_button_down)
# Option 4: Signal.connect() with a constructed Callable using a target object and method name.
button.button_down.connect(Callable(self, "_on_button_down"))
var button = Button.new()
# Option 1: Object.connect() with an implicit Callable for the defined function.
button.connect("button_down", _on_button_down)
# Option 2: Object.connect() with a constructed Callable using a target object and method name.
button.connect("button_down", Callable(self, "_on_button_down"))
# Option 3: Signal.connect() with an implicit Callable for the defined function.
button.button_down.connect(_on_button_down)
# Option 4: Signal.connect() with a constructed Callable using a target object and method name.
button.button_down.connect(Callable(self, "_on_button_down"))
func _on_button_down():
print("Button down!")
print("Button down!")
[/gdscript]
[csharp]
public override void _Ready()
{
var button = new Button();
// Option 1: In C#, we can use signals as events and connect with this idiomatic syntax:
button.ButtonDown += OnButtonDown;
// Option 2: GodotObject.Connect() with a constructed Callable from a method group.
button.Connect(Button.SignalName.ButtonDown, Callable.From(OnButtonDown));
// Option 3: GodotObject.Connect() with a constructed Callable using a target object and method name.
button.Connect(Button.SignalName.ButtonDown, new Callable(this, MethodName.OnButtonDown));
var button = new Button();
// Option 1: In C#, we can use signals as events and connect with this idiomatic syntax:
button.ButtonDown += OnButtonDown;
// Option 2: GodotObject.Connect() with a constructed Callable from a method group.
button.Connect(Button.SignalName.ButtonDown, Callable.From(OnButtonDown));
// Option 3: GodotObject.Connect() with a constructed Callable using a target object and method name.
button.Connect(Button.SignalName.ButtonDown, new Callable(this, MethodName.OnButtonDown));
}
private void OnButtonDown()
{
GD.Print("Button down!");
GD.Print("Button down!");
}
[/csharp]
[/codeblocks]
@@ -112,37 +112,37 @@
[codeblocks]
[gdscript]
func _ready():
# This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new()
# Using Callable.bind().
player.hit.connect(_on_player_hit.bind("sword", 100))
# This assumes that a `Player` class exists, which defines a `hit` signal.
var player = Player.new()
# Using Callable.bind().
player.hit.connect(_on_player_hit.bind("sword", 100))
# Parameters added when emitting the signal are passed first.
player.hit.emit("Dark lord", 5)
# Parameters added when emitting the signal are passed first.
player.hit.emit("Dark lord", 5)
# We pass two arguments when emitting (`hit_by`, `level`),
# and bind two more arguments when connecting (`weapon_type`, `damage`).
func _on_player_hit(hit_by, level, weapon_type, damage):
print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage])
print("Hit by %s (level %d) with weapon %s for %d damage." % [hit_by, level, weapon_type, damage])
[/gdscript]
[csharp]
public override void _Ready()
{
// This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player();
// Using lambda expressions that create a closure that captures the additional parameters.
// The lambda only receives the parameters defined by the signal's delegate.
player.Hit += (hitBy, level) =&gt; OnPlayerHit(hitBy, level, "sword", 100);
// This assumes that a `Player` class exists, which defines a `Hit` signal.
var player = new Player();
// Using lambda expressions that create a closure that captures the additional parameters.
// The lambda only receives the parameters defined by the signal's delegate.
player.Hit += (hitBy, level) =&gt; OnPlayerHit(hitBy, level, "sword", 100);
// Parameters added when emitting the signal are passed first.
player.EmitSignal(SignalName.Hit, "Dark lord", 5);
// Parameters added when emitting the signal are passed first.
player.EmitSignal(SignalName.Hit, "Dark lord", 5);
}
// We pass two arguments when emitting (`hit_by`, `level`),
// and bind two more arguments when connecting (`weapon_type`, `damage`).
private void OnPlayerHit(string hitBy, int level, string weaponType, int damage)
{
GD.Print($"Hit by {hitBy} (level {level}) with weapon {weaponType} for {damage} damage.");
GD.Print($"Hit by {hitBy} (level {level}) with weapon {weaponType} for {damage} damage.");
}
[/csharp]
[/codeblocks]
@@ -184,10 +184,10 @@
A signal can only be connected once to the same [Callable]. If the signal is already connected, this method returns [constant ERR_INVALID_PARAMETER] and generates an error, unless the signal is connected with [constant Object.CONNECT_REFERENCE_COUNTED]. To prevent this, use [method is_connected] first to check for existing connections.
[codeblock]
for button in $Buttons.get_children():
button.pressed.connect(_on_pressed.bind(button))
button.pressed.connect(_on_pressed.bind(button))
func _on_pressed(button):
print(button.name, " was pressed")
print(button.name, " was pressed")
[/codeblock]
[b]Note:[/b] If the [param callable]'s object is freed, the connection will be lost.
</description>

View File

@@ -18,23 +18,23 @@
[codeblocks]
[gdscript]
func _input(event):
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)):
print("A click!")
if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
if get_rect().has_point(to_local(event.position)):
print("A click!")
[/gdscript]
[csharp]
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton inputEventMouse)
{
if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == MouseButton.Left)
{
if (GetRect().HasPoint(ToLocal(inputEventMouse.Position)))
{
GD.Print("A click!");
}
}
}
if (@event is InputEventMouseButton inputEventMouse)
{
if (inputEventMouse.Pressed &amp;&amp; inputEventMouse.ButtonIndex == MouseButton.Left)
{
if (GetRect().HasPoint(ToLocal(inputEventMouse.Position)))
{
GD.Print("A click!");
}
}
}
}
[/csharp]
[/codeblocks]

View File

@@ -46,12 +46,12 @@
[b]Example:[/b] Possible return value. This means columns [code]0[/code] to [code]4[/code] should be red, and columns [code]5[/code] to the end of the line should be green:
[codeblock]
{
0: {
"color": Color(1, 0, 0)
},
5: {
"color": Color(0, 1, 0)
}
0: {
"color": Color(1, 0, 0)
},
5: {
"color": Color(0, 1, 0)
}
}
[/codeblock]
</description>

View File

@@ -132,9 +132,9 @@
begin_complex_operation()
begin_multicaret_edit()
for i in range(get_caret_count()):
if multicaret_edit_ignore_caret(i):
continue
# Logic here.
if multicaret_edit_ignore_caret(i):
continue
# Logic here.
end_multicaret_edit()
end_complex_operation()
[/codeblock]
@@ -466,38 +466,38 @@
[codeblocks]
[gdscript]
func _ready():
var menu = get_menu()
# Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items.
menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
var menu = get_menu()
# Remove all items after "Redo".
menu.item_count = menu.get_item_index(MENU_REDO) + 1
# Add custom items.
menu.add_separator()
menu.add_item("Insert Date", MENU_MAX + 1)
# Connect callback.
menu.id_pressed.connect(_on_item_pressed)
func _on_item_pressed(id):
if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system())
if id == MENU_MAX + 1:
insert_text_at_caret(Time.get_date_string_from_system())
[/gdscript]
[csharp]
public override void _Ready()
{
var menu = GetMenu();
// Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(TextEdit.MenuItems.Redo) + 1;
// Add custom items.
menu.AddSeparator();
menu.AddItem("Insert Date", TextEdit.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
var menu = GetMenu();
// Remove all items after "Redo".
menu.ItemCount = menu.GetItemIndex(TextEdit.MenuItems.Redo) + 1;
// Add custom items.
menu.AddSeparator();
menu.AddItem("Insert Date", TextEdit.MenuItems.Max + 1);
// Add event handler.
menu.IdPressed += OnItemPressed;
}
public void OnItemPressed(int id)
{
if (id == TextEdit.MenuItems.Max + 1)
{
InsertTextAtCaret(Time.GetDateStringFromSystem());
}
if (id == TextEdit.MenuItems.Max + 1)
{
InsertTextAtCaret(Time.GetDateStringFromSystem());
}
}
[/csharp]
[/codeblocks]
@@ -971,17 +971,17 @@
[gdscript]
var result = search("print", SEARCH_WHOLE_WORDS, 0, 0)
if result.x != -1:
# Result found.
var line_number = result.y
var column_number = result.x
# Result found.
var line_number = result.y
var column_number = result.x
[/gdscript]
[csharp]
Vector2I result = Search("print", (uint)TextEdit.SearchFlags.WholeWords, 0, 0);
if (result.X != -1)
{
// Result found.
int lineNumber = result.Y;
int columnNumber = result.X;
// Result found.
int lineNumber = result.Y;
int columnNumber = result.X;
}
[/csharp]
[/codeblocks]

View File

@@ -9,12 +9,12 @@
[codeblock]
var dummy_text_server = TextServerManager.find_interface("Dummy")
if dummy_text_server != null:
TextServerManager.set_primary_interface(dummy_text_server)
# If the other text servers are unneeded, they can be removed:
for i in TextServerManager.get_interface_count():
var text_server = TextServerManager.get_interface(i)
if text_server != dummy_text_server:
TextServerManager.remove_interface(text_server)
TextServerManager.set_primary_interface(dummy_text_server)
# If the other text servers are unneeded, they can be removed:
for i in TextServerManager.get_interface_count():
var text_server = TextServerManager.get_interface(i)
if text_server != dummy_text_server:
TextServerManager.remove_interface(text_server)
[/codeblock]
The command line argument [code]--text-driver Dummy[/code] (case-sensitive) can be used to force the "Dummy" [TextServer] on any project.
</description>

View File

@@ -128,12 +128,12 @@
If [param layer] is negative, the layers are accessed from the last one.
[codeblock]
func get_clicked_tile_power():
var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position())
var data = tile_map.get_cell_tile_data(0, clicked_cell)
if data:
return data.get_custom_data("power")
else:
return 0
var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position())
var data = tile_map.get_cell_tile_data(0, clicked_cell)
if data:
return data.get_custom_data("power")
else:
return 0
[/codeblock]
If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies. See [method TileSet.map_tile_proxy].
</description>

View File

@@ -102,12 +102,12 @@
Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource].
[codeblock]
func get_clicked_tile_power():
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var data = tile_map_layer.get_cell_tile_data(clicked_cell)
if data:
return data.get_custom_data("power")
else:
return 0
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var data = tile_map_layer.get_cell_tile_data(clicked_cell)
if data:
return data.get_custom_data("power")
else:
return 0
[/codeblock]
</description>
</method>

View File

@@ -292,16 +292,16 @@
[codeblock]
var alternate_id = $TileMapLayer.get_cell_alternative_tile(Vector2i(2, 2))
if not alternate_id &amp; TileSetAtlasSource.TRANSFORM_FLIP_H:
# If tile is not already flipped, flip it.
$TileMapLayer.set_cell(Vector2i(2, 2), source_id, atlas_coords, alternate_id | TileSetAtlasSource.TRANSFORM_FLIP_H)
# If tile is not already flipped, flip it.
$TileMapLayer.set_cell(Vector2i(2, 2), source_id, atlas_coords, alternate_id | TileSetAtlasSource.TRANSFORM_FLIP_H)
[/codeblock]
[b]Note:[/b] These transformations can be combined to do the equivalent of 0, 90, 180, and 270 degree rotations, as shown below:
[codeblock]
enum TileTransform {
ROTATE_0 = 0,
ROTATE_90 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_H,
ROTATE_180 = TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V,
ROTATE_270 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_V,
ROTATE_0 = 0,
ROTATE_90 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_H,
ROTATE_180 = TileSetAtlasSource.TRANSFORM_FLIP_H | TileSetAtlasSource.TRANSFORM_FLIP_V,
ROTATE_270 = TileSetAtlasSource.TRANSFORM_TRANSPOSE | TileSetAtlasSource.TRANSFORM_FLIP_V,
}
[/codeblock]
</constant>

View File

@@ -12,23 +12,23 @@
[gdscript]
var source_id = tile_map_layer.get_cell_source_id(Vector2i(x, y))
if source_id &gt; -1:
var scene_source = tile_map_layer.tile_set.get_source(source_id)
if scene_source is TileSetScenesCollectionSource:
var alt_id = tile_map_layer.get_cell_alternative_tile(Vector2i(x, y))
# The assigned PackedScene.
var scene = scene_source.get_scene_tile_scene(alt_id)
var scene_source = tile_map_layer.tile_set.get_source(source_id)
if scene_source is TileSetScenesCollectionSource:
var alt_id = tile_map_layer.get_cell_alternative_tile(Vector2i(x, y))
# The assigned PackedScene.
var scene = scene_source.get_scene_tile_scene(alt_id)
[/gdscript]
[csharp]
int sourceId = tileMapLayer.GetCellSourceId(new Vector2I(x, y));
if (sourceId &gt; -1)
{
TileSetSource source = tileMapLayer.TileSet.GetSource(sourceId);
if (source is TileSetScenesCollectionSource sceneSource)
{
int altId = tileMapLayer.GetCellAlternativeTile(new Vector2I(x, y));
// The assigned PackedScene.
PackedScene scene = sceneSource.GetSceneTileScene(altId);
}
TileSetSource source = tileMapLayer.TileSet.GetSource(sourceId);
if (source is TileSetScenesCollectionSource sceneSource)
{
int altId = tileMapLayer.GetCellAlternativeTile(new Vector2I(x, y));
// The assigned PackedScene.
PackedScene scene = sceneSource.GetSceneTileScene(altId);
}
}
[/csharp]
[/codeblocks]

View File

@@ -9,7 +9,7 @@
Without requiring much code, a timer node can be added and configured in the editor. The [signal timeout] signal it emits can also be connected through the Node dock in the editor:
[codeblock]
func _on_timer_timeout():
print("Time to attack!")
print("Time to attack!")
[/codeblock]
[b]Note:[/b] To create a one-shot timer without instantiating a node, use [method SceneTree.create_timer].
[b]Note:[/b] Timers are affected by [member Engine.time_scale]. The higher the time scale, the sooner timers will end. How often a timer processes may depend on the framerate or [member Engine.physics_ticks_per_second].

View File

@@ -109,9 +109,9 @@
[codeblocks]
[gdscript]
var my_transform = Transform2D(
Vector2(2, 0),
Vector2(0, 4),
Vector2(0, 0)
Vector2(2, 0),
Vector2(0, 4),
Vector2(0, 0)
)
# Rotating the Transform2D in any way preserves its scale.
my_transform = my_transform.rotated(TAU / 2)
@@ -120,9 +120,9 @@
[/gdscript]
[csharp]
var myTransform = new Transform2D(
Vector3(2.0f, 0.0f),
Vector3(0.0f, 4.0f),
Vector3(0.0f, 0.0f)
Vector3(2.0f, 0.0f),
Vector3(0.0f, 4.0f),
Vector3(0.0f, 0.0f)
);
// Rotating the Transform2D in any way preserves its scale.
myTransform = myTransform.Rotated(Mathf.Tau / 2.0f);

View File

@@ -9,24 +9,24 @@
[codeblocks]
[gdscript]
func _ready():
var tree = Tree.new()
var root = tree.create_item()
tree.hide_root = true
var child1 = tree.create_item(root)
var child2 = tree.create_item(root)
var subchild1 = tree.create_item(child1)
subchild1.set_text(0, "Subchild1")
var tree = Tree.new()
var root = tree.create_item()
tree.hide_root = true
var child1 = tree.create_item(root)
var child2 = tree.create_item(root)
var subchild1 = tree.create_item(child1)
subchild1.set_text(0, "Subchild1")
[/gdscript]
[csharp]
public override void _Ready()
{
var tree = new Tree();
TreeItem root = tree.CreateItem();
tree.HideRoot = true;
TreeItem child1 = tree.CreateItem(root);
TreeItem child2 = tree.CreateItem(root);
TreeItem subchild1 = tree.CreateItem(child1);
subchild1.SetText(0, "Subchild1");
var tree = new Tree();
TreeItem root = tree.CreateItem();
tree.HideRoot = true;
TreeItem child1 = tree.CreateItem(root);
TreeItem child2 = tree.CreateItem(root);
TreeItem subchild1 = tree.CreateItem(child1);
subchild1.SetText(0, "Subchild1");
}
[/csharp]
[/codeblocks]
@@ -153,20 +153,20 @@
[codeblocks]
[gdscript]
func _ready():
$Tree.item_edited.connect(on_Tree_item_edited)
$Tree.item_edited.connect(on_Tree_item_edited)
func on_Tree_item_edited():
print($Tree.get_edited()) # This item just got edited (e.g. checked).
print($Tree.get_edited()) # This item just got edited (e.g. checked).
[/gdscript]
[csharp]
public override void _Ready()
{
GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited;
GetNode&lt;Tree&gt;("Tree").ItemEdited += OnTreeItemEdited;
}
public void OnTreeItemEdited()
{
GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked).
GD.Print(GetNode&lt;Tree&gt;("Tree").GetEdited()); // This item just got edited (e.g. checked).
}
[/csharp]
[/codeblocks]

View File

@@ -58,12 +58,12 @@
[gdscript]
var tween = create_tween()
for sprite in get_children():
tween.tween_property(sprite, "position", Vector2(0, 0), 1.0)
tween.tween_property(sprite, "position", Vector2(0, 0), 1.0)
[/gdscript]
[csharp]
Tween tween = CreateTween();
foreach (Node sprite in GetChildren())
tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f);
tween.TweenProperty(sprite, "position", Vector2.Zero, 1.0f);
[/csharp]
[/codeblocks]
In the example above, all children of a node are moved one after another to position (0, 0).
@@ -72,18 +72,18 @@
[gdscript]
var tween
func animate():
if tween:
tween.kill() # Abort the previous animation.
tween = create_tween()
if tween:
tween.kill() # Abort the previous animation.
tween = create_tween()
[/gdscript]
[csharp]
private Tween _tween;
public void Animate()
{
if (_tween != null)
_tween.Kill(); // Abort the previous animation
_tween = CreateTween();
if (_tween != null)
_tween.Kill(); // Abort the previous animation
_tween = CreateTween();
}
[/csharp]
[/codeblocks]
@@ -413,24 +413,24 @@
[codeblocks]
[gdscript]
func _ready():
var tween = create_tween()
tween.tween_method(set_label_text, 0, 10, 1.0).set_delay(1.0)
var tween = create_tween()
tween.tween_method(set_label_text, 0, 10, 1.0).set_delay(1.0)
func set_label_text(value: int):
$Label.text = "Counting " + str(value)
$Label.text = "Counting " + str(value)
[/gdscript]
[csharp]
public override void _Ready()
{
base._Ready();
base._Ready();
Tween tween = CreateTween();
tween.TweenMethod(Callable.From&lt;int&gt;(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f);
Tween tween = CreateTween();
tween.TweenMethod(Callable.From&lt;int&gt;(SetLabelText), 0.0f, 10.0f, 1.0f).SetDelay(1.0f);
}
private void SetLabelText(int value)
{
GetNode&lt;Label&gt;("Label").Text = $"Counting {value}";
GetNode&lt;Label&gt;("Label").Text = $"Counting {value}";
}
[/csharp]
[/codeblocks]

View File

@@ -17,22 +17,22 @@
var peers = []
func _ready():
server.listen(4242)
server.listen(4242)
func _process(delta):
server.poll() # Important!
if server.is_connection_available():
var peer = server.take_connection()
var packet = peer.get_packet()
print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()])
print("Received data: %s" % [packet.get_string_from_utf8()])
# Reply so it knows we received the message.
peer.put_packet(packet)
# Keep a reference so we can keep contacting the remote peer.
peers.append(peer)
server.poll() # Important!
if server.is_connection_available():
var peer = server.take_connection()
var packet = peer.get_packet()
print("Accepted peer: %s:%s" % [peer.get_packet_ip(), peer.get_packet_port()])
print("Received data: %s" % [packet.get_string_from_utf8()])
# Reply so it knows we received the message.
peer.put_packet(packet)
# Keep a reference so we can keep contacting the remote peer.
peers.append(peer)
for i in range(0, peers.size()):
pass # Do something with the connected peers.
for i in range(0, peers.size()):
pass # Do something with the connected peers.
[/gdscript]
[csharp]
// ServerNode.cs
@@ -41,33 +41,33 @@
public partial class ServerNode : Node
{
private UdpServer _server = new UdpServer();
private List&lt;PacketPeerUdp&gt; _peers = new List&lt;PacketPeerUdp&gt;();
private UdpServer _server = new UdpServer();
private List&lt;PacketPeerUdp&gt; _peers = new List&lt;PacketPeerUdp&gt;();
public override void _Ready()
{
_server.Listen(4242);
}
public override void _Ready()
{
_server.Listen(4242);
}
public override void _Process(double delta)
{
_server.Poll(); // Important!
if (_server.IsConnectionAvailable())
{
PacketPeerUdp peer = _server.TakeConnection();
byte[] packet = peer.GetPacket();
GD.Print($"Accepted Peer: {peer.GetPacketIP()}:{peer.GetPacketPort()}");
GD.Print($"Received Data: {packet.GetStringFromUtf8()}");
// Reply so it knows we received the message.
peer.PutPacket(packet);
// Keep a reference so we can keep contacting the remote peer.
_peers.Add(peer);
}
foreach (var peer in _peers)
{
// Do something with the peers.
}
}
public override void _Process(double delta)
{
_server.Poll(); // Important!
if (_server.IsConnectionAvailable())
{
PacketPeerUdp peer = _server.TakeConnection();
byte[] packet = peer.GetPacket();
GD.Print($"Accepted Peer: {peer.GetPacketIP()}:{peer.GetPacketPort()}");
GD.Print($"Received Data: {packet.GetStringFromUtf8()}");
// Reply so it knows we received the message.
peer.PutPacket(packet);
// Keep a reference so we can keep contacting the remote peer.
_peers.Add(peer);
}
foreach (var peer in _peers)
{
// Do something with the peers.
}
}
}
[/csharp]
[/codeblocks]
@@ -81,15 +81,15 @@
var connected = false
func _ready():
udp.connect_to_host("127.0.0.1", 4242)
udp.connect_to_host("127.0.0.1", 4242)
func _process(delta):
if !connected:
# Try to contact server
udp.put_packet("The answer is... 42!".to_utf8_buffer())
if udp.get_available_packet_count() &gt; 0:
print("Connected: %s" % udp.get_packet().get_string_from_utf8())
connected = true
if !connected:
# Try to contact server
udp.put_packet("The answer is... 42!".to_utf8_buffer())
if udp.get_available_packet_count() &gt; 0:
print("Connected: %s" % udp.get_packet().get_string_from_utf8())
connected = true
[/gdscript]
[csharp]
// ClientNode.cs
@@ -97,27 +97,27 @@
public partial class ClientNode : Node
{
private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false;
private PacketPeerUdp _udp = new PacketPeerUdp();
private bool _connected = false;
public override void _Ready()
{
_udp.ConnectToHost("127.0.0.1", 4242);
}
public override void _Ready()
{
_udp.ConnectToHost("127.0.0.1", 4242);
}
public override void _Process(double delta)
{
if (!_connected)
{
// Try to contact server
_udp.PutPacket("The Answer Is..42!".ToUtf8Buffer());
}
if (_udp.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Connected: {_udp.GetPacket().GetStringFromUtf8()}");
_connected = true;
}
}
public override void _Process(double delta)
{
if (!_connected)
{
// Try to contact server
_udp.PutPacket("The Answer Is..42!".ToUtf8Buffer());
}
if (_udp.GetAvailablePacketCount() &gt; 0)
{
GD.Print($"Connected: {_udp.GetPacket().GetStringFromUtf8()}");
_connected = true;
}
}
}
[/csharp]
[/codeblocks]

View File

@@ -12,47 +12,47 @@
var undo_redo = UndoRedo.new()
func do_something():
pass # Put your code here.
pass # Put your code here.
func undo_something():
pass # Put here the code that reverts what's done by "do_something()".
pass # Put here the code that reverts what's done by "do_something()".
func _on_my_button_pressed():
var node = get_node("MyNode2D")
undo_redo.create_action("Move the node")
undo_redo.add_do_method(do_something)
undo_redo.add_undo_method(undo_something)
undo_redo.add_do_property(node, "position", Vector2(100,100))
undo_redo.add_undo_property(node, "position", node.position)
undo_redo.commit_action()
var node = get_node("MyNode2D")
undo_redo.create_action("Move the node")
undo_redo.add_do_method(do_something)
undo_redo.add_undo_method(undo_something)
undo_redo.add_do_property(node, "position", Vector2(100,100))
undo_redo.add_undo_property(node, "position", node.position)
undo_redo.commit_action()
[/gdscript]
[csharp]
private UndoRedo _undoRedo;
public override void _Ready()
{
_undoRedo = new UndoRedo();
_undoRedo = new UndoRedo();
}
public void DoSomething()
{
// Put your code here.
// Put your code here.
}
public void UndoSomething()
{
// Put here the code that reverts what's done by "DoSomething()".
// Put here the code that reverts what's done by "DoSomething()".
}
private void OnMyButtonPressed()
{
var node = GetNode&lt;Node2D&gt;("MyNode2D");
_undoRedo.CreateAction("Move the node");
_undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething));
_undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething));
_undoRedo.AddDoProperty(node, "position", new Vector2(100, 100));
_undoRedo.AddUndoProperty(node, "position", node.Position);
_undoRedo.CommitAction();
var node = GetNode&lt;Node2D&gt;("MyNode2D");
_undoRedo.CreateAction("Move the node");
_undoRedo.AddDoMethod(new Callable(this, MethodName.DoSomething));
_undoRedo.AddUndoMethod(new Callable(this, MethodName.UndoSomething));
_undoRedo.AddDoProperty(node, "position", new Vector2(100, 100));
_undoRedo.AddUndoProperty(node, "position", node.Position);
_undoRedo.CommitAction();
}
[/csharp]
[/codeblocks]

View File

@@ -34,32 +34,32 @@
[gdscript]
var foo = 2
match typeof(foo):
TYPE_NIL:
print("foo is null")
TYPE_INT:
print("foo is an integer")
TYPE_OBJECT:
# Note that Objects are their own special category.
# To get the name of the underlying Object type, you need the `get_class()` method.
print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string.
# Note that this does not get the script's `class_name` global identifier.
# If the `class_name` is needed, use `foo.get_script().get_global_name()` instead.
TYPE_NIL:
print("foo is null")
TYPE_INT:
print("foo is an integer")
TYPE_OBJECT:
# Note that Objects are their own special category.
# To get the name of the underlying Object type, you need the `get_class()` method.
print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string.
# Note that this does not get the script's `class_name` global identifier.
# If the `class_name` is needed, use `foo.get_script().get_global_name()` instead.
[/gdscript]
[csharp]
Variant foo = 2;
switch (foo.VariantType)
{
case Variant.Type.Nil:
GD.Print("foo is null");
break;
case Variant.Type.Int:
GD.Print("foo is an integer");
break;
case Variant.Type.Object:
// Note that Objects are their own special category.
// You can convert a Variant to a GodotObject and use reflection to get its name.
GD.Print($"foo is a(n) {foo.AsGodotObject().GetType().Name}");
break;
case Variant.Type.Nil:
GD.Print("foo is null");
break;
case Variant.Type.Int:
GD.Print("foo is an integer");
break;
case Variant.Type.Object:
// Note that Objects are their own special category.
// You can convert a Variant to a GodotObject and use reflection to get its name.
GD.Print($"foo is a(n) {foo.AsGodotObject().GetType().Name}");
break;
}
[/csharp]
[/codeblocks]

Some files were not shown because too many files have changed in this diff Show More