HVoid

Полная документация

Введение

HVoid - это профессиональный инструмент для управления асинхронными операциями в Unity. Он позволяет легко:

  • Выполнять задачи в фоновых потоках

  • Работать с главным потоком Unity

  • Отменять операции

  • Отслеживать прогресс задач

  • Запускать корутины из любого потока

Преимущества HVoid:

  • Простота использования (минимальный порог входа)

  • Высокая производительность

  • Безопасная работа с потоками

  • Интеграция с жизненным циклом Unity

Установка

  1. Поместите его в папку Assets/Plugins

  2. Готово! Система автоматически инициализируется

Быстрый старт

Пример 1: Простая фоновая задача

using HVoid;
using UnityEngine;

public class SimpleExample : MonoBehaviour
{
    void Start()
    {
        // Запускаем метод в фоновом потоке
        HVoid.Background(ProcessData);
    }

    void ProcessData()
    {
        Debug.Log("Начали обработку в фоне...");
        
        // Имитируем долгую операцию
        System.Threading.Thread.Sleep(3000);
        
        // Возвращаемся в главный поток
        HVoid.Main(() => {
            Debug.Log("Обработка завершена!");
        });
    }
}

Основные функции

1. Работа с главным потоком

HVoid.Main()

Выполняет код в главном потоке Unity. Обязательно используйте для работы с Unity API.

// Обновляем UI из любого потока
HVoid.Main(() => {
    scoreText.text = "Очки: 100";
    player.transform.position = Vector3.zero;
});

// Группируем несколько операций
HVoid.Main(() => {
    EnablePlayerControls();
    UpdateHealthBar();
    PlaySoundEffect();
});

HVoid.MainAsync()

Выполняет код в главном потоке и возвращает Task для ожидания.

async void LoadGameAssets()
{
    // Показываем загрузочный экран
    await HVoid.MainAsync(() => {
        ShowLoadingScreen();
        DisableInput();
    });
    
    // Загружаем данные в фоне
    await HVoid.Background(LoadAssets);
    
    // Скрываем загрузочный экран
    await HVoid.MainAsync(HideLoadingScreen);
}

2. Фоновые задачи

HVoid.Background()

Запускает метод в фоновом потоке.

// Простой запуск
HVoid.Background(CalculateStatistics);

// С лямбда-выражением
HVoid.Background(() => {
    var result = ComplexCalculation();
    HVoid.Main(() => DisplayResult(result));
});

// С параметрами
void StartProcessing(string data)
{
    HVoid.Background(() => ProcessData(data));
}

HVoid.Background() с прогрессом

// Создаем обработчик прогресса
var progress = new Progress<float>(p => {
    loadingBar.fillAmount = p;
    percentText.text = $"{p:P0}";
});

// Запускаем задачу с прогрессом
HVoid.Background(ct => {
    for (int i = 0; i <= 100; i++)
    {
        // Проверяем отмену
        ct.ThrowIfCancellationRequested();
        
        // Имитируем работу
        System.Threading.Thread.Sleep(50);
        
        // Отправляем прогресс
        progress.Report(i / 100f);
    }
}, progress);

3. Отменяемые задачи

HVoid.CancellableBackground()

Создает задачу, которую можно отменить.

CancellationTokenSource cts;

void StartLongOperation()
{
    // Запускаем задачу с возможностью отмены
    (var task, cts) = HVoid.CancellableBackground(ct => {
        while (true)
        {
            ct.ThrowIfCancellationRequested();
            // Выполняем работу...
        }
    });
}

void CancelOperation()
{
    // Отменяем операцию
    cts?.Cancel();
}

4. Отложенные действия

HVoid.Delayed()

Выполняет действие через указанное время.

// Простая задержка
HVoid.Delayed(2.5f, () => {
    ShowTutorialMessage();
});

// С проверкой существования объекта
HVoid.Delayed(5f, () => {
    if (this != null) // Проверяем, что объект существует
    {
        Destroy(gameObject);
    }
});

Продвинутые сценарии

Пример: Загрузка данных с сервера

