Размер указателя зависит от платформы, на которой указан код показателя. На 32-битных платформах размер указателя равен 4 байта, а на 64-битных — 8 байт.
Размер указателя зависит от платформы, на которой указан код показателя. На 32-битных платформах размер указателя равен 4 байта, а на 64-битных — 8 байт.
Мы знаем, что if в шейдере - плохо. На самом деле бывает плохо, а бывает и нормально. Тут зависит от условия и что мы в нем делаем. Но я предпочитаю не полагаться на компилятор, а просто не использовать if-конструкции.
Давайте разберем простой пример:
half4 color = ...; if (color.a < _Threshold) { color = float4(1, 0, 0, 1); }
Если альфа у нас меньше чем какое-то значение, то закрасим красным цветом, если больше - оставим цвет как был.
Реальный код может быть сложнее, могут быть вложенные if-конструкции и т.д.
По сути это не важно, т.к. решение будет схожим. Для простоты заменим результат работы условия на XXX, т.к. нам не важно что там будет - функция, еще одно условие или какие-то другие хитрые вычисления:
if (color.a < _Threshold) { color = XXX; }
Теперь разберемся с условием, давайте перенесем все в одну сторону:
color.a - _Threshold < 0
Теперь наша задача записать все в одну строку:
color = lerp(XXX, color, color.a - _Threshold);
Т.е. мы возьмем XXX, если значение будет ноль и оставим color, если значение будет единица.
Теперь нам нужно избавиться от этой "плавности", одним из способов это сделать - добавить 0.5 и выполнить round (можно еще +0.5 и floor):
color = lerp(XXX, color, round((color.a - _Threshold) + 0.5));
Таким образом мы избавились от условия, чего и добивались :)
public T A<T>() where T : struct { var t = new T(); ... return t; }
Вот такой код мы обычно воспринимаем как "сделать default значение и потом мы его вернем". Все бы ничего, но это не совсем так. Вот как будет выглядеть этот код:
public T A<T>() where T : struct { var t = System.Activator.CreateInstance<T>(); ... return t; }
Исправить это довольно просто:
public T A<T>() where T : struct { T t = default; ... return t; }
Используйте UnsafeList вместо NativeList где это возможно. Поясню. UnsafeList - это прямой доступ к аллоцированной памяти, а NativeList содержит в себе указатель на UnsafeList, таким образом, чтобы дойти до данных списка нужно обратиться к указателю.
Из минусов - отсутствие safety handler.
Важно: UnsafeList содержит данные о количестве элементов, т.е. относиться к этой структуре нужно как к любому ValueType (оно будет копироваться).
В принципе это касается всех коллекций.
Довольно часто мы пишем в коде подобные штуки: direction * deltaTime * 2f
Фактически мы умножаем Vector direction на float и на какой-нибудь мультипликатор, например, 2. На самом деле лучше писать вот так:
direction * (deltaTime * 2f)
Т.к. в таком случае операций умножения для вектора будет одна вместо двух.
Иногда в редакторе нужно использовать SerializedProperty у объекта, до которого просто никак не дойти. Допустим, я хочу вывести поля класса, а класс этот находится не в ScriptableObject и не в компоненте.
Для этого можно использовать простой хак:
public class Temp : ScriptableObject { [SerializedReference] public object data; } var temp = Temp.CreateInstance<Temp>(); temp.data = yourInstance; var so = new SerializedObject(temp); var prop = so.FindProperty("data");
Еще нужно не забыть убить этот Temp 🙂
Для того, чтобы ускорить выполнение кода в райнтаме при компиляции через IL2CPP, можно воспользоваться атрибутом Il2CppSetOptionAttribute:
Его не существует в Unity, поэтому его нужно объявить самостоятельно, Unity сама находит его по имени. Атрибут можно использовать для одного класса/структуры/метода несколько раз с разными значениями.
Производитель предупреждает тем, что при генерации кода C++ мы выбираем из кода лишние проверки. Можно использовать в тех местах, где мы уверены, что не будет случайного нуля или мы точно не попадем за рамки массива. Проще говоря, все исключения, на которые в обычной жизни мы никак не могли повлиять.
Я часто встречаю в различных проектах первый вариант при поиске ближайшей цели, например. Уж не знаю, почему так получается, но, наверное, люди не особо вникают в то, как это работает.
sqrMagnitude внутри: x*x + y*y + z*z
Вектор3.Расстояние внутри: sqrt(x*x + y*y + z*z)
В sqrMagnitude по результатам Пифагора мы вычисляем расстояние между точками, тут все просто.
Но когда мы можем использовать sqrMagnitude? Самое банальное: проверка расстояния, когда точка высчитывает расстояние одинаково. Получается, что корень считает, что у нас нет никаких потребностей, если нам нужно найти ближайший объект или, например, определить, находится ли юнит в радиусе для выстрела.
Если вы хотите найти ли точку в любой фигуре, вам достаточно взять любое направление и подсчитать количество пересечений с границами этой фигуры. Если чётное — значит точка лежит вне фигуры, если нечётное — внутри.
У SerializedProperty появилось boxedValue. Не во всех случаях он работает, но во всех случаях для большого числа кейсов теперь можно читать и писать нормально.
Какие протоколы мы используем?
TCP (Transmission Control Protocol) и UDP (User Datagram Protocol) - это два наиболее распространенных протокола передачи данных. Основное отличие между ними заключается в том, что TCP является протоколом, обеспечивающим надежную передачу данных, а UDP - протоколом без установления соединения и без гарантии доставки данных.
TCP обеспечивает контроль над передачей данных, используя механизмы подтверждения и повторной передачи пакетов в случае потерь или ошибок. Он также гарантирует, что данные будут доставлены в правильном порядке и без дублирования. TCP используется для передачи данных, которые требуют высокой степени надежности. Например, мы хотим передать информацию об игроке от сервера клиенту.
UDP, с другой стороны, не обеспечивает надежной передачи данных и не гарантирует их доставку. Он используется для передачи данных, которые не требуют высокой степени надежности, например, для передачи последней позиции игрока, когда нам не важно где он находился до этого.
RUDP (Reliable User Datagram Protocol) - это протокол, который сочетает в себе преимущества TCP и UDP. Он обеспечивает надежную передачу данных, как TCP, но без установления соединения, как UDP. RUDP используется для передачи данных с гарантией доставки, но не гарантирует порядок пакетов.
В случае с TCP при получении пакетов 1, 3, 4, 5, TCP отдаст только пакет 1, а остальные пакеты придержит до тех пор, пока пакет 2 не будет доставлен. Таким образом можно замечать некую «тормознутость» при использовании TCP, когда пакетов нет-нет, а потом хоп, и вдруг сразу и много. С RUDP/UDP такого не происходит.
Закончу на моей любимой шутке: я бы рассказал вам шутку про UDP, но боюсь что она до вас не дойдет.
КЭШ - это Oriented Bounding Box, это такой Rect с поворотом, но в 3D