Browse Source

[3.x] Add C# code examples (salvage of VinnNo's PRs)

Aaron Franke 3 years ago
parent
commit
1ea8cccaf1

+ 4 - 4
tutorials/2d/2d_sprite_animation.rst

@@ -81,7 +81,7 @@ released.
 
     onready var _animated_sprite = $AnimatedSprite
 
-    func _process(delta):
+    func _process(_delta):
         if Input.is_action_pressed("ui_right"):
             _animated_sprite.play("run")
         else:
@@ -98,7 +98,7 @@ released.
             _animatedSprite = GetNode<AnimatedSprite>("AnimatedSprite");
         }
 
-        public override _Process(float delta)
+        public override _Process(float _delta)
         {
             if (Input.IsActionPressed("ui_right"))
             {
@@ -220,7 +220,7 @@ released.
 
     onready var _animation_player = $AnimationPlayer
 
-    func _process(delta):
+    func _process(_delta):
         if Input.is_action_pressed("ui_right"):
             _animation_player.play("walk")
         else:
@@ -237,7 +237,7 @@ released.
             _animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
         }
 
-        public override void _Process(float delta)
+        public override void _Process(float _delta)
         {
             if (Input.IsActionPressed("ui_right"))
             {

+ 2 - 9
tutorials/2d/custom_drawing_in_2d.rst

@@ -360,13 +360,6 @@ calls ``_draw()``. This way, you can control when you want to refresh the frame.
 
  .. code-tab:: csharp
 
-    private float Wrap(float value, float minVal, float maxVal)
-    {
-        float f1 = value - minVal;
-        float f2 = maxVal - minVal;
-        return (f1 % f2) + minVal;
-    }
-
     public override void _Process(float delta)
     {
         _angleFrom += _rotationAngle;
@@ -375,8 +368,8 @@ calls ``_draw()``. This way, you can control when you want to refresh the frame.
         // We only wrap angles when both of them are bigger than 360.
         if (_angleFrom > 360 && _angleTo > 360)
         {
-            _angleFrom = Wrap(_angleFrom, 0, 360);
-            _angleTo = Wrap(_angleTo, 0, 360);
+            _angleFrom = Mathf.Wrap(_angleFrom, 0, 360);
+            _angleTo = Mathf.Wrap(_angleTo, 0, 360);
         }
         Update();
     }

+ 70 - 0
tutorials/math/beziers_and_curves.rst

@@ -34,6 +34,14 @@ change the value of ``t`` from 0 to 1.
         var q0 = p0.linear_interpolate(p1, t)
         var q1 = p1.linear_interpolate(p2, t)
 
+ .. code-tab:: csharp
+
+    private Vector2 QuadraticBezier(Vector2 p0, Vector2 p1, Vector2 p2, float t)
+    {
+        Vector2 q0 = p0.LinearInterpolate(p1, t);
+        Vector2 q1 = p1.LinearInterpolate(p2, t);
+    }
+
 We then interpolate ``q0`` and ``q1`` to obtain a single point ``r`` that moves
 along a curve.
 
@@ -43,6 +51,11 @@ along a curve.
         var r = q0.linear_interpolate(q1, t)
         return r
 
+ .. code-tab:: csharp
+
+        Vector2 r = q0.LinearInterpolate(q1, t);
+        return r;
+
 This type of is called a *Quadratic Bezier* curve.
 
 .. image:: img/bezier_quadratic_points2.gif
@@ -65,6 +78,13 @@ We first use a function with four parameters to take four points as an input,
 
     func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float):
 
+ .. code-tab:: csharp
+
+    public Vector2 CubicBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
+    {
+
+    }
+
 We apply a linear interpolation to each couple of points to reduce them to
 three:
 
@@ -75,6 +95,12 @@ three:
         var q1 = p1.linear_interpolate(p2, t)
         var q2 = p2.linear_interpolate(p3, t)
 
+ .. code-tab:: csharp
+
+        Vector2 q0 = p0.LinearInterpolate(p1, t);
+        Vector2 q1 = p1.LinearInterpolate(p2, t);
+        Vector2 q2 = p2.LinearInterpolate(p3, t);
+
 We then take our three points and reduce them to two:
 
 .. tabs::
@@ -83,6 +109,11 @@ We then take our three points and reduce them to two:
         var r0 = q0.linear_interpolate(q1, t)
         var r1 = q1.linear_interpolate(q2, t)
 
+ .. code-tab:: csharp
+
+        Vector2 r0 = q0.LinearInterpolate(q1, t);
+        Vector2 r1 = q1.LinearInterpolate(q2, t);
+
 And to one:
 
 .. tabs::
@@ -91,6 +122,11 @@ And to one:
         var s = r0.linear_interpolate(r1, t)
         return s
 
+ .. code-tab:: csharp
+
+        Vector2 s = r0.LinearInterpolate(r1, t);
+        return s;
+
 Here is the full function:
 
 .. tabs::
@@ -107,6 +143,21 @@ Here is the full function:
         var s = r0.linear_interpolate(r1, t)
         return s
 
+ .. code-tab:: csharp
+
+    private Vector2 CubicBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
+    {
+        Vector2 q0 = p0.LinearInterpolate(p1, t);
+        Vector2 q1 = p1.LinearInterpolate(p2, t);
+        Vector2 q2 = p2.LinearInterpolate(p3, t);
+
+        Vector2 r0 = q0.LinearInterpolate(q1, t);
+        Vector2 r1 = q1.LinearInterpolate(q2, t);
+
+        Vector2 s = r0.LinearInterpolate(r1, t);
+        return s;
+    }
+
 The result will be a smooth curve interpolating between all four points:
 
 .. image:: img/bezier_cubic_points.gif
@@ -164,6 +215,15 @@ Let's do a simple example with the following pseudocode:
         t += delta
         position = _cubic_bezier(p0, p1, p2, p3, t)
 
+ .. code-tab:: csharp
+
+    private float _t = 0.0f;
+
+    public override void _Process(float delta)
+    {
+        _t += delta;
+        Position = CubicBezier(p0, p1, p2, p3, _t);
+    }
 
 .. image:: img/bezier_interpolation_speed.gif
 
@@ -204,6 +264,16 @@ Traversal at constant speed, then, can be done with the following pseudo-code:
         t += delta
         position = curve.interpolate_baked(t * curve.get_baked_length(), true)
 
+ .. code-tab:: csharp
+
+    private float _t = 0.0f;
+
+    public override void _Process(float delta)
+    {
+        _t += delta;
+        Position = curve.InterpolateBaked(_t * curve.GetBakedLength(), true);
+    }
+
 And the output will, then, move at constant speed:
 
 .. image:: img/bezier_interpolation_baked.gif

+ 47 - 4
tutorials/math/interpolation.rst

@@ -11,15 +11,13 @@ As an example if ``t`` is 0, then the state is A. If ``t`` is 1, then the state
 
 Between two real (floating-point) numbers, a simple interpolation is usually described as:
 
-.. tabs::
- .. code-tab:: gdscript GDScript
+::
 
     interpolation = A * (1 - t) + B * t
 
 And often simplified to:
 
-.. tabs::
- .. code-tab:: gdscript GDScript
+::
 
     interpolation = A + (B - A) * t
 
@@ -40,11 +38,28 @@ Here is simple pseudo-code for going from point A to B using interpolation:
 .. tabs::
  .. code-tab:: gdscript GDScript
 
+    var t = 0.0
+
     func _physics_process(delta):
         t += delta * 0.4
 
         $Sprite.position = $A.position.linear_interpolate($B.position, t)
 
+ .. code-tab:: csharp
+
+    private float _t = 0.0f;
+
+    public override void _PhysicsProcess(float delta)
+    {
+        _t += delta * 0.4f;
+
+        Position2D a = GetNode<Position2D>("A");
+        Position2D b = GetNode<Position2D>("B");
+        Sprite sprite = GetNode<Sprite>("Sprite");
+
+        sprite.Position = a.Position.LinearInterpolate(b.Position, _t);
+    }
+
 It will produce the following motion:
 
 .. image:: img/interpolation_vector.gif
@@ -71,6 +86,21 @@ Using the following pseudocode:
 
         $Monkey.transform = $Position1.transform.interpolate_with($Position2.transform, t)
 
+ .. code-tab:: csharp
+
+    private float _t = 0.0f;
+
+    public override void _PhysicsProcess(float delta)
+    {
+        _t += delta;
+
+        Position3D p1 = GetNode<Position3D>("Position1");
+        Position3D p2 = GetNode<Position3D>("Position2");
+        CSGMesh monkey = GetNode<CSGMesh>("Monkey");
+
+        monkey.Transform = p1.Transform.InterpolateWith(p2.Transform, _t);
+    }
+
 And again, it will produce the following motion:
 
 .. image:: img/interpolation_monkey.gif
@@ -91,6 +121,19 @@ Interpolation can be used to smooth movement, rotation, etc. Here is an example
 
         $Sprite.position = $Sprite.position.linear_interpolate(mouse_pos, delta * FOLLOW_SPEED)
 
+ .. code-tab:: csharp
+
+    private const float FollowSpeed = 4.0f;
+
+    public override void _PhysicsProcess(float delta)
+    {
+        Vector2 mousePos = GetLocalMousePosition();
+
+        Sprite sprite = GetNode<Sprite>("Sprite");
+
+        sprite.Position = sprite.Position.LinearInterpolate(mousePos, delta * FollowSpeed);
+    }
+
 Here is how it looks:
 
 .. image:: img/interpolation_follow.gif

+ 237 - 51
tutorials/math/random_number_generation.rst

@@ -42,25 +42,54 @@ In global scope, you can find a :ref:`randomize()
 once when your project starts to initialize the random seed.** Calling it
 multiple times is unnecessary and may impact performance negatively.
 
-Putting it in your main scene script's ``_ready()`` method is a good choice::
+Putting it in your main scene script's ``_ready()`` method is a good choice:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     func _ready():
         randomize()
 
+ .. code-tab:: csharp
+
+    public override void _Ready()
+    {
+        GD.Randomize();
+    }
+
 You can also set a fixed random seed instead using :ref:`seed()
 <class_@GDScript_method_seed>`. Doing so will give you *deterministic* results
-across runs::
+across runs:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     func _ready():
         seed(12345)
         # To use a string as a seed, you can hash it to a number.
         seed("Hello world".hash())
 
+ .. code-tab:: csharp
+
+    public override void _Ready()
+    {
+        GD.Seed(12345);
+        GD.Seed("Hello world".Hash());
+    }
+
 When using the RandomNumberGenerator class, you should call ``randomize()`` on
-the instance since it has its own seed::
+the instance since it has its own seed:
 
-    var rng = RandomNumberGenerator.new()
-    rng.randomize()
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    var random = RandomNumberGenerator.new()
+    random.randomize()
+
+ .. code-tab:: csharp
+
+    var random = new RandomNumberGenerator();
+    random.Randomize();
 
 Getting a random number
 -----------------------
@@ -71,7 +100,10 @@ random numbers in Godot.
 The function :ref:`randi() <class_@GDScript_method_randi>` returns a random
 number between 0 and 2^32-1. Since the maximum value is huge, you most likely
 want to use the modulo operator (``%``) to bound the result between 0 and the
-denominator::
+denominator:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     # Prints a random integer between 0 and 49.
     print(randi() % 50)
@@ -79,6 +111,14 @@ denominator::
     # Prints a random integer between 10 and 60.
     print(randi() % 51 + 10)
 
+ .. code-tab:: csharp
+
+    // Prints a random integer between 0 and 49.
+    GD.Print(GD.Randi() % 50);
+
+    // Prints a random integer between 10 and 60.
+    GD.Print(GD.Randi() % 51 + 10);
+
 :ref:`randf() <class_@GDScript_method_randf>` returns a random floating-point
 number between 0 and 1. This is useful to implement a
 :ref:`doc_random_number_generation_weighted_random_probability` system, among
@@ -87,83 +127,169 @@ other things.
 :ref:`randfn() <class_RandomNumberGenerator_method_randfn>` returns a random
 floating-point number following a `normal distribution
 <https://en.wikipedia.org/wiki/Normal_distribution>`__. This means the returned
-value is more likely to be around the mean (0.0 by default), varying by the deviation (1.0 by default)::
+value is more likely to be around the mean (0.0 by default),
+varying by the deviation (1.0 by default):
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     # Prints a random floating-point number from a normal distribution with a mean 0.0 and deviation 1.0.
-    var rng = RandomNumberGenerator.new()
-    rng.randomize()
-    print(rng.randfn())
+    var random = RandomNumberGenerator.new()
+    random.randomize()
+    print(random.randfn())
+
+ .. code-tab:: csharp
+
+    // Prints a normally distributed floating-point number between 0.0 and 1.0.
+    var random = new RandomNumberGenerator();
+    random.Randomize();
+    GD.Print(random.Randfn());
 
 :ref:`rand_range() <class_@GDScript_method_rand_range>` takes two arguments
 ``from`` and ``to``, and returns a random floating-point number between ``from``
-and ``to``::
+and ``to``:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     # Prints a random floating-point number between -4 and 6.5.
     print(rand_range(-4, 6.5))
 
+ .. code-tab:: csharp
+
+    // Prints a random floating-point number between -4 and 6.5.
+    GD.Print(GD.RandRange(-4, 6.5));
+
 :ref:`RandomNumberGenerator.randi_range()
 <class_RandomNumberGenerator_method_randi_range>` takes two arguments ``from``
-and ``to``, and returns a random integer between ``from`` and ``to``::
+and ``to``, and returns a random integer between ``from`` and ``to``:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     # Prints a random integer between -10 and 10.
-    var rng = RandomNumberGenerator.new()
-    rng.randomize()
-    print(rng.randi_range(-10, 10))
+    var random = RandomNumberGenerator.new()
+    random.randomize()
+    print(random.randi_range(-10, 10))
+
+ .. code-tab:: csharp
+
+    # Prints a random integer number between -10 and 10.
+    random.Randomize();
+    GD.Print(random.RandiRange(-10, 10));
 
 Get a random array element
 --------------------------
 
-We can use random integer generation to get a random element from an array::
+We can use random integer generation to get a random element from an array:
 
-    var fruits = ["apple", "orange", "pear", "banana"]
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
+    var _fruits = ["apple", "orange", "pear", "banana"]
 
     func _ready():
         randomize()
 
-        for i in 100:
+        for i in range(100):
             # Pick 100 fruits randomly.
-            # (``for i in 100`` is a faster shorthand for ``for i in range(100)``.)
             print(get_fruit())
 
 
     func get_fruit():
-        var random_fruit = fruits[randi() % fruits.size()]
+        var random_fruit = _fruits[randi() % _fruits.size()]
         # Returns "apple", "orange", "pear", or "banana" every time the code runs.
         # We may get the same fruit multiple times in a row.
         return random_fruit
 
+ .. code-tab:: csharp
+
+    private string[] _fruits = { "apple", "orange", "pear", "banana" };
+
+    public override void _Ready()
+    {
+        GD.Randomize();
+
+        for (int i = 0; i < 100; i++)
+        {
+            // Pick 100 fruits randomly.
+            GD.Print(GetFruit());
+        }
+    }
+
+    public string GetFruit()
+    {
+        string randomFruit = _fruits[GD.Randi() % _fruits.Length];
+        // Returns "apple", "orange", "pear", or "banana" every time the code runs.
+        // We may get the same fruit multiple times in a row.
+        return randomFruit;
+    }
+
 To prevent the same fruit from being picked more than once in a row, we can add
-more logic to this method::
+more logic to this method:
 
-    var fruits = ["apple", "orange", "pear", "banana"]
-    var last_fruit = ""
+.. tabs::
+ .. code-tab:: gdscript GDScript
+
+    var _fruits = ["apple", "orange", "pear", "banana"]
+    var _last_fruit = ""
 
 
     func _ready():
         randomize()
 
         # Pick 100 fruits randomly.
-        # Note: ``for i in 100`` is a shorthand for ``for i in range(100)``.
-        for i in 100:
+        for i in range(100):
             print(get_fruit())
 
 
     func get_fruit():
-        var random_fruit = fruits[randi() % fruits.size()]
-        while random_fruit == last_fruit:
+        var random_fruit = _fruits[randi() % _fruits.size()]
+        while random_fruit == _last_fruit:
             # The last fruit was picked, try again until we get a different fruit.
-            random_fruit = fruits[randi() % fruits.size()]
+            random_fruit = _fruits[randi() % _fruits.size()]
 
         # Note: if the random element to pick is passed by reference,
         # such as an array or dictionary,
-        # use `last_fruit = random_fruit.duplicate()` instead.
-        last_fruit = random_fruit
+        # use `_last_fruit = random_fruit.duplicate()` instead.
+        _last_fruit = random_fruit
 
         # Returns "apple", "orange", "pear", or "banana" every time the code runs.
         # The function will never return the same fruit more than once in a row.
         return random_fruit
 
+ .. code-tab:: csharp
+
+    private string[] _fruits = { "apple", "orange", "pear", "banana" };
+    private string _lastFruit = "";
+
+    public override void _Ready()
+    {
+        GD.Randomize();
+
+        for (int i = 0; i < 100; i++)
+        {
+            // Pick 100 fruits randomly.
+            GD.Print(GetFruit());
+        }
+    }
+
+    public string GetFruit()
+    {
+        string randomFruit = _fruits[GD.Randi() % _fruits.Length];
+        while (randomFruit == _lastFruit)
+        {
+            // The last fruit was picked, try again until we get a different fruit.
+            randomFruit = _fruits[GD.Randi() % _fruits.Length];
+        }
+
+        _lastFruit = randomFruit;
+
+        // Returns "apple", "orange", "pear", or "banana" every time the code runs.
+        // The function will never return the same fruit more than once in a row.
+        return randomFruit;
+    }
+
 This approach can be useful to make random number generation feel less
 repetitive. Still, it doesn't prevent results from "ping-ponging" between a
 limited set of values. To prevent this, use the :ref:`shuffle bag
@@ -172,7 +298,10 @@ limited set of values. To prevent this, use the :ref:`shuffle bag
 Get a random dictionary value
 -----------------------------
 
-We can apply similar logic from arrays to dictionaries as well::
+We can apply similar logic from arrays to dictionaries as well:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     var metals = {
         "copper": {"quantity": 50, "price": 50},
@@ -184,7 +313,7 @@ We can apply similar logic from arrays to dictionaries as well::
     func _ready():
         randomize()
 
-        for i in 20:
+        for i in range(20):
             print(get_metal())
 
 
@@ -194,7 +323,6 @@ We can apply similar logic from arrays to dictionaries as well::
         # The same metal may be selected multiple times in succession.
         return random_metal
 
-
 .. _doc_random_number_generation_weighted_random_probability:
 
 Weighted random probability
@@ -202,12 +330,15 @@ Weighted random probability
 
 The :ref:`randf() <class_@GDScript_method_randf>` method returns a
 floating-point number between 0.0 and 1.0. We can use this to create a
-"weighted" probability where different outcomes have different likelihoods::
+"weighted" probability where different outcomes have different likelihoods:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
     func _ready():
         randomize()
 
-        for i in 100:
+        for i in range(100):
             print(get_item_rarity())
 
 
@@ -224,6 +355,39 @@ floating-point number between 0.0 and 1.0. We can use this to create a
             # 5% chance of being returned.
             return "Rare"
 
+ .. code-tab:: csharp
+
+    public override void _Ready()
+    {
+        GD.Randomize();
+
+        for (int i = 0; i < 100; i++)
+        {
+            GD.Print(GetItemRarity());
+        }
+    }
+
+    public string GetItemRarity()
+    {
+        float randomFloat = GD.Randf();
+
+        if (randomFloat < 0.8f)
+        {
+            // 80% chance of being returned.
+            return "Common";
+        }
+        else if (randomFloat < 0.95f)
+        {
+            // 15% chance of being returned
+            return "Uncommon";
+        }
+        else
+        {
+            // 5% chance of being returned.
+            return "Rare";
+        }
+    }
+
 .. _doc_random_number_generation_shuffle_bags:
 
 "Better" randomness using shuffle bags
@@ -238,29 +402,29 @@ You can accomplish this using the *shuffle bag* pattern. It works by removing an
 element from the array after choosing it. After multiple selections, the array
 ends up empty. When that happens, you reinitialize it to its default value::
 
-    var fruits = ["apple", "orange", "pear", "banana"]
+    var _fruits = ["apple", "orange", "pear", "banana"]
     # A copy of the fruits array so we can restore the original value into `fruits`.
-    var fruits_full = []
+    var _fruits_full = []
 
 
     func _ready():
         randomize()
-        fruits_full = fruits.duplicate()
-        fruits.shuffle()
+        _fruits_full = _fruits.duplicate()
+        _fruits.shuffle()
 
         for i in 100:
             print(get_fruit())
 
 
     func get_fruit():
-        if fruits.empty():
+        if _fruits.empty():
             # Fill the fruits array again and shuffle it.
-            fruits = fruits_full.duplicate()
-            fruits.shuffle()
+            _fruits = _fruits_full.duplicate()
+            _fruits.shuffle()
 
         # Get a random fruit, since we shuffled the array,
-        # and remove it from the `fruits` array.
-        var random_fruit = fruits.pop_front()
+        # and remove it from the `_fruits` array.
+        var random_fruit = _fruits.pop_front()
         # Prints "apple", "orange", "pear", or "banana" every time the code runs.
         return random_fruit
 
@@ -279,19 +443,41 @@ time, or anything else.
 To achieve this, you can use random *noise* functions. Noise functions are
 especially popular in procedural generation to generate realistic-looking
 terrain. Godot provides :ref:`class_opensimplexnoise` for this, which supports
-1D, 2D, 3D, and 4D noise. Here's an example with 1D noise::
+1D, 2D, 3D, and 4D noise. Here's an example with 1D noise:
+
+.. tabs::
+ .. code-tab:: gdscript GDScript
 
-    var noise = OpenSimplexNoise.new()
+    var _noise = OpenSimplexNoise.new()
 
     func _ready():
         randomize()
         # Configure the OpenSimplexNoise instance.
-        noise.seed = randi()
-        noise.octaves = 4
-        noise.period = 20.0
-        noise.persistence = 0.8
+        _noise.seed = randi()
+        _noise.octaves = 4
+        _noise.period = 20.0
+        _noise.persistence = 0.8
 
         for i in 100:
             # Prints a slowly-changing series of floating-point numbers
             # between -1.0 and 1.0.
-            print(noise.get_noise_1d(i))
+            print(_noise.get_noise_1d(i))
+
+ .. code-tab:: csharp
+
+    private OpenSimplexNoise _noise = new OpenSimplexNoise();
+
+    public override void _Ready()
+    {
+        GD.Randomize();
+        // Configure the OpenSimplexNoise instance.
+        _noise.Seed = (int)GD.Randi();
+        _noise.Octaves = 4;
+        _noise.Period = 20.0f;
+        _noise.Persistence = 0.8f;
+
+        for (int i = 0; i < 100; i++)
+        {
+            GD.Print(_noise.GetNoise1d(i));
+        }
+    }