> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/ru/skripting/random-math-and-more.md).

# Случайность, математика и многое другое

Эта страница — набор полезных утилит, которые вы будете использовать постоянно: RNG, форматирование, время и несколько основных подсистем, встречающихся в большинстве игр.

{% hint style="info" %}
Если вы ищете массивы/срезы, см. [Массивы и коллекции](/all-out-docs/ru/skripting/arrays-and-collections.md).
{% endhint %}

## Случайные числа (RNG)

Для генератора случайных чисел используется явный `u64` seed. Передавайте seed по `ref` чтобы он обновлялся.

```go
rng: u64 = rng_root_seed();
// или детерминированно для каждой сущности:
// rng: u64 = rng_seed(entity.id);

// Значения диапазона включают границы
roll := rng_range_int(ref rng, 1, 10);
chance := rng_range_float(ref rng, 0, 1);

// Случайные точки и перемешивание
offset := rng_disk(ref rng, 0.5, 2.0);
spawn_points: [..]v2;
spawn_points.append({0, 0});
spawn_points.append({4, 0});
rng_shuffle(ref rng, spawn_points);

// Смешайте значение в seed, не извлекая случайное число.
rng_mix(ref rng, entity.id);
independent_seed := mix_u64(rng, 123); // возвращает смешанный seed; rng не изменяется
```

{% hint style="warning" %}
Игровая случайность должна выполняться в общем предсказанном игровом пути. Начните с `rng_root_seed()` или другого стабильного seed; не инициализируйте игровую случайность локальными данными.
{% endhint %}

`mix_u64(a: u64, b: u64) -> u64` и `rng_mix(rng: ref u64, value: u64)` — это встроенные intrinsic-функции с тем же детерминированным алгоритмом смешивания. `rng_mix` записывает смешанный результат обратно в `rng`; порядок повторных смешиваний имеет значение.

## Математические функции

Эти функции объявлены в `core:basic`, который `core:ao` также импортирует. В таблицах, `F` означает отдельные `f32` и `f64` перегрузки; `float` есть `f32`и `int` есть `s64`. Аргументы в перегрузке используют один и тот же тип. `T` обозначает универсальный числовой тип, а `V` обозначает отдельные `v2`, `v3`и `v4` перегрузки.

### Справочник по скалярной математике

| Сигнатура функции                                                              | Поведение                                                                                                                                                            |
| ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ceil(x: F) -> F`                                                              | Наименьшее целое значение, большее или равное `x`: `ceil(1.25)` есть `2.0`, `ceil(-1.25)` есть `-1.0`.                                                               |
| `floor(x: F) -> F`                                                             | Наибольшее целое значение, меньшее или равное `x`: `floor(1.25)` есть `1.0`, `floor(-1.25)` есть `-2.0`.                                                             |
| `round(x: F) -> F`                                                             | Ближайшее целое значение, при этом случаи ровно посередине округляются от нуля: `round(2.5)` есть `3.0`, `round(-2.5)` есть `-3.0`.                                  |
| `sin(v: F) -> F`                                                               | Синус угла в радианах.                                                                                                                                               |
| `cos(v: F) -> F`                                                               | Косинус угла в радианах.                                                                                                                                             |
| `atan2(y: F, x: F) -> F`                                                       | Угол в радианах по направлению `(x, y)` вектора. Передавайте **сначала y**.                                                                                          |
| `to_degrees(radians: F) -> F`                                                  | Преобразует радианы в градусы, сохраняя точность.                                                                                                                    |
| `to_radians(degrees: F) -> F`                                                  | Преобразует градусы в радианы, сохраняя точность.                                                                                                                    |
| `pow(b: F, e: F) -> F`                                                         | Возвести основание `b` в степень `e`.                                                                                                                                |
| `sqrt(x: F) -> F`                                                              | Квадратный корень.                                                                                                                                                   |
| `Math.exp(v: F) -> F`                                                          | Натуральная экспонента, e в степени `v`.                                                                                                                             |
| `Math.log(v: F) -> F`                                                          | Натуральный логарифм. Глобальная `log` функция является псевдонимом для логирования.                                                                                 |
| `abs(a: T) -> T`                                                               | Абсолютное значение.                                                                                                                                                 |
| `sign(v: T) -> T`                                                              | `-1` для отрицательных значений; `1` для нуля и положительных значений.                                                                                              |
| `min(a: F, b: F) -> F`; `min(a: int, b: int) -> int`                           | Меньшее из двух значений.                                                                                                                                            |
| `max(a: F, b: F) -> F`; `max(a: int, b: int) -> int`                           | Большее из двух значений.                                                                                                                                            |
| `clamp(a: F, min: F, max: F) -> F`; `clamp(a: int, min: int, max: int) -> int` | Ограничивает значение включительными границами, сначала проверяя нижнюю границу.                                                                                     |
| `lerp(a: F, b: F, t: F) -> F`                                                  | Линейная интерполяция; `t` не ограничивается.                                                                                                                        |
| `linear_step(start: float, end: float, time: float) -> float`                  | Нормализуйте `время` к интервалу и ограничьте до `[0, 1]`; возвращает `1` если конечные точки равны.                                                                 |
| `next_power_of_two(n: s64) -> s64`                                             | Наименьшая степень двойки, не меньшая чем `n`; возвращает `0` для неположительного ввода. Входные значения выше `2^62` переполняются до минимального `s64` значения. |

`PI` также доступна как константа.

Скалярные помощники и `dot` выполняются как математические инструкции VM. Вектор `lerp` непосредственно сводится к векторным арифметическим инструкциям. Им не требуются внешние вызовы. Составные помощники `in_range` и `normalize_vector_to_radius` остаются кодом CSL, собранным из этих примитивов.

Для чисел с плавающей запятой `min` и `max` возвращают второй аргумент, когда значения равны или хотя бы одно из них NaN. `clamp` сохраняет входное значение NaN. `abs` сохраняет знаковый ноль и NaN; для целых `abs` сохраняет знаковое минимальное значение при переполнении. Это те же самые поведенческие особенности, что и у исходных помощников CSL.

### Округление

`ceil`, `floor`и `round` возвращают значение с плавающей точкой той же точности, что и входное. Точные целые, бесконечности и знаковый ноль не изменяются; NaN даёт NaN. Округление вверх означает в сторону положительной бесконечности, поэтому `ceil(-1.25)` есть `-1.0`. `round` использует округление «половина — от нуля», а не округление к ближайшему чётному.

```go
slots := ceil(2.25).(int);       // 3
cell := floor(-2.25).(int);      // -3
nearest := round(-2.5).(int);    // -3
truncated := (-2.25).(int);      // -2: приведение усекает к нулю
precise: f64 = 1.0000000000000002;
rounded := ceil(precise);        // 2.0, всё ещё f64
```

Переводите результат в `int` только когда он конечен и помещается в `int`. Нет `trunc` функции. Для форматирования десятичного отображения используйте `format_float(value, decimals=2)`; она не изменяет числовое значение.

### Справочник по векторной математике

| Сигнатура функции                 | Поведение                                                    |
| --------------------------------- | ------------------------------------------------------------ |
| `length(v: V) -> float`           | Длина вектора.                                               |
| `length_squared(v: V) -> float`   | Квадрат длины, без вычисления квадратного корня.             |
| `normalize(v: V) -> V`            | Нормализовать вектор.                                        |
| `dot(a: V, b: V) -> float`        | Скалярное произведение.                                      |
| `lerp(a: V, b: V, t: float) -> V` | Покомпонентная линейная интерполяция; `t` не ограничивается. |

### Примеры

```go
angle_sin := sin(x);
angle_cos := cos(x);
angle := atan2(dir.y, dir.x);
degrees := to_degrees(angle);
radians := to_radians(degrees);