async void LoadPlayerProfile()
{
    try
    {
        // Показываем индикатор загрузки
        HVoid.Main(() => loadingIndicator.SetActive(true));
        
        // Загружаем данные в фоне
        var profile = await HVoid.Background(() => {
            return ServerApi.GetPlayerProfile(playerId);
        });
        
        // Обновляем UI
        HVoid.Main(() => {
            playerName.text = profile.name;
            playerAvatar.sprite = LoadAvatar(profile.avatarId);
        });
    }
    catch (Exception ex)
    {
        Debug.LogError($"Ошибка загрузки: {ex.Message}");
        HVoid.Main(() => ShowErrorPopup("Не удалось загрузить данные"));
    }
    finally
    {
        HVoid.Main(() => loadingIndicator.SetActive(false));
    }
}

Пример: Параллельная обработка

async void ProcessAllData()
{
    // Создаем задачи
    var textureTask = HVoid.Background(() => ProcessTextures());
    var audioTask = HVoid.Background(() => ProcessAudio());
    var modelTask = HVoid.Background(() => ProcessModels());
    
    // Ждем завершения всех задач
    await Task.WhenAll(textureTask, audioTask, modelTask);
    
    // Уведомляем о завершении
    HVoid.Main(() => Debug.Log("Все ресурсы обработаны!"));
}

Пример: Генерация мира

async void GenerateWorld()
{
    var progress = new Progress<GenerationStage>(stage => {
        HVoid.Main(() => UpdateGenerationProgress(stage));
    });
    
    await HVoid.Background(ct => {
        GenerateTerrain(ct, progress);
        GenerateVegetation(ct, progress);
        GenerateStructures(ct, progress);
    }, progress);
}

Лучшие практики

1. Всегда проверяйте отмену в длительных операциях

HVoid.Background(ct => {
    for (int i = 0; i < 1000000; i++)
    {
        // Регулярно проверяем токен отмены
        ct.ThrowIfCancellationRequested();
        
        // Выполняем работу...
    }
});

2. Минимизируйте вызовы главного потока

Когда что выбирать?

  1. Используйте HVoid.Main() когда:

    • Нужно просто выполнить действие на главном потоке

    • Не важно, когда именно выполнится операция

    • Делаете единичные простые операции

  2. Используйте HVoid.MainAsync() когда:

    • Нужно дождаться завершения операции

    • Работаете с async/await

    • Строите цепочки последовательных операций

    • Требуется гарантия выполнения перед продолжением кода

Производительность

  • Main() немного эффективнее для единичных операций

  • Для групповых операций лучше использовать один вызов MainAsync() вместо нескольких Main()

// Плохо: много отдельных вызовов
for (int i = 0; i < 1000; i++)
{
    HVoid.Main(() => UpdateItem(i));
}

// Хорошо: один вызов для всех операций
HVoid.Main(() => {
    for (int i = 0; i < 1000; i++)
    {
        UpdateItem(i);
    }
});

// Оптимально
await HVoid.MainAsync(() => {
    for (int i = 0; i < 1000; i++)
    {
        UpdateItem(i);
    }
});

3. Используйте async/await для цепочек задач

async void LoadGame()
{
    await LoadConfig();
    await LoadAssets();
    await InitializeSystems();
    StartGame();
}

Часто задаваемые вопросы

В: Безопасно ли использовать Unity API в фоновом потоке?

О: Нет! Все операции с Unity API должны выполняться через:

  • HVoid.Main()

  • HVoid.MainAsync()

  • HVoid.MainCoroutine()

В: Как обрабатывать ошибки в фоновых задачах?

csharpCopyDownload

try
{
    await HVoid.Background(() => {
        throw new InvalidOperationException("Тестовая ошибка");
    });
}
catch (Exception ex)
{
    Debug.LogError($"Перехвачено исключение: {ex.Message}");
    HVoid.Main(() => ShowError(ex.Message));
}

В: Как отменить все задачи при выходе из игры?

О: HVoid автоматически отменяет все задачи при завершении работы приложения.

Заключение

HVoid предоставляет мощные и простые инструменты для работы с асинхронным кодом в Unity. С его помощью вы можете:

  1. Упростить сложную многопоточную логику

  2. Улучшить производительность вашей игры

  3. Создавать плавные и отзывчивые интерфейсы

  4. Легко управлять длительными операциями

  5. Реализовывать сложные сценарии загрузки

Скачать HVoidLib

Для новичков рекомендуется начать с простых примеров из раздела "Быстрый старт", постепенно переходя к более сложным сценариям.

Last updated

Was this helpful?