← Назад к вопросам

Какие паттерны проектирования вы знаете? Приведите примеры использования в Unity.?

1.0 Junior🔥 111 комментариев
#Unity Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Знакомые паттерны проектирования в Unity

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

Основные паттерны, используемые в Unity

1. Синглтон (Singleton)

Самый распространенный, но требующий осторожного применения паттерн. Используется для глобального доступа к менеджерам и сервисам.

public class GameManager : MonoBehaviour
{
    private static GameManager _instance;
    
    public static GameManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<GameManager>();
                if (_instance == null)
                {
                    GameObject singleton = new GameObject("GameManager");
                    _instance = singleton.AddComponent<GameManager>();
                    DontDestroyOnLoad(singleton);
                }
            }
            return _instance;
        }
    }
    
    private void Awake()
    {
        if (_instance != null && _instance != this)
        {
            Destroy(gameObject);
        }
        else
        {
            _instance = this;
            DontDestroyOnLoad(gameObject);
        }
    }
    
    public void LoadLevel(int levelId) { /* ... */ }
}

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

2. Наблюдатель (Observer) и События (Events)

В Unity этот паттерн реализован через систему C# событий и UnityEvents.

public class PlayerHealth : MonoBehaviour
{
    public event Action<float> OnHealthChanged;
    public event Action OnPlayerDeath;
    
    private float _currentHealth = 100f;
    
    public void TakeDamage(float damage)
    {
        _currentHealth -= damage;
        OnHealthChanged?.Invoke(_currentHealth);
        
        if (_currentHealth <= 0)
        {
            OnPlayerDeath?.Invoke();
        }
    }
}

// В другом классе
public class UIManager : MonoBehaviour
{
    [SerializeField] private PlayerHealth _playerHealth;
    [SerializeField] private Slider _healthBar;
    
    private void OnEnable()
    {
        _playerHealth.OnHealthChanged += UpdateHealthBar;
    }
    
    private void OnDisable()
    {
        _playerHealth.OnHealthChanged -= UpdateHealthBar;
    }
    
    private void UpdateHealthBar(float health)
    {
        _healthBar.value = health / 100f;
    }
}

Преимущества: слабая связность компонентов, упрощение коммуникации между системами.

3. Состояние (State)

Критически важен для управления поведением игровых объектов, особенно AI и анимаций.

public interface IPlayerState
{
    void Enter(PlayerController player);
    void Update(PlayerController player);
    void Exit(PlayerController player);
}

public class RunningState : IPlayerState
{
    public void Enter(PlayerController player)
    {
        player.Animator.SetBool("IsRunning", true);
    }
    
    public void Update(PlayerController player)
    {
        if (!player.IsGrounded)
        {
            player.SetState(new JumpingState());
        }
        else if (player.Input.Magnitude < 0.1f)
        {
            player.SetState(new IdleState());
        }
    }
    
    public void Exit(PlayerController player)
    {
        player.Animator.SetBool("IsRunning", false);
    }
}

public class PlayerController : MonoBehaviour
{
    private IPlayerState _currentState;
    
    public void SetState(IPlayerState newState)
    {
        _currentState?.Exit(this);
        _currentState = newState;
        _currentState.Enter(this);
    }
    
    private void Update()
    {
        _currentState?.Update(this);
    }
}

4. Фабрика (Factory) и Пул объектов (Object Pool)

Часто используются вместе для оптимизации создания и переиспользования объектов.

public class ProjectilePool : MonoBehaviour
{
    [SerializeField] private GameObject _projectilePrefab;
    [SerializeField] private int _poolSize = 20;
    
    private Queue<GameObject> _projectilePool = new Queue<GameObject>();
    
    private void Start()
    {
        for (int i = 0; i < _poolSize; i++)
        {
            GameObject projectile = Instantiate(_projectilePrefab);
            projectile.SetActive(false);
            _projectilePool.Enqueue(projectile);
        }
    }
    
    public GameObject GetProjectile(Vector3 position, Quaternion rotation)
    {
        if (_projectilePool.Count == 0)
        {
            GameObject newProjectile = Instantiate(_projectilePrefab);
            newProjectile.SetActive(false);
            _projectilePool.Enqueue(newProjectile);
        }
        
        GameObject projectile = _projectilePool.Dequeue();
        projectile.transform.position = position;
        projectile.transform.rotation = rotation;
        projectile.SetActive(true);
        
        return projectile;
    }
    
    public void ReturnProjectile(GameObject projectile)
    {
        projectile.SetActive(false);
        _projectilePool.Enqueue(projectile);
    }
}

5. Команда (Command)

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

public interface ICommand
{
    void Execute();
    void Undo();
}

public class MoveCommand : ICommand
{
    private Transform _transform;
    private Vector3 _previousPosition;
    private Vector3 _newPosition;
    
    public MoveCommand(Transform transform, Vector3 newPosition)
    {
        _transform = transform;
        _newPosition = newPosition;
        _previousPosition = transform.position;
    }
    
    public void Execute()
    {
        _transform.position = _newPosition;
    }
    
    public void Undo()
    {
        _transform.position = _previousPosition;
    }
}

public class CommandManager : MonoBehaviour
{
    private Stack<ICommand> _commandHistory = new Stack<ICommand>();
    
    public void ExecuteCommand(ICommand command)
    {
        command.Execute();
        _commandHistory.Push(command);
    }
    
    public void UndoLastCommand()
    {
        if (_commandHistory.Count > 0)
        {
            ICommand command = _commandHistory.Pop();
            command.Undo();
        }
    }
}

Другие полезные паттерны в Unity:

  • Декоратор (Decorator) - для модификации поведения объектов без наследования (например, система баффов/дебаффов)
  • Стратегия (Strategy) - для переключения алгоритмов поведения (разные типы атаки, передвижения)
  • Компоновщик (Composite) - для организации иерархических структур (древовидная структура инвентаря)
  • Адаптер (Adapter) - для интеграции сторонних SDK и библиотек
  • Модель-Представление-Контроллер (MVC/MVP/MVVM) - для организации UI логики

Критические замечания по использованию:

  1. Не использовать паттерны ради паттернов - каждый паттерн должен решать конкретную проблему
  2. Синглтон может стать антипаттерном - создает глобальное состояние и усложняет тестирование
  3. Сочетать с архитектурными подходами - паттерны хорошо работают вместе с Data-Oriented Design, ECS (в Unity DOTS) и Scriptable Objects
  4. Учитывать специфику Unity - некоторые паттерны могут конфликтовать с компонентной моделью Unity

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

Какие паттерны проектирования вы знаете? Приведите примеры использования в Unity.? | PrepBro