Обертка для Invoke

API Unity часто подталкивает программистов к плохой практике хардкода имен функций. Один из таких скользких путей это использование функции Invoke у класса MonoBehaviour (Invoke, CancelInvoke, IsInvoking, InvokeRepeating).

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

public void Start()
{
    Invoke("ShowPanel", 2f);
}

private void ShowPanel()
{
    //show panel there
}

Или есть необходимость создавать игровой объект (пулю из пистолета, монстра, выбегающего из-за угла и т.п.) регулярно с определенной периодичностью. Например, через секунду после старта уровня первый раз и каждые три секунды следующий:

public void Start()
{
    InvokeRepeating("SpawnMonster", 1f, 3f);
}

private void SpawnMonster()
{
    //Spawn monster there
}

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

Попробуем решить эту проблему, используя возможности языка C# и написать обертки для функций Invoke и ко.:Для начала напишем метод, который достает имя функции из лямбда выражения, вызывающего эту функцию:

private string GetMethodName(Expression expr)
{
    return ((MethodCallExpression) expr.Body).Method.Name;
}

После чего, напишем обертку для функции Invoke, которая принимает на вход не имя функции, а лямбду, вызывающую функцию, достает из лямбды имя и вызывает встроенную в Unity функцию Invoke:

protected void Invoke(Expression expr, float time)
{
    Invoke(GetMethodName(expr), time);
}

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

public void Start()
{
    Invoke(() => ShowPanel(), 2f);
}

private void ShowPanel()
{
    //show panel there
}

и

public void Start()
{
    InvokeRepeating(() => SpawnMonster(), 1f, 3f);
}

private void SpawnMonster()
{
    //Spawn monster there
}

Теперь, любое переименование функции во время рефакторинга приведет к ошибке компиляции либо будут переименованы все вызовы функций автоматически утилитами рефакторинга, если используете такие.Обертки для всех Invoke функций можно взять тут: MonoBehaviourBase.csСпасибо за внимание!

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments