Danil Iarosh 839a68aef1 Improve VFX, UI overlays, session statistics, COM reliability, audio mixer, and expand architecture guides
Подробный список изменений:
- Перенесены эффекты частиц из C#-кода в готовые префабы-ассеты (Vfx Prefabs) в папке Assets/Resources/Vfx/ с автоматической генерацией материалов в Editor.
- Исправлены ошибки duration на играющих системах частиц и розовые текстуры в GameVfxService.cs.
- Исправлена навигация и фокус кнопок на оверлеях ContinueGameOverlay и PrizeResultOverlay с автоматическим подсвечиванием кнопок лимонно-зеленым цветом при фокусе и проигрыванием звука.
- Добавлена проверка настроек в GameplayHudController.cs для скрытия ContinueGameOverlay, если продолжение игры отключено.
- Расширен сбор статистики: создана структура GameplaySessionRecord, добавлена история до 50 раундов в PrizeSessionStateService и JsonPrizeSessionStateRepository, выведен расчет средних показателей и список 5 последних раундов в сервисной статистике.
- Повышена надежность COM-транспорта: добавлен sleep (80мс) в Dispose для graceful shutdown потоков, реализован цикл переподключения до 10 попыток при обрыве связи.
- Интегрированы настройки громкости с микшером: изменен шаг изменения громкости на 5% (0.05) для удобства, добавлен статус-чек и логи в ApplyServiceVolumes, расширены юнит-тесты на GetFloat параметры.
- Созданы новые архитектурные гайды по аппаратному COM-транспорту и призовой экономике автомата в папке GUIDES/architecture/.
- Оптимизирован и обновлен RAG-индекс проекта.
2026-07-03 15:04:08 +03:00

148 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Полное руководство по UniTask
**UniTask** (`Cysharp.Threading.Tasks`) — это библиотека, которая заменяет стандартные Unity `Coroutine` и `System.Threading.Tasks.Task`.
Главное преимущество UniTask — **полное отсутствие аллокаций памяти (Zero Allocation)**. Структуры `UniTask` созданы специально для Unity, они интегрированы с `PlayerLoop` и работают быстрее стандартных тасок C#.
## 1. Базовые принципы
- Если метод возвращает `Task` или `IEnumerator`, перепишите его на `UniTask`.
- Вместо `yield return null` используйте `await UniTask.Yield()`.
- Вместо `yield return new WaitForSeconds(1)` используйте `await UniTask.Delay(1000)`.
```csharp
using Cysharp.Threading.Tasks;
public async UniTaskVoid StartGameSequenceAsync()
{
Debug.Log("Start");
// Ждем 1 секунду игрового времени (учитывает Time.timeScale)
await UniTask.Delay(TimeSpan.FromSeconds(1));
Debug.Log("End");
}
```
## 2. Возврат значений и Forget()
В отличие от корутин, UniTask может легко возвращать значения:
```csharp
public async UniTask<int> CalculateScoreAsync()
{
await UniTask.Delay(500);
return 100;
}
```
Если вы вызываете асинхронный метод из синхронного кода (например, из клика по кнопке) и вам не нужно дожидаться результата, метод следует пометить как `UniTaskVoid` или вызвать у него `.Forget()`. Это гарантирует, что в случае ошибки (Exception), она будет выведена в консоль Unity.
```csharp
public void OnButtonClick()
{
// Правильный вызов (Fire and Forget)
PlayAnimationAsync().Forget();
}
```
## 3. Отмена (Cancellation) — КРИТИЧЕСКИ ВАЖНО
В Unity объекты часто уничтожаются (например, при смене сцены). Если ваша таска в этот момент "спит" в `await UniTask.Delay`, она проснется и попытается обратиться к уничтоженному объекту, вызвав `MissingReferenceException`.
Всегда прокидывайте `CancellationToken` во все асинхронные методы!
```csharp
private async UniTaskVoid MoveObjectAsync(CancellationToken token)
{
while (true)
{
// Если токен отменен, Delay выкинет OperationCanceledException и цикл прервется
await UniTask.Delay(100, cancellationToken: token);
transform.position += Vector3.forward;
}
}
private void Start()
{
// Получаем токен, который АВТОМАТИЧЕСКИ отменится при OnDestroy() этого MonoBehaviour
MoveObjectAsync(this.GetCancellationTokenOnDestroy()).Forget();
}
```
## 4. Продвинутые конструкции (Когда нужна мощь)
### Параллельное выполнение (WhenAll)
Если нужно загрузить три ресурса одновременно и подождать завершения всех:
```csharp
public async UniTask LoadLevelAsync()
{
var task1 = LoadTextureAsync();
var task2 = LoadAudioAsync();
var task3 = LoadDataAsync();
// Ждем, пока завершатся все три параллельные таски
await UniTask.WhenAll(task1, task2, task3);
Debug.Log("Всё загружено!");
}
```
### Гонка тасок (WhenAny)
Если нужно дождаться ПЕРВОГО события (например, игрок нажал кнопку ИЛИ истек таймер):
```csharp
public async UniTask WaitForInteractionAsync(CancellationToken ct)
{
var clickTask = WaitUserClickAsync(ct);
var timeoutTask = UniTask.Delay(TimeSpan.FromSeconds(5), cancellationToken: ct);
int finishedIndex = await UniTask.WhenAny(clickTask, timeoutTask);
if (finishedIndex == 0) Debug.Log("Игрок нажал кнопку!");
else Debug.Log("Игрок ничего не сделал, время вышло.");
}
```
### Таймауты
Любой метод можно ограничить по времени:
```csharp
try
{
// Если метод не завершится за 2 секунды, будет брошено исключение TimeoutException
await DownloadDataAsync().Timeout(TimeSpan.FromSeconds(2));
}
catch (TimeoutException)
{
Debug.LogError("Слишком долго!");
}
```
## 5. Многопоточность (Переключение потоков)
Unity API (например, `transform.position`, `Instantiate`) можно использовать **только в Главном Потоке (Main Thread)**.
Но если вам нужно сделать тяжелые вычисления (генерация уровня, парсинг JSON 20MB), вы можете временно "прыгнуть" в фоновый поток (Thread Pool), а затем вернуться обратно!
```csharp
public async UniTask ProcessHeavyDataAsync()
{
// Мы в главном потоке (Main Thread)
var json = Resources.Load<TextAsset>("heavy_data").text;
// ПРЫГАЕМ В ФОНОВЫЙ ПОТОК (Thread Pool)
await UniTask.SwitchToThreadPool();
// Тут нельзя трогать Unity API, но можно грузить процессор на 100%
var parsedData = Newtonsoft.Json.JsonConvert.DeserializeObject<Data>(json);
HeavyCalculations(parsedData);
// ВОЗВРАЩАЕМСЯ В ГЛАВНЫЙ ПОТОК
await UniTask.SwitchToMainThread();
// Снова можно трогать Unity API!
transform.position = parsedData.startPosition;
}
```
> [!IMPORTANT]
> Переключение потоков с помощью `UniTask` — это мощнейший инструмент оптимизации, который позволяет избавиться от фризов (лагов) при подгрузке тяжелых данных, оставляя код линейным и легко читаемым.