Pull to refresh

Системы событий в Unity3D

Reading time5 min
Views32K
Доброго времени суток!

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

Разбирать все это дело мы будем на примере системы управления звуком. Данная система будет позволять нам включать/отключать музыку и звуки в настройках игры.

Прежде чем мы создадим класс-менеджер, который будет управлять настройками звука и музыки, мы создадим простой сериализуемый класс. Он будет использоваться в качестве модели данных для сохранения в JSON.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//=============================================
//    AudioSettingsModel
//    @usage model for audio settings
//
//    Developed by CodeBits Interactive
//    https://cdbits.net/
//=============================================
[System.Serializable]
public class AudioSettingsModel
{
    public bool music = true; // Флаг, отвечающий за музыку
    public bool sounds = true; // Флаг, отвечающий за звуки
}

Теперь можно приступить к написанию класса-менеджера. Его мы будем устанавливать на самой первой сцене. Данный менеджер будет глобальным объектом и не будет удаляться при переходе со сцены на сцену.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;

//=============================================
//   Audio Manager
//   @usage works with audio settings
//
//   Developed by CodeBits Interactive
//   https://cdbits.net/
//=============================================
[AddComponentMenu("Game Managers/Audio Manager")]
public class AudioManager : MonoBehaviour{
    // Публичные параметры
    public static AudioManager instance = null; // Инстанс менеджера
    public static AudioSettingsModel settings = null; // Модель аудио настроек
    private static string _settings_path = ""; // Путь к файлу настроек аудио

    // Инициализация менеджера
    void Awake(){
        // Устанавливаем путь для сохранения настроек
        _settings_path = Application.persistentDataPath + "/audioSettings.gdf";

        // Проверяем, задан ли инстанс нашего менеджера
        if (instance == null){ // Инстанс не задан
            instance = this; // Установить в инстанс текущий объект
        }

        // Устанавливаем параметр, который указывает на то,
        // что данный объект не должен удаляться при выгрузке
        // уровня
        DontDestroyOnLoad(gameObject);

        // Инициализируем настройки нашего менеджера
        InitializeSettings();
    }

    // Инициализация менеджера
    private void InitializeSettings(){
        // Если модель настроек не задана
        if (settings == null) settings = new AudioSettingsModel(); // Создаем новую модель
        if (File.Exists(_settings_path)){ // Если существует файл с настройками
            loadSettings(); // Загружаем файл настроек звука
        }
    }

    // Загрузить аудио настройки
    public void loadSettings(){
        string _data = File.ReadAllText(_settings_path); // Считываем весь текст из файла
        settings = JsonUtility.FromJson<AudioSettingsModel>(_data); // Десериализуем его в текущую модель
    }

    // Сохранить аудио настройки
    public void saveSettings(){
        string _json_data = JsonUtility.ToJson(settings); // Сериализуем текущие настройки из модели
        File.WriteAllText(_settings_path, _json_data); // Сохраняем в наш файл
    }

    // Создаем делегаты для нашего события, которое в дальнейшем
    // будет использоваться для отслеживания изменений настроек аудио
    public delegate void AudioSettingsChanged(); // Добавить новый делегат
    public event AudioSettingsChanged OnAudioSettingsChanged; // Создать на его основе событие

    // Включить/выключить звуки
    public void toggleSounds(bool enabled){
        settings.sounds = enabled; // Изменить настройки звуков в текущей модели
        saveSettings(_settings_path, settings); // Сохранить настройки
        if (OnAudioSettingsChanged != null) OnAudioSettingsChanged(); // Вызвать наше событие
    }

    // Включить/выключить музыку
    public void toggleMusic(bool enabled){
        settings.music = enabled; // Изменить настройки музыки в текущей модели
        saveSettings(_settings_path, settings); // Сохранить настройки
        if (OnAudioSettingsChanged != null) OnAudioSettingsChanged(); // Вызвать наше событие
    }
}

Теперь, когда менеджер готов, вы можете создать на вашей начальной сцене пустой объект и назвать его, к примеру "_AUDIO_MANAGER", после чего добавить на него наш класс-менеджер. Сделать это можно просто вызвав меню добавления компонента на объекте и выбрав «Game Managers» => «Audio Manager».

После этого, нам необходимо написать компонент, который мы будем пристыковывать к каждому объекту с AudioSource.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//=============================================
//    Audio Muter
//    @usage on/off audio sources on objects
//
//    Developed by CodeBits Interactive
//    https://cdbits.net/
//=============================================
[AddComponentMenu("Audio/Audio Muter Component")]
public class AudioMuter : MonoBehaviour {
    // Публичные параметры компонента
    public bool is_music = false; // Данный флаг дает понять нашему классу, является ли AudioSource звуком или музыкой.

    // Приватные параметры
    private AudioSource _as; // AudioSource
    private float _base_volume = 1F; // Базовая громкость AudioSource

    // Инициализация объекта
    void Start(){
        // Получаем компонент AudioSource и его изначальную громкость
        _as = this.gameObject.GetComponent<AudioSource>(); // Получить компонент
        _base_volume = _as.volume; // Получить базовую громкость

        // Здесь мы добавляем слушатель, который будет выполнять метод _audioSettingsChanged,
        // когда настройки музыки/звуков были изменены
        AudioManager.instance.OnAudioSettingsChanged += _audioSettingsChanged; // Установить

        // Ну и на старте мы должны проверить текущее состояние звуков/музыки
        _audioSettingsChanged();
    }

    // При уничтожении объекта
    void OnDestroy(){
        AudioManager.instance.OnAudioSettingsChanged -= _audioSettingsChanged; // Уничтожаем слушатель
    }

    // Данный метод служит для включения/отключения громкости AudioSource
    private void _audioSettingsChanged(){
        if (is_music)
            _as.volume = (AudioManager.settings.music) ? _base_volume : 0F;
        if (!is_music)
            _as.volume = (AudioManager.settings.sounds) ? _base_volume : 0F;
    }
}

Таким образом мы можем управлять звуками/музыкой в игре. Данный пример не в коем случае не говорит, как следует делать это правильно, а лишь демонстрирует работу системы событий и слушателей в Unity3D.

И напоследок хочется поговорить о том, что мы сейчас использовали. В примере ниже, был объявлен делегат, из которого был создан слушатель:

public delegate void AudioSettingsChanged();
public event AudioSettingsChanged OnAudioSettingsChanged;

Вы можете установить выполнение слушателя при определенных условиях и цеплять к ним определенные методы, которые будут выполняться при достижении этих условий.

А при помощи делегатов, на основе которого мы создали слушатель, вы можете создавать Callback-функции. Особенно полезно это может быть для асинхронных методов (к примеру при отправке асинхронных POST-запросов).

Надеюсь, вам пригодится мой небольшой опыт в этом деле и вы сможете применить данный пример для своих проектов. Также буду рад ответить на ваши вопросы (если кому-то что-то непонятно).
Tags:
Hubs:
Total votes 8: ↑6 and ↓2+4
Comments6

Articles