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

4.5 KiB
Raw Permalink Blame History

Полное руководство по Addressables

Система Addressables (com.unity.addressables) — это замена устаревшей папке Resources и сложным AssetBundles. Она позволяет загружать контент по текстовому адресу из любой точки (локально или с удаленного сервера), не меняя код игры.

1. Загрузка одиночных ассетов и Интеграция с UniTask

В проекте мы используем Cysharp.Threading.Tasks для превращения неудобных AsyncOperationHandle в удобные UniTask.

using UnityEngine.AddressableAssets;
using Cysharp.Threading.Tasks;
using UnityEngine;

public class AssetLoader
{
    public async UniTask<GameObject> LoadPlayerPrefabAsync()
    {
        // "PlayerPrefab" — это адрес, заданный в окне Addressables Groups
        GameObject prefab = await Addressables.LoadAssetAsync<GameObject>("PlayerPrefab").ToUniTask();
        return prefab;
    }
}

2. Инстанцирование (InstantiateAsync)

Если вам нужно загрузить префаб и сразу создать его на сцене, НЕ ИСПОЛЬЗУЙТЕ Object.Instantiate(await LoadAssetAsync()). Правильный способ — использовать Addressables.InstantiateAsync.

public async UniTask<GameObject> SpawnEnemyAsync(Vector3 position)
{
    // Загрузит префаб в память и сразу создаст его копию на сцене.
    // Addressables сам отслеживает этот объект!
    GameObject enemyInstance = await Addressables.InstantiateAsync("EnemyPrefab", position, Quaternion.identity).ToUniTask();
    
    return enemyInstance;
}

3. Reference Counting и Управление Памятью (КРИТИЧНО)

Главная проблема Addressables — утечки памяти (Memory Leaks), если не освобождать ресурсы. Система использует счетчик ссылок (Reference Counting).

  • Загрузили текстуру — счетчик = 1.
  • Загрузили ее еще раз где-то еще — счетчик = 2.
  • Вызвали Release — счетчик = 1.
  • Вызвали Release еще раз — счетчик = 0, текстура выгружена из оперативной памяти (RAM/VRAM).

Правила освобождения памяти:

Сценарий 1: Вы использовали LoadAssetAsync Если вы загрузили ассет (например, ScriptableObject настроек, AudioClip или Texture), вы обязаны вызвать Addressables.Release().

private AudioClip backgroundMusic;

public async UniTask PlayMusicAsync()
{
    backgroundMusic = await Addressables.LoadAssetAsync<AudioClip>("MenuMusic").ToUniTask();
    audioSource.PlayOneShot(backgroundMusic);
}

public void OnDestroy()
{
    // Если объект уничтожается, освобождаем память от музыки!
    if (backgroundMusic != null)
    {
        Addressables.Release(backgroundMusic);
    }
}

Сценарий 2: Вы использовали InstantiateAsync Если вы создали GameObject через Addressables, вы не должны удалять его через Destroy(gameObject). Используйте Addressables.ReleaseInstance().

public void KillEnemy(GameObject enemyInstance)
{
    // Это автоматически уничтожит GameObject на сцене И уменьшит счетчик префаба в памяти.
    // Если это был последний враг такого типа, сам префаб выгрузится из RAM.
    Addressables.ReleaseInstance(enemyInstance);
}

4. Загрузка по Меткам (Labels)

Addressables позволяет загружать списки ассетов. Например, вы можете пометить все префабы уровней меткой Level и загрузить их одним вызовом.

public async UniTask<IList<LevelData>> LoadAllLevelsAsync()
{
    // Загружает все ассеты, у которых стоит Label "Level"
    IList<LevelData> levels = await Addressables.LoadAssetsAsync<LevelData>("Level", null).ToUniTask();
    return levels;
}