Преобразование вызова функции в константу - PullRequest
0 голосов
/ 14 марта 2019

У нас есть переменная a, которая вычисляется с помощью функции WhatIsA() для цикла for.Значение WhatIsA известно во время компиляции.Могу ли я что-то сделать (возможно, атрибут), чтобы компилятор знал, что он может стереть переменную и поместить константы вместо всех ее ссылок?

for (int i = 0; i < 1343434; i++)
{
    int a = WhatIsA(); //retval of WhatIsA does not change after compilation, ever.
    DoSomethingWithVariableA(a);
    DooooSomethingWithVariableA(a);
    DoooooooSomethingWithVariableA(a);
}

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

private void Update()
{
    LayerMask mask = LayerMask.GetMask("Terrarin");
    CollidesBottom = Raycast((Vector2)transform.position + colliderBottomLeftOffset, Vector2.right, colliderWidth, mask);
    CollidesTop = Raycast((Vector2)transform.position + colliderTopRightOffset, Vector2.left, colliderWidth, mask);
    CollidesRight = Raycast((Vector2)transform.position + colliderTopRightOffset, Vector2.down, colliderHeight, mask);
    CollidesLeft = Raycast((Vector2)transform.position + colliderBottomLeftOffset, Vector2.up, colliderHeight, mask);
}

GetMask - известное время компиляции, или, по крайней мере, так и должно быть.Компилятор может или не может оптимизировать его.Единственное, что я могу сделать сам, это, возможно, поднять маску до переменной поля и вычислить ее в функции Start, но тогда ее область действия будет больше, чем нужно.

Ответы [ 2 ]

0 голосов
/ 15 марта 2019

Вы можете взглянуть на эту ветку , чтобы получить более подробные объяснения того, как именно работают LayerMasks.

Вкратце: LayerMask в основном является значением типа int. Он представляет собой двоичную 32-битную систему флагов, в которой вы включаете (1) и выключаете (0) определенные индексы уровня. Так, например значение

0000 0000 0000 0000 0000 0000 0000 0101
                                    | |
                                    | |layer1
                                    |
                                    |layer3

означает, что layer1 и layer3 должны быть включены и в десятичном формате имеют значение 5.


Конечно, есть варианты сделать эту маску постоянной. Простейшим способом будет один раз вывести

LayerMask mask = LayerMask.GetMask("Terrarin");
Debug.Log(mask.value);

, который даст вам десятичное представление маски слоя. И чем вы можете просто использовать

// 256 e.g. is the layer9
// the first entry after Unity's 8 default layers
LayerMask mask = 256;

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

LayerMask mask = 1 << 9;

Или используйте эти Двоичные -> Десятичный преобразователь & Десятичный -> Двоичный преобразователь


Конечно, вы можете сделать это только в Update, но зачем создавать его каждый кадр? Если вы все равно жестко закодируете его, вы можете использовать const или, как сказано в другом ответе, просто получить значение один раз в Awake.

Я тоже не понимаю твоих опасений по поводу "объема". Пока это остается частным, это не имеет значения

.. наоборот: ваше решение Update выделяет и уничтожает mask снова и снова -> больше работы для GC.


Однако я бы НЕ рекомендовал это!

Это очень плохой дизайн по двум причинам:

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

  2. Это делает ваш код на 0% гибким и пригодным для повторного использования! Представьте, что теперь у вас закончена система Raycaster. Теперь вы хотите, чтобы другой объект в сцене просвечивал другой слой ... Итак, вы бы предпочли скопировать весь сценарий, просто чтобы изменить жестко закодированный слой (я надеюсь, что нет), или вы бы предпочли использовать тот же сценарий и просто изменить слой значение.

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

[SerializeField] private LayerMask mask = 256;

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

0 голосов
/ 14 марта 2019

Установите a внутри Start() или Awake() и укажите переменную.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...