Update some C# examples for 4.0 (#6693)

* Update some C# examples

- Rename members that have been renamed in Godot's C# API for 4.0.
- Change `delta` parameter type to `double`.
- Ensure parameters match base declaration.
- Other minor code fixes.

---------

Co-authored-by: Paul Joannon <437025+paulloz@users.noreply.github.com>
This commit is contained in:
Raul Santos
2023-02-04 17:03:03 +01:00
committed by GitHub
parent d6b4fe8ab9
commit b319da3f07
30 changed files with 236 additions and 219 deletions

View File

@@ -104,7 +104,9 @@ way:
.. code-tab:: csharp
var localPos = new Vector2(10,20); // local to Control/Node2D
var ie = new InputEventMouseButton();
ie.ButtonIndex = (int)ButtonList.Left;
ie.Position = (GetViewportTransform() * GetGlobalTransform()).Xform(localPos);
var ie = new InputEventMouseButton()
{
ButtonIndex = MouseButton.Left,
Position = GetViewportTransform() * (GetGlobalTransform() * localPos),
};
GetTree().InputEvent(ie);

View File

@@ -84,7 +84,7 @@ redrawn if modified:
using Godot;
public partial class CustomNode2D : Node2D
public partial class MyNode2D : Node2D
{
private Texture _texture;
public Texture Texture
@@ -133,7 +133,7 @@ call ``queue_redraw()`` from the ``_process()`` callback, like this:
// Your draw commands here
}
public override void _Process(float delta)
public override void _Process(double delta)
{
QueueRedraw();
}
@@ -387,7 +387,7 @@ using ``get_node()``.
using Godot;
public partial class CustomNode2D : Node2D
public partial class MyNode2D : Node2D
{
private float _rotationAngle = 50;
private float _angleFrom = 75;
@@ -421,7 +421,7 @@ calls ``_draw()``. This way, you can control when you want to refresh the frame.
.. code-tab:: csharp
public override void _Process(float delta)
public override void _Process(double delta)
{
_angleFrom += _rotationAngle;
_angleTo += _rotationAngle;
@@ -490,10 +490,10 @@ smaller value, which directly depends on the rendering speed.
.. code-tab:: csharp
public override void _Process(float delta)
public override void _Process(double delta)
{
_angleFrom += _rotationAngle * delta;
_angleTo += _rotationAngle * delta;
_angleFrom += _rotationAngle * (float)delta;
_angleTo += _rotationAngle * (float)delta;
// We only wrap angles when both of them are bigger than 360.
if (_angleFrom > 360 && _angleTo > 360)

View File

@@ -112,9 +112,9 @@ A default basis (unmodified) is akin to:
// Instead we can use the Identity property.
var identityBasis = Basis.Identity;
GD.Print(identityBasis.x); // prints: (1, 0, 0)
GD.Print(identityBasis.y); // prints: (0, 1, 0)
GD.Print(identityBasis.z); // prints: (0, 0, 1)
GD.Print(identityBasis.X); // prints: (1, 0, 0)
GD.Print(identityBasis.Y); // prints: (0, 1, 0)
GD.Print(identityBasis.Z); // prints: (0, 0, 1)
// The Identity basis is equivalent to:
var basis = new Basis(Vector3.Right, Vector3.Up, Vector3.Back);
@@ -161,9 +161,9 @@ It is possible to rotate a transform, either by multiplying its basis by another
Vector3 axis = new Vector3(1, 0, 0); // Or Vector3.Right
float rotationAmount = 0.1f;
// Rotate the transform around the X axis by 0.1 radians.
transform.basis = new Basis(axis, rotationAmount) * transform.basis;
transform.Basis = new Basis(axis, rotationAmount) * transform.Basis;
// shortened
transform.basis = transform.basis.Rotated(axis, rotationAmount);
transform.Basis = transform.Basis.Rotated(axis, rotationAmount);
A method in Node3D simplifies this:
@@ -246,7 +246,7 @@ Imagine you need to shoot a bullet in the direction your player is facing. Just
.. code-tab:: csharp
bullet.Transform = transform;
bullet.LinearVelocity = transform.basis.z * BulletSpeed;
bullet.LinearVelocity = transform.Basis.Z * BulletSpeed;
Is the enemy looking at the player? Use the dot product for this (see the :ref:`doc_vector_math` tutorial for an explanation of the dot product):
@@ -261,8 +261,8 @@ Is the enemy looking at the player? Use the dot product for this (see the :ref:`
.. code-tab:: csharp
// Get the direction vector from player to enemy
Vector3 direction = enemy.Transform.origin - player.Transform.origin;
if (direction.Dot(enemy.Transform.basis.z) > 0)
Vector3 direction = enemy.Transform.Origin - player.Transform.Origin;
if (direction.Dot(enemy.Transform.Basis.Z) > 0)
{
enemy.ImWatchingYou(player);
}
@@ -281,7 +281,7 @@ Strafe left:
// Remember that +X is right
if (Input.IsActionPressed("strafe_left"))
{
TranslateObjectLocal(-Transform.basis.x);
TranslateObjectLocal(-Transform.Basis.X);
}
Jump:
@@ -299,7 +299,7 @@ Jump:
// Keep in mind Y is up-axis
if (Input.IsActionJustPressed("jump"))
velocity.y = JumpSpeed;
velocity.Y = JumpSpeed;
velocity = MoveAndSlide(velocity);
@@ -341,12 +341,12 @@ Example of looking around, FPS style:
if (@event is InputEventMouseMotion mouseMotion)
{
// modify accumulated mouse rotation
_rotationX += mouseMotion.Relative.x * LookAroundSpeed;
_rotationY += mouseMotion.Relative.y * LookAroundSpeed;
_rotationX += mouseMotion.Relative.X * LookAroundSpeed;
_rotationY += mouseMotion.Relative.Y * LookAroundSpeed;
// reset rotation
Transform3D transform = Transform;
transform.basis = Basis.Identity;
transform.Basis = Basis.Identity;
Transform = transform;
RotateObjectLocal(Vector3.Up, _rotationX); // first rotate about Y
@@ -377,12 +377,12 @@ Converting a rotation to quaternion is straightforward.
.. code-tab:: csharp
// Convert basis to quaternion, keep in mind scale is lost
var a = transform.basis.Quaternion();
var b = transform2.basis.Quaternion();
var a = transform.Basis.GetQuaternion();
var b = transform2.Basis.GetQuaternion();
// Interpolate using spherical-linear interpolation (SLERP).
var c = a.Slerp(b, 0.5f); // find halfway point between a and b
// Apply back
transform.basis = new Basis(c);
transform.Basis = new Basis(c);
The :ref:`class_Quaternion` type reference has more information on the datatype (it
can also do transform accumulation, transform points, etc., though this is used

View File

@@ -249,28 +249,25 @@ tree structures.
.. code-tab:: csharp
using Godot;
using System.Collections.Generic;
// Can decide whether to expose getters/setters for properties later
public partial class TreeNode : Object
public partial class TreeNode : GodotObject
{
private TreeNode _parent = null;
private object[] _children = new object[0];
private List<TreeNode> _children = new();
public override void Notification(int what)
public override void _Notification(int what)
{
switch (what)
{
case NotificationPredelete:
foreach (object child in _children)
foreach (TreeNode child in _children)
{
TreeNode node = child as TreeNode;
if (node != null)
node.Free();
node.Free();
}
break;
default:
break;
}
}
}

View File

@@ -26,8 +26,8 @@ is to get a reference to an existing object from another acquired instance.
.. code-tab:: csharp
Object obj = node.Object; // Property access.
Object obj = node.GetObject(); // Method access.
GodotObject obj = node.Object; // Property access.
GodotObject obj = node.GetObject(); // Method access.
The same principle applies for :ref:`RefCounted <class_RefCounted>` objects.
While users often access :ref:`Node <class_Node>` and
@@ -181,31 +181,35 @@ Nodes likewise have an alternative access point: the SceneTree.
.. code-tab:: csharp
public class MyNode
using Godot;
using System;
using System.Diagnostics;
public class MyNode : Node
{
// Slow
public void DynamicLookupWithDynamicNodePath()
{
GD.Print(GetNode(NodePath("Child")));
GD.Print(GetNode("Child"));
}
// Fastest. Lookup node and cache for future access.
// Doesn't break if node moves later.
public Node Child;
private Node _child;
public void _Ready()
{
Child = GetNode(NodePath("Child"));
_child = GetNode("Child");
}
public void LookupAndCacheForFutureAccess()
{
GD.Print(Child);
GD.Print(_child);
}
// Delegate reference assignment to an external source.
// Con: need to perform a validation check.
// Pro: node makes no requirements of its external structure.
// 'prop' can come from anywhere.
public object Prop;
public object Prop { get; set; }
public void CallMeAfterPropIsInitializedByParent()
{
// Validate prop in one of three ways.
@@ -223,7 +227,15 @@ Nodes likewise have an alternative access point: the SceneTree.
return;
}
// Fail with an exception.
if (prop == null)
{
throw new InvalidOperationException("'Prop' wasn't initialized.");
}
// Fail and terminate.
// Note: Scripts run from a release export template don't
// run `Debug.Assert` statements.
Debug.Assert(Prop, "'Prop' wasn't initialized");
}
@@ -232,10 +244,10 @@ Nodes likewise have an alternative access point: the SceneTree.
// that manage their own data and don't interfere with other objects.
public void ReferenceAGlobalAutoloadedVariable()
{
Node globals = GetNode(NodePath("/root/Globals"));
MyNode globals = GetNode<MyNode>("/root/Globals");
GD.Print(globals);
GD.Print(globals.prop);
GD.Print(globals.my_getter());
GD.Print(globals.Prop);
GD.Print(globals.MyGetter());
}
};

View File

@@ -119,7 +119,7 @@ deltatime methods as needed.
{
// Called every frame, even when the engine detects no input.
public void _Process(float delta)
public void _Process(double delta)
{
if (Input.IsActionJustPressed("ui_select"))
GD.Print(delta);
@@ -130,12 +130,10 @@ deltatime methods as needed.
{
switch (event)
{
case InputEventKey keyEvent:
case InputEventKey:
if (Input.IsActionJustPressed("ui_accept"))
GD.Print(GetProcessDeltaTime());
break;
default:
break;
}
}
@@ -187,7 +185,7 @@ instantiation:
set
{
_test = value;
GD.Print("Setting: " + _test);
GD.Print($"Setting: {_test}");
}
}

View File

@@ -82,7 +82,7 @@ program termination, you should send the notification yourself:
.. code-tab:: csharp
GetTree().Root.PropagateNotification((int)NotificationWmCloseRequest)
GetTree().Root.PropagateNotification((int)NotificationWmCloseRequest);
Sending this notification will inform all nodes about the program termination,
but will not terminate the program itself *unlike in 3.X*. In order to achieve

View File

@@ -43,20 +43,20 @@ Examples:
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent.IsActionPressed("jump"))
if (@event.IsActionPressed("jump"))
{
Jump();
}
}
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
if (Input.IsActionPressed("move_right"))
{
// Move as long as the key/button is pressed.
position.x += speed * delta;
position.X += speed * (float)delta;
}
}
@@ -89,9 +89,9 @@ attach the following script:
public partial class Node : Godot.Node
{
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
GD.Print(inputEvent.AsText());
GD.Print(@event.AsText());
}
}
@@ -136,9 +136,9 @@ avoid this, make sure to test the event type first:
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent is InputEventMouseButton mouseEvent)
if (@event is InputEventMouseButton mouseEvent)
{
GD.Print("mouse button event at ", mouseEvent.Position);
}
@@ -172,9 +172,9 @@ the action you're looking for:
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent.IsActionPressed("my_action"))
if (@event.IsActionPressed("my_action"))
{
GD.Print("my_action occurred!");
}
@@ -198,11 +198,11 @@ the :kbd:`T`:
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent is InputEventKey keyEvent && keyEvent.Pressed)
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
if ((KeyList)keyEvent.Keycode == KeyList.T)
if (keyEvent.Keycode == Key.T)
{
GD.Print("T was pressed");
}
@@ -247,13 +247,13 @@ different when it's :kbd:`Shift + T`:
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent is InputEventKey keyEvent && keyEvent.Pressed)
if (@event is InputEventKey keyEvent && keyEvent.Pressed)
{
switch ((KeyList)keyEvent.Keycode)
switch (keyEvent.Keycode)
{
case KeyList.T:
case Key.T:
GD.Print(keyEvent.Shift ? "Shift+T was pressed" : "T was pressed");
break;
}
@@ -292,9 +292,9 @@ also counts as a button - two buttons, to be precise, with both
.. code-tab:: csharp
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
if (inputEvent is InputEventMouseButton mouseEvent && mouseEvent.Pressed)
if (@event is InputEventMouseButton mouseEvent && mouseEvent.Pressed)
{
switch (mouseEvent.ButtonIndex)
{
@@ -346,12 +346,12 @@ node:
using Godot;
public partial class Node2D : Godot.Node2D
public partial class MyNode2D : Node2D
{
private bool dragging = false;
private int clickRadius = 32; // Size of the sprite.
private bool _dragging = false;
private int _clickRadius = 32; // Size of the sprite.
public override void _Input(InputEvent inputEvent)
public override void _Input(InputEvent @event)
{
Sprite2D sprite = GetNodeOrNull<Sprite2D>("Sprite2D");
if (sprite == null)
@@ -359,25 +359,25 @@ node:
return; // No suitable node was found.
}
if (inputEvent is InputEventMouseButton mouseEvent && (ButtonList)mouseEvent.ButtonIndex == ButtonList.Left)
if (@event is InputEventMouseButton mouseEvent && mouseEvent.ButtonIndex == MouseButton.Left)
{
if ((mouseEvent.Position - sprite.Position).Length() < clickRadius)
if ((mouseEvent.Position - sprite.Position).Length() < _clickRadius)
{
// Start dragging if the click is on the sprite.
if (!dragging && mouseEvent.Pressed)
if (!_dragging && mouseEvent.Pressed)
{
dragging = true;
_dragging = true;
}
}
// Stop dragging if the button is released.
if (dragging && !mouseEvent.Pressed)
if (_dragging && !mouseEvent.Pressed)
{
dragging = false;
_dragging = false;
}
}
else
{
if (inputEvent is InputEventMouseMotion motionEvent && dragging)
if (@event is InputEventMouseMotion motionEvent && _dragging)
{
// While dragging, move the sprite with the mouse.
sprite.Position = motionEvent.Position;

View File

@@ -27,7 +27,7 @@ Here is a quick example, closing your game if the escape key is hit:
public override void _UnhandledInput(InputEvent @event)
{
if (@event is InputEventKey eventKey)
if (eventKey.Pressed && eventKey.Keycode == (int)KeyList.Escape)
if (eventKey.Pressed && eventKey.Keycode == Key.Escape)
GetTree().Quit();
}
@@ -48,7 +48,7 @@ You can set up your InputMap under **Project > Project Settings > Input Map** an
.. code-tab:: csharp
public override void _Process(float delta)
public override void _Process(double delta)
{
if (Input.IsActionPressed("ui_right"))
{

View File

@@ -94,8 +94,8 @@ The save function will look like this:
{
{ "Filename", SceneFilePath },
{ "Parent", GetParent().GetPath() },
{ "PosX", Position.x }, // Vector2 is not supported by JSON
{ "PosY", Position.y },
{ "PosX", Position.X }, // Vector2 is not supported by JSON
{ "PosY", Position.Y },
{ "Attack", Attack },
{ "Defense", Defense },
{ "CurrentHealth", CurrentHealth },
@@ -152,7 +152,7 @@ way to pull the data out of the file as well.
# Call the node's save function.
var node_data = node.call("save")
# JSON provides a static method to serialized JSON string
# JSON provides a static method to serialized JSON string.
var json_string = JSON.stringify(node_data)
# Store the save dictionary as a new line in the save file.
@@ -188,8 +188,8 @@ way to pull the data out of the file as well.
// Call the node's save function.
var nodeData = saveNode.Call("Save");
// JSON provides a static method to serialized JSON string
var jsonString = JSON.Stringify(nodeData);
// Json provides a static method to serialized JSON string.
var jsonString = Json.Stringify(nodeData);
// Store the save dictionary as a new line in the save file.
saveGame.StoreLine(jsonString);
@@ -257,7 +257,9 @@ load function:
public void LoadGame()
{
if (!FileAccess.FileExists("user://savegame.save"))
{
return; // Error! We don't have a save to load.
}
// We need to revert the game state so we're not cloning objects during loading.
// This will vary wildly depending on the needs of a project, so take care with
@@ -265,7 +267,9 @@ load function:
// For our example, we will accomplish this by deleting saveable objects.
var saveNodes = GetTree().GetNodesInGroup("Persist");
foreach (Node saveNode in saveNodes)
{
saveNode.QueueFree();
}
// Load the file line by line and process that dictionary to restore the object
// it represents.
@@ -276,7 +280,7 @@ load function:
var jsonString = saveGame.GetLine();
// Creates the helper class to interact with JSON
var json = new JSON();
var json = new Json();
var parseResult = json.Parse(jsonString);
if (parseResult != Error.Ok)
{
@@ -288,18 +292,19 @@ load function:
var nodeData = new Godot.Collections.Dictionary<string, Variant>((Godot.Collections.Dictionary)json.Data);
// Firstly, we need to create the object and add it to the tree and set its position.
var newObjectScene = (PackedScene)ResourceLoader.Load(nodeData["Filename"].ToString());
var newObject = (Node)newObjectScene.Instantiate();
var newObjectScene = GD.Load<PackedScene>(nodeData["Filename"].ToString());
var newObject = newObjectScene.Instantiate<Node>();
GetNode(nodeData["Parent"].ToString()).AddChild(newObject);
newObject.Set("position", new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
newObject.Set(Node2D.PropertyName.Position, new Vector2((float)nodeData["PosX"], (float)nodeData["PosY"]));
// Now we set the remaining variables.
foreach (KeyValuePair<string, Variant> entry in nodeData)
foreach (var (key, value) in nodeData)
{
string key = entry.Key;
if (key == "Filename" || key == "Parent" || key == "PosX" || key == "PosY")
{
continue;
newObject.Set(key, entry.Value);
}
newObject.Set(key, value);
}
}
}

View File

@@ -219,9 +219,9 @@ Let's do an example with the following pseudocode:
private float _t = 0.0f;
public override void _Process(float delta)
public override void _Process(double delta)
{
_t += delta;
_t += (float)delta;
Position = CubicBezier(p0, p1, p2, p3, _t);
}
@@ -268,9 +268,9 @@ Traversal at constant speed, then, can be done with the following pseudo-code:
private float _t = 0.0f;
public override void _Process(float delta)
public override void _Process(double delta)
{
_t += delta;
_t += (float)delta;
Position = curve.InterpolateBaked(_t * curve.GetBakedLength(), true);
}

View File

@@ -49,9 +49,9 @@ Here is example pseudo-code for going from point A to B using interpolation:
private float _t = 0.0f;
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
_t += delta * 0.4f;
_t += (float)delta * 0.4f;
Marker2D a = GetNode<Marker2D>("A");
Marker2D b = GetNode<Marker2D>("B");
@@ -90,9 +90,9 @@ Using the following pseudocode:
private float _t = 0.0f;
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
_t += delta;
_t += (float)delta;
Marker3D p1 = GetNode<Marker3D>("Position1");
Marker3D p2 = GetNode<Marker3D>("Position2");
@@ -125,13 +125,13 @@ Interpolation can be used to smooth movement, rotation, etc. Here is an example
private const float FollowSpeed = 4.0f;
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
Vector2 mousePos = GetLocalMousePosition();
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
sprite.Position = sprite.Position.Lerp(mousePos, delta * FollowSpeed);
sprite.Position = sprite.Position.Lerp(mousePos, (float)delta * FollowSpeed);
}
Here is how it looks:

View File

@@ -170,9 +170,9 @@ Here's how that would be done in code (place the script on a Node2D):
float rot = 0.5f; // The rotation to apply.
Transform2D t = Transform2D.Identity;
t.x.x = t.y.y = Mathf.Cos(rot);
t.x.y = t.y.x = Mathf.Sin(rot);
t.y.x *= -1;
t.X.X = t.Y.Y = Mathf.Cos(rot);
t.X.Y = t.Y.X = Mathf.Sin(rot);
t.Y.X *= -1;
Transform = t; // Change the node's transform to what we calculated.
To calculate the object's rotation from an existing transformation
@@ -265,15 +265,15 @@ you to try and reproduce the screenshot without looking at the code!
Transform2D t = Transform2D.Identity;
// Translation
t.origin = new Vector2(350, 150);
t.Origin = new Vector2(350, 150);
// Rotation
float rot = -0.5f; // The rotation to apply.
t.x.x = t.y.y = Mathf.Cos(rot);
t.x.y = t.y.x = Mathf.Sin(rot);
t.y.x *= -1;
t.X.X = t.Y.Y = Mathf.Cos(rot);
t.X.Y = t.Y.X = Mathf.Sin(rot);
t.Y.X *= -1;
// Scale
t.x *= 3;
t.y *= 3;
t.X *= 3;
t.Y *= 3;
Transform = t; // Change the node's transform to what we calculated.
Shearing the transformation matrix (advanced)
@@ -435,7 +435,7 @@ This code moves an object 100 units to its own right:
.. code-tab:: csharp
Transform2D t = Transform;
t.origin += t.x * 100;
t.Origin += t.X * 100;
Transform = t;
For moving in 3D, you would need to replace "x" with "basis.x".
@@ -500,11 +500,11 @@ the code we would use:
// Calculate the child's world space transform
// origin = (2, 0) * 100 + (0, 1) * 100 + (100, 200)
Vector2 origin = parent.x * child.origin.x + parent.y * child.origin.y + parent.origin;
Vector2 origin = parent.X * child.Origin.X + parent.Y * child.Origin.Y + parent.Origin;
// basisX = (2, 0) * 0.5 + (0, 1) * 0 = (0.5, 0)
Vector2 basisX = parent.x * child.x.x + parent.y * child.x.y;
Vector2 basisX = parent.X * child.X.X + parent.Y * child.X.Y;
// basisY = (2, 0) * 0 + (0, 1) * 0.5 = (0.5, 0)
Vector2 basisY = parent.x * child.y.x + parent.y * child.y.y;
Vector2 basisY = parent.X * child.Y.X + parent.Y * child.Y.Y;
// Change the node's transform to what we calculated.
Transform = new Transform2D(basisX, basisY, origin);

View File

@@ -468,6 +468,6 @@ terrain. Godot provides :ref:`class_fastnoiselite` for this, which supports
for (int i = 0; i < 100; i++)
{
GD.Print(_noise.GetNoise1d(i));
GD.Print(_noise.GetNoise1D(i));
}
}

View File

@@ -97,8 +97,8 @@ The individual components of the vector can be accessed directly by name.
var a = new Vector2(2, 5);
// create a vector and assign x and y manually
var b = new Vector2();
b.x = 3;
b.y = 1;
b.X = 3;
b.Y = 1;
Adding vectors
--------------
@@ -345,9 +345,9 @@ The cross product is calculated like this:
.. code-tab:: csharp
var c = new Vector3();
c.x = (a.y * b.z) - (a.z * b.y);
c.y = (a.z * b.x) - (a.x * b.z);
c.z = (a.x * b.y) - (a.y * b.x);
c.X = (a.Y * b.Z) - (a.Z * b.Y);
c.Y = (a.Z * b.X) - (a.X * b.Z);
c.Z = (a.X * b.Y) - (a.Y * b.X);

View File

@@ -178,7 +178,7 @@ NavigationServer2D and a NavigationAgent2D for path movement.
return;
}
Vector2 currentAgentPosition = GlobalTransform.origin;
Vector2 currentAgentPosition = GlobalTransform.Origin;
Vector2 nextPathPosition = _navigationAgent.GetNextLocation();
Vector2 newVelocity = (nextPathPosition - currentAgentPosition).Normalized();

View File

@@ -185,7 +185,7 @@ a NavigationAgent3D for path movement.
return;
}
Vector3 currentAgentPosition = GlobalTransform.origin;
Vector3 currentAgentPosition = GlobalTransform.Origin;
Vector3 nextPathPosition = _navigationAgent.GetNextLocation();
Vector3 newVelocity = (nextPathPosition - currentAgentPosition).Normalized();

View File

@@ -51,7 +51,7 @@ Below is all the code we need to make it work. The URL points to an online API m
using Godot;
public partial class HTTPRequestDemo : CanvasLayer
public partial class MyCanvasLayer : CanvasLayer
{
public override void _Ready()
{
@@ -59,15 +59,15 @@ Below is all the code we need to make it work. The URL points to an online API m
GetNode("Button").Pressed += OnButtonPressed;
}
public void OnButtonPressed()
private void OnButtonPressed()
{
HTTPRequest httpRequest = GetNode<HTTPRequest>("HTTPRequest");
HttpRequest httpRequest = GetNode<HttpRequest>("HTTPRequest");
httpRequest.Request("http://www.mocky.io/v2/5185415ba171ea3a00704eed");
}
public void OnRequestCompleted(int result, int response_code, string[] headers, byte[] body)
private void OnRequestCompleted(long result, long responseCode, string[] headers, byte[] body)
{
JSONParseResult json = JSON.Parse(Encoding.UTF8.GetString(body));
JsonParseResult json = Json.Parse(Encoding.UTF8.GetString(body));
GD.Print(json.Result);
}
}
@@ -89,7 +89,7 @@ For example, to set a custom user agent (the HTTP ``user-agent`` header) you cou
.. code-tab:: csharp
HTTPRequest httpRequest = GetNode<HTTPRequest>("HTTPRequest");
HttpRequest httpRequest = GetNode<HttpRequest>("HTTPRequest");
httpRequest.Request("http://www.mocky.io/v2/5185415ba171ea3a00704eed", new string[] { "user-agent: YourCustomUserAgent" });
Please note that, for SSL/TLS encryption and thus HTTPS URLs to work, you may need to take some steps as described :ref:`here <doc_ssl_certificates>`.
@@ -108,20 +108,22 @@ Until now, we have limited ourselves to requesting data from a server. But what
func _make_post_request(url, data_to_send, use_ssl):
# Convert data to json string:
var query = JSON.print(data_to_send)
var query = JSON.stringify(data_to_send)
# Add 'Content-Type' header:
var headers = ["Content-Type: application/json"]
$HTTPRequest.request(url, headers, use_ssl, HTTPClient.METHOD_POST, query)
.. code-tab:: csharp
public void MakePostRequest(string url, object data_to_send, bool use_ssl)
{
string query = JSON.Print(data_to_send);
HTTPRequest httpRequest = GetNode<HTTPRequest>("HTTPRequest");
string[] headers = new string[] { "Content-Type: application/json" };
httpRequest.Request(url, headers, use_ssl, HTTPClient.Method.Post, query);
}
public void MakePostRequest(string url, Variant dataToSend, bool useSsl)
{
// Convert data to json string:
string query = Json.Stringify(dataToSend);
// Add 'Content-Type' header:
string[] headers = new string[] { "Content-Type: application/json" };
HttpRequest httpRequest = GetNode<HttpRequest>("HTTPRequest");
httpRequest.Request(url, headers, useSsl, HttpClient.Method.Post, query);
}
Keep in mind that you have to wait for a request to finish before sending another one. Making multiple request at once requires you to have one node per request.
A common strategy is to create and delete HTTPRequest nodes at runtime as necessary.

View File

@@ -76,14 +76,14 @@ efficient for millions of objects, but for a few thousands, GDScript should be f
using Godot;
public partial class YourClassName : MultiMeshInstance3D
public partial class MyMultiMeshInstance3D : MultiMeshInstance3D
{
public override void _Ready()
{
// Create the multimesh.
Multimesh = new MultiMesh();
// Set the format first.
Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3d;
Multimesh.TransformFormat = MultiMesh.TransformFormatEnum.Transform3D;
Multimesh.ColorFormat = MultiMesh.ColorFormatEnum.None;
Multimesh.CustomDataFormat = MultiMesh.CustomDataFormatEnum.None;
// Then resize (otherwise, changing the format is not allowed)

View File

@@ -60,9 +60,9 @@ Use the following code in 2D:
.. code-tab:: csharp
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceRid = GetWorld2d().Space;
var spaceRid = GetWorld2D().Space;
var spaceState = Physics2DServer.SpaceGetDirectState(spaceRid);
}
@@ -76,9 +76,9 @@ Or more directly:
.. code-tab:: csharp
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld2d().DirectSpaceState;
var spaceState = GetWorld2D().DirectSpaceState;
}
And in 3D:
@@ -91,9 +91,9 @@ And in 3D:
.. code-tab:: csharp
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld3d().DirectSpaceState;
var spaceState = GetWorld3D().DirectSpaceState;
}
Raycast query
@@ -114,11 +114,11 @@ may be used. For example:
.. code-tab:: csharp
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld2d().DirectSpaceState;
var spaceState = GetWorld2D().DirectSpaceState;
// use global coordinates, not local to node
var query = PhysicsRayQueryParameters2D.create(new Vector2(), new Vector2(50, 100));
var query = PhysicsRayQueryParameters2D.Create(Vector2.Zero, new Vector2(50, 100));
var result = spaceState.IntersectRay(query);
}
@@ -182,13 +182,13 @@ from a CharacterBody2D or any other collision object node:
using Godot;
public partial class Body : CharacterBody2D
public partial class MyCharacterBody2D : CharacterBody2D
{
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld2d().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.create(globalPosition, enemyPosition);
query.Exclude = new Godot.Collections.Array { this };
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(globalPosition, enemyPosition);
query.Exclude = new Godot.Collections.Array<Rid> { GetRid() };
var result = spaceState.IntersectRay(query);
}
}
@@ -221,13 +221,13 @@ member variable. The array of exceptions can be supplied as the last argument as
using Godot;
public partial class Body : CharacterBody2D
public partial class MyCharacterBody2D : CharacterBody2D
{
public override void _PhysicsProcess(float delta)
public override void _PhysicsProcess(double delta)
{
var spaceState = GetWorld2d().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.create(globalPosition, enemyPosition,
CollisionMask, new Godot.Collections.Array { this });
var spaceState = GetWorld2D().DirectSpaceState;
var query = PhysicsRayQueryParameters2D.Create(globalPosition, enemyPosition,
CollisionMask, new Godot.Collections.Array<Rid> { GetRid() });
var result = spaceState.IntersectRay(query);
}
}
@@ -270,11 +270,11 @@ To obtain it using a camera, the following code can be used:
public override void _Input(InputEvent @event)
{
if (@event is InputEventMouseButton eventMouseButton && eventMouseButton.Pressed && eventMouseButton.ButtonIndex == 1)
if (@event is InputEventMouseButton eventMouseButton && eventMouseButton.Pressed && eventMouseButton.ButtonIndex == MouseButton.Left)
{
var camera3d = GetNode<Camera3D>("Camera3D");
var from = camera3d.ProjectRayOrigin(eventMouseButton.Position);
var to = from + camera3d.ProjectRayNormal(eventMouseButton.Position) * RayLength;
var camera3D = GetNode<Camera3D>("Camera3D");
var from = camera3D.ProjectRayOrigin(eventMouseButton.Position);
var to = from + camera3D.ProjectRayNormal(eventMouseButton.Position) * RayLength;
}
}

View File

@@ -52,21 +52,21 @@ Here is a custom ``look_at()`` method that will work reliably with rigid bodies:
using Godot;
public partial class Body : RigidBody3D
public partial class MyRigidBody3D : RigidBody3D
{
private void LookFollow(PhysicsDirectBodyState state, Transform3D currentTransform, Vector3 targetPosition)
{
var upDir = new Vector3(0, 1, 0);
var curDir = currentTransform.basis.Xform(new Vector3(0, 0, 1));
var targetDir = (targetPosition - currentTransform.origin).Normalized();
var rotationAngle = Mathf.Acos(curDir.x) - Mathf.Acos(targetDir.x);
var curDir = currentTransform.Basis * new Vector3(0, 0, 1);
var targetDir = (targetPosition - currentTransform.Origin).Normalized();
var rotationAngle = Mathf.Acos(curDir.X) - Mathf.Acos(targetDir.X);
state.SetAngularVelocity(upDir * (rotationAngle / state.GetStep()));
}
public override void _IntegrateForces(PhysicsDirectBodyState state)
{
var targetPosition = GetNode<Node3D>("my_target_node3d_node").GetGlobalTransform().origin;
var targetPosition = GetNode<Node3D>("MyTargetNode3DNode").GetGlobalTransform().Origin;
LookFollow(state, GetGlobalTransform(), targetPosition);
}
}

View File

@@ -507,15 +507,15 @@ Here's the code for the player body:
Vector2 velocity = Velocity;
// Add the gravity.
velocity.y += Gravity * (float)delta;
velocity.Y += Gravity * (float)delta;
// Handle jump.
if (Input.IsActionJustPressed("jump") && IsOnFloor())
velocity.y = JumpSpeed;
velocity.Y = JumpSpeed;
// Get the input direction.
Vector2 direction = Input.GetAxis("ui_left", "ui_right");
velocity.x = direction * Speed;
velocity.X = direction * Speed;
Velocity = velocity;
MoveAndSlide();

View File

@@ -143,13 +143,13 @@ specifically add :ref:`class_EditorProperty`-based controls.
public partial class MyInspectorPlugin : EditorInspectorPlugin
{
public override bool CanHandle(Object @object)
public override bool _CanHandle(Variant @object)
{
// We support all objects in this example.
return true;
}
public override bool ParseProperty(Object @object, int type, string path, int hint, string hintText, int usage)
public override bool _ParseProperty(GodotObject @object, int type, string name, int hintType, string hintString, int usageFlags, bool wide)
{
// We handle properties of type integer.
if (type == (int)Variant.Type.Int)

View File

@@ -90,7 +90,7 @@ Here is how a ``_process()`` function might look for you:
.. code-tab:: csharp
public override void _Process(float delta)
public override void _Process(double delta)
{
if (Engine.IsEditorHint())
{
@@ -133,9 +133,9 @@ and open a script, and change it to this:
[Tool]
public partial class MySprite : Sprite2D
{
public override void _Process(float delta)
public override void _Process(double delta)
{
Rotation += Mathf.Pi * delta;
Rotation += Mathf.Pi * (float)delta;
}
}
@@ -162,15 +162,15 @@ look like this:
.. code-tab:: csharp
public override void _Process(float delta)
public override void _Process(double delta)
{
if (Engine.IsEditorHint())
{
Rotation += Mathf.Pi * delta;
Rotation += Mathf.Pi * (float)delta;
}
else
{
Rotation -= Mathf.Pi * delta;
Rotation -= Mathf.Pi * (float)delta;
}
}
@@ -208,24 +208,23 @@ Add and export a variable speed to the script. The function set_speed after
[Tool]
public partial class MySprite : Sprite2D
{
private float speed = 1;
private float _speed = 1;
[Export]
public float Speed {
get => speed;
set => SetSpeed(value);
public float Speed
{
get => _speed;
set
{
// Update speed and reset the rotation.
_speed = value;
Rotation = 0;
}
}
// Update speed and reset the rotation.
private void SetSpeed(float newSpeed)
public override void _Process(double delta)
{
speed = newSpeed;
Rotation = 0;
}
public override void _Process(float delta)
{
Rotation += Mathf.Pi * delta * speed;
Rotation += Mathf.Pi * (float)delta * speed;
}
}

View File

@@ -327,7 +327,7 @@ the performance of C# in Godot — while generally in the same order of magnitud
a little faster; the specifics are going to vary according to your use case.
GDScript is likely fast enough for most general scripting workloads.
Most properties of Godot C# objects that are based on ``Godot.Object``
Most properties of Godot C# objects that are based on ``GodotObject``
(e.g. any ``Node`` like ``Control`` or ``Node3D`` like ``Camera3D``) require native (interop) calls as they talk to
Godot's C++ core.
Consider assigning values of such properties into a local variable if you need to modify or read them multiple times at

View File

@@ -74,8 +74,8 @@ Exceptions:
=========================== =======================================================
GDScript C#
=========================== =======================================================
``weakref(obj)`` ``Object.WeakRef(obj)``
``is_instance_valid(obj)`` ``Object.IsInstanceValid(obj)``
``weakref(obj)`` ``GodotObject.WeakRef(obj)``
``is_instance_valid(obj)`` ``GodotObject.IsInstanceValid(obj)``
=========================== =======================================================
Tips
@@ -177,9 +177,9 @@ Example:
Input.IsActionPressed("ui_down")
However, in some very rare cases this is not enough. For example, you may want
to access a member from the base class ``Godot.Object``, like ``Connect``.
to access a member from the base class ``GodotObject``, like ``Connect``.
For such use cases we provide a static property named ``Singleton`` that returns
the singleton instance. The type of this instance is ``Godot.Object``.
the singleton instance. The type of this instance is ``GodotObject``.
Example:
@@ -586,7 +586,7 @@ An expression ``t`` is awaitable if one of the following holds:
.. _ValueTask<TResult>: https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.valuetask-1
An equivalent of awaiting a signal in GDScript can be achieved with the ``await`` keyword and
``Godot.Object.ToSignal``.
``GodotObject.ToSignal``.
Example:

View File

@@ -332,14 +332,14 @@ Export annotations are also provided for the physics and render layers defined i
.. code-block:: csharp
[Export(PropertyHint.Layers2dPhysics)]
private int Layers2dPhysics;
[Export(PropertyHint.Layers2dRender)]
private int Layers2dRender;
[Export(PropertyHint.Layers3dPhysics)]
private int layers3dPhysics;
[Export(PropertyHint.Layers3dRender)]
private int layers3dRender;
[Export(PropertyHint.Layers2DPhysics)]
private int Layers2DPhysics;
[Export(PropertyHint.Layers2DRender)]
private int Layers2DRender;
[Export(PropertyHint.Layers3DPhysics)]
private int layers3DPhysics;
[Export(PropertyHint.Layers3DRender)]
private int layers3DRender;
Using bit flags requires some understanding of bitwise operations.
If in doubt, use boolean variables instead.

View File

@@ -92,15 +92,17 @@ Signals support arguments of:
* All the `built-in value types <https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/built-in-types-table>`_,
except ``decimal``, ``nint`` and ``nuint``
* ``string``
* Classes derived from :ref:`Godot.Object <class_Object>`
* Classes derived from :ref:`GodotObject <class_Object>`
* Collections types defined in the ``Godot.Collections`` namespace
Consequently, any ``Node`` or ``Reference`` will be compatible automatically, but custom data objects will need
to inherit from ``Godot.Object`` or one of its subclasses.
to inherit from ``GodotObject`` or one of its subclasses.
.. code-block:: csharp
public partial class DataObject : Godot.Object
using Godot;
public partial class DataObject : GodotObject
{
public string MyFirstString { get; set; }
public string MySecondString { get; set; }

View File

@@ -87,7 +87,7 @@ with :ref:`new() <class_CSharpScript_method_new>`.
For example, MyCoolNode.cs should contain a class named MyCoolNode.
The C# class needs to derive a Godot class, for example ``Godot.Object``.
The C# class needs to derive a Godot class, for example ``GodotObject``.
Otherwise, the same error will occur.
You also need to check your ``.cs`` file is referenced in the project's
@@ -101,8 +101,8 @@ be instantiated with :ref:`GDScript.New() <class_GDScript_method_new>`.
.. code-block:: csharp
GDScript MyGDScript = (GDScript) GD.Load("res://path_to_gd_file.gd");
Object myGDScriptNode = (Godot.Object) MyGDScript.New(); // This is a Godot.Object
GDScript MyGDScript = (GDScript)GD.Load("res://path_to_gd_file.gd");
GodotObject myGDScriptNode = (GodotObject)MyGDScript.New(); // This is a GodotObject
Here we are using an :ref:`class_Object`, but you can use type conversion like
explained in :ref:`doc_c_sharp_features_type_conversion_and_casting`.
@@ -126,8 +126,8 @@ Accessing GDScript fields from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
As C# is statically typed, accessing GDScript from C# is a bit more
convoluted, you will have to use :ref:`Object.Get() <class_Object_method_get>`
and :ref:`Object.Set() <class_Object_method_set>`. The first argument is the name of the field you want to access.
convoluted, you will have to use :ref:`GodotObject.Get() <class_Object_method_get>`
and :ref:`GodotObject.Set() <class_Object_method_set>`. The first argument is the name of the field you want to access.
.. code-block:: csharp
@@ -164,7 +164,7 @@ Calling GDScript methods from C#
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To call GDScript methods from C# you'll need to use
:ref:`Object.Call() <class_Object_method_call>`. The first argument is the
:ref:`GodotObject.Call() <class_Object_method_call>`. The first argument is the
name of the method you want to call. The following arguments will be passed
to said method.

View File

@@ -144,7 +144,7 @@ Simply override it in your control. No processing needs to be set.
public override void _GuiInput(InputEvent @event)
{
if (@event is InputEventMouseButton mbe && mbe.ButtonIndex == (int)ButtonList.Left && mbe.Pressed)
if (@event is InputEventMouseButton mbe && mbe.ButtonIndex == MouseButton.Left && mbe.Pressed)
{
GD.Print("Left mouse button was pressed!");
}