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

Цель

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

Модульность

Для модульной системы включения нам нужна система идентификации, чтобы можно было идентифицировать каждое включение. Вы можете использовать либо переменную типа данных int, либо, в моем случае, перечисление. Перечисления предоставляют строку для идентификации объекта, но также присваивают значение за именем.

public enum PowerupType 
{ 
    None, // 0 
    TripleShot, // 1
    Speed, // 2
    Shield // 3
}

Мне нужно использовать перечисление в сценарии Powerup, чтобы мы могли назначить тип предмету коллекционирования. Таким образом, мы можем инициализировать переменную типа PowerupType и объявить ее с типом PowerupType.None по умолчанию.

[SerializeField] private PowerupType _powerupType = PowerupType.None;

Это позволит нам выбрать тип включения в инспекторе.

Теперь мы можем использовать оператор switch для проверки отдельных функций бонусов.

 private void OnTriggerEnter2D(Collider2D other)
 {
    if (other.CompareTag(“Player”))
    {
       var player = other.transform.GetComponent<Player>();
       if(player != null)
       {
          switch (_powerupType)
          {
             case PowerupType.TripleShot:
                 player.TripleShotActive();
                 break;
             case PowerupType.Speed:
                 player.SpeedBoostActive();
                 break;
             case PowerupType.Shield:
                 player.ShieldActive();
                 break;
             default:
                 _powerupType = PowerupType.None;
                 break;
          }
       }
       Destroy(gameObject);
    }
 }

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

Рефакторинг

Вот функция, которая нуждается в рефакторинге:

private IEnumerator SpawnPowerUpRoutine()
{
    while (!_stopSpawning)
    {
        float randomX = Random.Range(-11, 11);
        Vector3 randonXposition = new Vector3(randomX, 8, 0);
        Instantiate(_tripleShotPrefab, randonXposition, Quaternion.identity);
        float randomTime = Random.Range(6, 20);
        yield return new WaitForSeconds(randomTime);
    }
}

Как видите, жирным шрифтом выделено только одно усиление.

Мне нужно изменить _tripleShotPrefab на массив GameObjects.

Массив — это фиксированный список, размер которого не может измениться во время работы игры. Он должен иметь длину при определении и не может быть изменен. Он является частью семейства коллекций C#, наряду со списком, словарем, очередью и стеком.

Я изменил переменную _tripleShotPrefab на это:

[SerializeField] private GameObject[] _powerupPrefabs = null;

Теперь он принимает набор GameObject, и мы, программисты или дизайнеры, можем настроить количество игровых объектов, которые он может хранить в инспекторе.

Теперь я должен изменить то, как мы создаем бонусы.

В функции SpawnPowerUpRoutine() мне нужно изменить переменную _tripleShotPrefab на _powerupPrefabs[]. Компилятор выдаст нам ошибку.

_powerupPrefabs[] нужно значение в нижнем индексе (скобки). Помните, я хочу, чтобы наша система повышения мощности была модульной. Итак, давайте создадим локальный тип данных int, который может рандомизировать длину нашего массива _powerupPrefabs.

int randomPowerup = Random.Range(0, _powerupPrefabs.Length);

Переменная randomPowerup будет содержать случайное число из числа включений, которые мы храним в массиве _powerupPrefabs. Это позволит случайным образом создавать все бонусы.

private IEnumerator SpawnPowerUpRoutine()
{
    while (!_stopSpawning)
    {
        float randomX = Random.Range(-11, 11);
        Vector3 randonXposition = new Vector3(randomX, 8, 0);
        int randomPowerup = Random.Range(0, _powerupPrefabs.Length);
        Instantiate(_powerupPrefabs[], randonXposition, Quaternion.identity);
float randomTime = Random.Range(6, 20);
        yield return new WaitForSeconds(randomTime);
    }
}

Мне нужно передать randomPowerup в нижний индекс _powerupPrefabs внутри функции Instantiate().

private IEnumerator SpawnPowerUpRoutine()
{
    while (!_stopSpawning)
    {
        float randomX = Random.Range(-11, 11);
        Vector3 randonXposition = new Vector3(randomX, 8, 0);
        int randomPowerup = Random.Range(0, _powerupPrefabs.Length);
        Instantiate(_powerupPrefabs[randomPowerup], randonXposition, Quaternion.identity);
float randomTime = Random.Range(6, 20);
        yield return new WaitForSeconds(randomTime);
    }
}

Закончив рефакторинг, я могу вернуться в Unity, щелкнуть игровой объект Spawn Manager, к которому прикреплен скрипт SpawnManager, и назначить наши префабы массиву _powerupPrefabs в инспекторе.

Перетащите бонусы в массив, и готово!

Теперь у нас есть модульная система усиления!

Вывод

Используя массив, я разбиваю на модули систему, которая могла бы быть запутанной с операторами if и else. Я поражен тем, насколько эффективным и чистым стало это небольшое изменение.

Следующим усилением, которое нужно реализовать, будут щиты!

Это все на сегодня. Спасибо за чтение!