Какой из этих двух кодов «лучше»? Создание локальной переменной или переменной класса?

11

Я делаю больше игр и задаю более глупые вопросы.

Надеюсь, это очень кратко. Я делаю очень простой класс, который просто перемещает объект Player, применяя силу к жесткому телу, но меня удивляет, должен ли я делать ссылку на класс на rb или просто на локальную переменную внутри Обновлять каждый кадр? (имея в виду, что он уже существует в родительском классе Monobehaviour.GameObject Unity).

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

Вот что я имею в виду, два способа, которыми я думал об этом:

public class Player : MonoBehaviour {

private void FixedUpdate()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

или же...

public class Player : MonoBehaviour {
Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void FixedUpdate()
{
    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}
Big T Larrity
источник
4
Это больше похоже на вопрос для обзора кода SE.
Orphevs
1
Вы также можете сделать свойство класса float va.
Чад
Я, вероятно, в конце концов, на самом деле буду Чадом, потому что я буду использовать его в двух методах в классе. Это был действительно простой код, чтобы задать вопрос о локальных и классовых переменных, не разбрасывая его большим количеством кода. Мне действительно нравится хранить переменные локальными (и «вне пути», как это где!), Но, конечно, я должен убедиться, что я не начинаю дублировать вещи вместо того, чтобы иметь одну переменную класса для каждой.
Big T Larrity
Фрагмент кода не является «кодом». На вопрос «какой код лучше», вы выглядите как любитель.
Майлз Рут
1
Я - любитель, так что со мной все в порядке, спасибо Майлзу
Big T Larrity

Ответы:

25

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

Это связано с тем, что более узкая область действия уменьшает количество мест в коде, в которых вы должны рассуждать об этих данных, и, таким образом, уменьшает количество мест, в которых вы можете рассуждать неправильно (что приводит к ошибкам).

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

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

Маловероятно, что издержки для каждого вызова будут значительными в этом случае, но со временем выполнение этого для многих компонентов может сложиться. Вы бы хотели применить профилировщик, чтобы быть уверенным.

Итак, подведем итог: в общем, по умолчанию все делается как можно более локальным, но в этом случае, вероятно, разумно сделать rbчлен, чтобы вы могли выполнить поиск один раз Awakeи избежать необходимости делать это каждый FixedUpdateвызов.


источник
1
спасибо, Джош, я чувствую, что было бы лучше, если бы rb инициализировался только один раз, и большое спасибо за четкое объяснение почему. Приятно знать наверняка, вы видите, что я не был на 100% уверен, что GetComponent считается инициализирующим его каждый раз или просто «ищущим» его из Monobehaviour. Но теперь я получаю это огромное спасибо за супер-быстрый полезный ответ
Big T Larrity
1
@SuperMegaBroBro GetComponent работает довольно быстро - вам будет сложно сделать любой поиск с сопоставимой скоростью. Если у вас нет данных о производительности, свидетельствующих о том, что это проблема, придерживайтесь подхода «держите вещи локально». Вы всегда можете оптимизировать это позже. См. Answers.unity.com/questions/185164/… Не забывайте, что кеширование тоже не бесплатно - если вы кешируете все GetComponentв своей игре, это, вероятно, будет чистым убытком. Мера. Определите, где оптимизация того стоит. Сосредоточьтесь на создании отличной игры :)
Luaan
1
Основная суть, которую вы должны убрать из этого ответа (что довольно неплохо), заключается в следующем: если вы хотите использовать код, который легче всего рассуждать, тестировать и гарантировать, что он не содержит ошибок, возьмите локальную переменную. Но, как всегда, нам иногда приходится жертвовать, чтобы усовершенствовать код по соображениям производительности, поэтому член класса может быть уместным (но сначала профиль, просто не делайте преждевременную оптимизацию).
Полигном
Большое спасибо, ребята, особенно Luaan, поскольку я задавался вопросом об этой проблеме "кэширования", пока я писал оригинальный вопрос (но я действительно не знал, как это сформулировать). Я, конечно, буду максимально использовать «локальный» подход. спасибо за большую помощь, как обычно, ребята.
Big T Larrity
2

Ответ Джоша Петри очень хороший - вот дополнительная точка зрения.

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

Например, если у меня есть Personкласс с waveGoodbyeметодом, возможно, у моего класса раньше не было handобъекта, и поэтому я мог бы объявить его локально в waveGoodbye. Теперь здесь очевидно, что у человека есть рука, поэтому вы можете, естественно, объявить ее членом, Personне задумываясь об этом, но проблема та же.

Если вы объявите handлокально, то позже вы можете добавить karateChopметод, который также требует руки. Это происходит, когда объявление переменных локально может стать проблематичным - потому что начинающие разработчики часто прибегают к копированию / вставке объявления, waveGoodbyeи теперь у вас одна и та же концепция, расположенная в двух местах. Любые изменения handдолжны быть изменены в обоих местах, и, таким образом, начинается ошибка муравейника .

В общем,

  1. Если вы уверены в размещении своей декларации, поместите ее туда, где это имеет смысл.

  2. Если вы не уверены в себе, то начните с локального и убедитесь, что вы проведете рефакторинг, когда получите повторное использование кода.

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

аааааа
источник
2
Кроме того, упорядоченный порядок вещей, как и у каждого, Personдолжен иметь члена, hand если он имеет отношение к приложению, часто помогает другим разработчикам (чаще всего вам через 6 месяцев) лучше понимать код. В этом случае кажется логичным иметь в Rigidbodyкачестве члена вашей группы Playerи, я бы сказал, больше, даже если это подразумевает худшую производительность. В видеоиграх это важный момент для рассмотрения, но я думаю, что в коде ясность часто важнее
alseether
1
отличные ответы спасибо ребята. Я не пытаюсь звучать как всезнайка, но все эти ответы только что подтвердили то, о чем я уже думал, так что на этот раз я очень счастлив и добился хорошего прогресса в своих играх. Прямо сейчас я делаю трехмерную футбольную игру с правильной анимацией и всем остальным, добиваясь реальных успехов: D Скоро я буду нуждаться в помощи о том, как сделать это для двух игроков, и, смею сказать, многопользовательской онлайн: D Удачи, ребята, и еще раз спасибо!
Big T Larrity