result := pow(2.0, 3.0);   // 8.0
root := sqrt(16.0);        // 4.0

value := lerp(0.0, 100.0, 0.5);  // 50.0
clamped := clamp(value, 0.0, 10.0);
stepped := linear_step(0.0, 1.0, value);

absolute := abs(-5);
minimum := min(5, 10);
maximum := max(5, 10);
direction_sign := sign(-12);

len := length(v);
len_sq := length_squared(v);
normalized := normalize(v);
facing := dot(normalized, {1, 0});
```

## Форматирование строк

Используйте `%` заполнители с массивом аргументов:

```go
format_string("Значение: %", {42});
format_string("здоровье: 100%");
```

Если вам нужен аргумент рядом со знаком процента (или рядом с другим аргументом), используйте `%0` как псевдоним для `%`:

```go
hp := 67;
format_string("здоровье: %0%%", {hp}); // "здоровье: 67%"
```

Для округления дробной части используйте `format_float`:

```go
value := 3.14159;
format_string("пи: %", {format_float(value, decimals=2)}); // "пи: 3.14"
```

Распространённые строковые помощники:

```go
clean := string_trim("  привет  ");
parts := string_split("a,b,c", ",");
name_lower := to_lower(player.get_username());
name_upper := to_upper("готово");
short := string_substring("abcdef", 1, 3); // "bcd"
```

## Логирование

Логирование следует тем же правилам форматирования:

```go
log_info("Имя: %, возраст: %", {player.get_username(), 12});
```

## Время

```go
current_time := get_time();       // вещественные секунды с начала игры
frame := get_frame_number();      // номер текущего кадра
now_ns := get_nanoseconds_since_epoch();
utc := get_utc_datetime();
```

## SFX

```go
sound := get_asset(SFX_Asset, "sfx/click.wav");

desc := SFX.default_sfx_desc();
desc.entity_to_follow = entity.id;
desc.delay = 0.25;

sound_id := SFX.play(sound, desc);
SFX.stop(sound_id);
```

{% hint style="warning" %}
Вызывайте игровые звуки из общего игрового пути. Движок согласует предсказанное воспроизведение. Для звука, который должен слышать только один игрок, задайте `desc.specific_to_player = player`; не оборачивайте `SFX.play` в `is_local()`.
{% endhint %}

## Быстрый старт по экономике (валюты)

Валюты экономики **для каждого игрока** и **автоматически сохраняются**.

```go
ao_before_scene_load :: proc() {
    coin_icon := get_asset(Texture_Asset, "ui/coin.png");
    Economy.register_currency("Монеты", coin_icon);
}

Economy.deposit_currency(player, "Монеты", 10);
coins := Economy.get_balance(player, "Монеты");

COST :: 50;
if Economy.can_withdraw_currency(player, "Монеты", COST) {
    Economy.withdraw_currency(player, "Монеты", COST);
}
```

Суммы пополнения и снятия должны быть неотрицательными.

См. [Economy](/all-out-docs/ru/dannye-i-sokhranenie/economy.md) за полным руководством.
