mirror of
https://github.com/godotengine/godot-docs.git
synced 2025-12-31 17:49:03 +03:00
Add C# code examples (salvage of VinnNo's PRs)
This commit is contained in:
@@ -80,7 +80,7 @@ released.
|
||||
|
||||
onready var _animated_sprite = $AnimatedSprite2D
|
||||
|
||||
func _process(delta):
|
||||
func _process(_delta):
|
||||
if Input.is_action_pressed("ui_right"):
|
||||
_animated_sprite.play("run")
|
||||
else:
|
||||
@@ -97,7 +97,7 @@ released.
|
||||
_animatedSprite = GetNode<AnimatedSprite>("AnimatedSprite");
|
||||
}
|
||||
|
||||
public override _Process(float delta)
|
||||
public override _Process(float _delta)
|
||||
{
|
||||
if (Input.IsActionPressed("ui_right"))
|
||||
{
|
||||
@@ -219,7 +219,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:
|
||||
@@ -236,7 +236,7 @@ released.
|
||||
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
}
|
||||
|
||||
public override void _Process(float delta)
|
||||
public override void _Process(float _delta)
|
||||
{
|
||||
if (Input.IsActionPressed("ui_right"))
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -31,8 +31,16 @@ change the value of ``t`` from 0 to 1.
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
func _quadratic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, t: float):
|
||||
var q0 = p0.linear_interpolate(p1, t)
|
||||
var q1 = p1.linear_interpolate(p2, t)
|
||||
var q0 = p0.lerp(p1, t)
|
||||
var q1 = p1.lerp(p2, t)
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
private Vector2 QuadraticBezier(Vector2 p0, Vector2 p1, Vector2 p2, float t)
|
||||
{
|
||||
Vector2 q0 = p0.Lerp(p1, t);
|
||||
Vector2 q1 = p1.Lerp(p2, t);
|
||||
}
|
||||
|
||||
We then interpolate ``q0`` and ``q1`` to obtain a single point ``r`` that moves
|
||||
along a curve.
|
||||
@@ -40,9 +48,14 @@ along a curve.
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
var r = q0.linear_interpolate(q1, t)
|
||||
var r = q0.lerp(q1, t)
|
||||
return r
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
Vector2 r = q0.Lerp(q1, t);
|
||||
return r;
|
||||
|
||||
This type of curve is called a *Quadratic Bezier* curve.
|
||||
|
||||
.. image:: img/bezier_quadratic_points2.gif
|
||||
@@ -65,48 +78,86 @@ 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:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
var q0 = p0.linear_interpolate(p1, t)
|
||||
var q1 = p1.linear_interpolate(p2, t)
|
||||
var q2 = p2.linear_interpolate(p3, t)
|
||||
var q0 = p0.lerp(p1, t)
|
||||
var q1 = p1.lerp(p2, t)
|
||||
var q2 = p2.lerp(p3, t)
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
Vector2 q0 = p0.Lerp(p1, t);
|
||||
Vector2 q1 = p1.Lerp(p2, t);
|
||||
Vector2 q2 = p2.Lerp(p3, t);
|
||||
|
||||
We then take our three points and reduce them to two:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
var r0 = q0.linear_interpolate(q1, t)
|
||||
var r1 = q1.linear_interpolate(q2, t)
|
||||
var r0 = q0.lerp(q1, t)
|
||||
var r1 = q1.lerp(q2, t)
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
Vector2 r0 = q0.Lerp(q1, t);
|
||||
Vector2 r1 = q1.Lerp(q2, t);
|
||||
|
||||
And to one:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
var s = r0.linear_interpolate(r1, t)
|
||||
var s = r0.lerp(r1, t)
|
||||
return s
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
Vector2 s = r0.Lerp(r1, t);
|
||||
return s;
|
||||
|
||||
Here is the full function:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
func _cubic_bezier(p0: Vector2, p1: Vector2, p2: Vector2, p3: Vector2, t: float):
|
||||
var q0 = p0.linear_interpolate(p1, t)
|
||||
var q1 = p1.linear_interpolate(p2, t)
|
||||
var q2 = p2.linear_interpolate(p3, t)
|
||||
var q0 = p0.lerp(p1, t)
|
||||
var q1 = p1.lerp(p2, t)
|
||||
var q2 = p2.lerp(p3, t)
|
||||
|
||||
var r0 = q0.linear_interpolate(q1, t)
|
||||
var r1 = q1.linear_interpolate(q2, t)
|
||||
var r0 = q0.lerp(q1, t)
|
||||
var r1 = q1.lerp(q2, t)
|
||||
|
||||
var s = r0.linear_interpolate(r1, t)
|
||||
var s = r0.lerp(r1, t)
|
||||
return s
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
private Vector2 CubicBezier(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
|
||||
{
|
||||
Vector2 q0 = p0.Lerp(p1, t);
|
||||
Vector2 q1 = p1.Lerp(p2, t);
|
||||
Vector2 q2 = p2.Lerp(p3, t);
|
||||
|
||||
Vector2 r0 = q0.Lerp(q1, t);
|
||||
Vector2 r1 = q1.Lerp(q2, t);
|
||||
|
||||
Vector2 s = r0.Lerp(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 an 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
|
||||
|
||||
@@ -11,15 +11,13 @@ For example, if ``t`` is 0, then the state is A. If ``t`` is 1, then the state i
|
||||
|
||||
Between two real (floating-point) numbers, an interpolation can be 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
|
||||
|
||||
@@ -31,7 +29,7 @@ Vector interpolation
|
||||
--------------------
|
||||
|
||||
Vector types (:ref:`Vector2 <class_Vector2>` and :ref:`Vector3 <class_Vector3>`) can also be interpolated, they come with handy functions to do it
|
||||
:ref:`Vector2.linear_interpolate() <class_Vector2_method_linear_interpolate>` and :ref:`Vector3.linear_interpolate() <class_Vector3_method_linear_interpolate>`.
|
||||
:ref:`Vector2.lerp() <class_Vector2_method_lerp>` and :ref:`Vector3.lerp() <class_Vector3_method_lerp>`.
|
||||
|
||||
For cubic interpolation, there are also :ref:`Vector2.cubic_interpolate() <class_Vector2_method_cubic_interpolate>` and :ref:`Vector3.cubic_interpolate() <class_Vector3_method_cubic_interpolate>`, which do a :ref:`Bezier <doc_beziers_and_curves>` style interpolation.
|
||||
|
||||
@@ -40,10 +38,27 @@ Here is example 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
|
||||
|
||||
$Sprite2D.position = $A.position.linear_interpolate($B.position, t)
|
||||
$Sprite2D.position = $A.position.lerp($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");
|
||||
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
|
||||
|
||||
sprite.Position = a.Position.Lerp(b.Position, _t);
|
||||
}
|
||||
|
||||
It will produce the following motion:
|
||||
|
||||
@@ -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
|
||||
@@ -89,7 +119,20 @@ Interpolation can be used to smooth movement, rotation, etc. Here is an example
|
||||
func _physics_process(delta):
|
||||
var mouse_pos = get_local_mouse_position()
|
||||
|
||||
$Sprite2D.position = $Sprite2D.position.linear_interpolate(mouse_pos, delta * FOLLOW_SPEED)
|
||||
$Sprite2D.position = $Sprite2D.position.lerp(mouse_pos, delta * FOLLOW_SPEED)
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
private const float FollowSpeed = 4.0f;
|
||||
|
||||
public override void _PhysicsProcess(float delta)
|
||||
{
|
||||
Vector2 mousePos = GetLocalMousePosition();
|
||||
|
||||
Sprite2D sprite = GetNode<Sprite2D>("Sprite2D");
|
||||
|
||||
sprite.Position = sprite.Position.Lerp(mousePos, delta * FollowSpeed);
|
||||
}
|
||||
|
||||
Here is how it looks:
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
When using the RandomNumberGenerator class, you should call ``randomize()`` on
|
||||
the instance since it has its own seed::
|
||||
.. code-tab:: csharp
|
||||
|
||||
var rng = RandomNumberGenerator.new()
|
||||
rng.randomize()
|
||||
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:
|
||||
|
||||
.. 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
|
||||
|
||||
To prevent the same fruit from being picked more than once in a row, we can add
|
||||
more logic to this method::
|
||||
.. code-tab:: csharp
|
||||
|
||||
var fruits = ["apple", "orange", "pear", "banana"]
|
||||
var last_fruit = ""
|
||||
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:
|
||||
|
||||
.. 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:
|
||||
|
||||
var noise = OpenSimplexNoise.new()
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,8 +161,8 @@ it as if it was an image (via :ref:`ViewportContainer <class_ViewportContainer>`
|
||||
Creating custom Containers
|
||||
--------------------------
|
||||
|
||||
It is possible to easily create a custom container using script. Here is an example of a container that fits children
|
||||
to its rect size:
|
||||
It is possible to create a custom container using a script.
|
||||
Here is an example of a container that fits children to its rect size:
|
||||
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
@@ -174,8 +174,34 @@ to its rect size:
|
||||
# Must re-sort the children
|
||||
for c in get_children():
|
||||
# Fit to own size
|
||||
fit_child_in_rect( c, Rect2( Vector2(), rect_size ) )
|
||||
fit_child_in_rect(c, Rect2(Vector2(), rect_size))
|
||||
|
||||
func set_some_setting():
|
||||
# Some setting changed, ask for children re-sort
|
||||
# Some setting changed, ask for children re-sort.
|
||||
queue_sort()
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
using Godot;
|
||||
|
||||
public class CustomContainer : Container
|
||||
{
|
||||
public override void _Notification(int what)
|
||||
{
|
||||
if (what == NotificationSortChildren)
|
||||
{
|
||||
// Must re-sort the children
|
||||
foreach (Control c in GetChildren())
|
||||
{
|
||||
// Fit to own size
|
||||
FitChildInRect(c, new Rect2(new Vector2(), RectSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetSomeSetting()
|
||||
{
|
||||
// Some setting changed, ask for children re-sort.
|
||||
QueueSort();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ To center a control in its parent, set its anchors to 0.5 and each margin
|
||||
to half of its relevant dimension. For example, the code below shows how
|
||||
a TextureRect can be centered in its parent:
|
||||
|
||||
::
|
||||
.. tabs::
|
||||
.. code-tab:: gdscript GDScript
|
||||
|
||||
var rect = TextureRect.new()
|
||||
rect.texture = load("res://icon.png")
|
||||
@@ -72,12 +73,30 @@ a TextureRect can be centered in its parent:
|
||||
rect.anchor_top = 0.5
|
||||
rect.anchor_bottom = 0.5
|
||||
var texture_size = rect.texture.get_size()
|
||||
rect.margin_left = -texture_size.x / 2
|
||||
rect.margin_right = -texture_size.x / 2
|
||||
rect.margin_top = -texture_size.y / 2
|
||||
rect.margin_bottom = -texture_size.y / 2
|
||||
rect.offset_left = -texture_size.x / 2
|
||||
rect.offset_right = texture_size.x / 2
|
||||
rect.offset_top = -texture_size.y / 2
|
||||
rect.offset_bottom = texture_size.y / 2
|
||||
add_child(rect)
|
||||
|
||||
.. code-tab:: csharp
|
||||
|
||||
var rect = new TextureRect();
|
||||
|
||||
rect.Texture = ResourceLoader.Load<Texture>("res://icon.png");
|
||||
rect.AnchorLeft = 0.5f;
|
||||
rect.AnchorRight = 0.5f;
|
||||
rect.AnchorTop = 0.5f;
|
||||
rect.AnchorBottom = 0.5f;
|
||||
|
||||
var textureSize = rect.Texture.GetSize();
|
||||
|
||||
rect.OffsetLeft = -textureSize.x / 2;
|
||||
rect.OffsetRight = textureSize.x / 2;
|
||||
rect.OffsetTop = -textureSize.y / 2;
|
||||
rect.OffsetBottom = textureSize.y / 2;
|
||||
AddChild(rect);
|
||||
|
||||
Setting each anchor to 0.5 moves the reference point for the margins to
|
||||
the center of its parent. From there, we set negative margins so that
|
||||
the control gets its natural size.
|
||||
|
||||
Reference in New Issue
Block a user