Unity: Всё, что вы не знали о разработке – Telegram
Unity: Всё, что вы не знали о разработке
1.74K subscribers
40 photos
101 links
Авторский канал о разработке в Unity от Alex Silaev (CTO в Zillion Whales). Mushroom Wars 2 моих рук дело.
Рассказываю об интересный кейсах, делюсь лайфхаками, решениями.
Download Telegram
Всем привет!
Меня зовут Алекс Силаев и последние 15 лет я занимаюсь разработкой в Unity. До этого была backend-разработка, БД и прочие интересные штуки.

В данный момент занимаю позицию CTO в компании Zillion Whales (основной проект Mushroom Wars).

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

Основная тема - C# и Unity.

Мой github: http://github.com/chromealex
👍7🐳2
А знаете ли?
В C# строки хранятся в памяти в единственном экземпляре. Называется интернирование. Код
if (str1 == “something” || str2 == “something”)
не будет создавать 2 строки, а будет использовать ссылку на один и тот же объект (да, строка - это Reference Type).

#strings
👍18🥱6👎3🤯3💩1
А знаете ли?
Чтобы атомарно изменить значение переменной можно использовать lock, но это один из самых долгих способов. Гораздо быстрее использовать Interlocked методы. В некоторых случаях (в хот частях) лучше вообще обходиться без синхронизаций между потоками.

#threading
👍7💩2🥱1
Для сравнения Unity Object с null можно использовать конструкцию if (obj is null) вместо if (obj == null). А еще если obj - это Unity Object, то оператор == перегружен и проверяет не только фактический null на стороне C#, но и объект на стороне C++. Тот же эффект достигается при использовании ReferenceEquals.

#code
👍14🥱2💩1
Вы можете написать метод GetEnumerator в любой структуре или классе, это позволит использовать конструкцию foreach. Но есть несколько моментов, которые стоит понимать:
* Результат метода должен вернуть структуру или объект, в котором есть метод MoveNext и свойство Current;
* При использовании интерфейса IEnumerable (например, в List<>) при любом использовании foreach или GetEnumerator значение будет запаковано (boxing) и избежать этого уже никак не выйдет.

#code #foreach
👍6💩1🥱1
🥕Ну и задачка, пишите ответы в комменты;)

Что означает конструкция a = *(val1 + val2);?

1. Это не будет компилироваться;
2. Это же простое умножение, можно записать как a = a * (val1 + val2);
3. Это будет работать только в unsafe, двигаем val на index (на сколько - зависит от типа val), получаем данные по указателю;
4. Встречал такое, но точно не знаю как это работает;
5. Свой вариант.

#unsafe
👍8
Можно вызывать internal методы из других assembly, но для этого нужно разрешить другим assembly видеть эти методы. Для этого нужно написать аттрибут InternalsVisibleTo с указанием имени assembly, которая будет видеть internal-методы.
[assembly: InternalsVisibleTo("Friend.Assembly.Name")]

#assembly
👍17🥱3💩1🤨1
🥕Задачка
Вы наверняка знаете, что можно сделать static constructor. Для этого нужно просто написать static MyClass() и сделать там свои грязные делишки.
Но иногда хочется получить static destructor у этого же класса.
На практике я с таким столкнулся, когда в конструкторе я выделял память, которую нужно было где-то удалять.
Вопрос знатокам: каким образом вы бы решили такую проблему? Попробуйте не гуглить;) Своим решением поделюсь чуть позже.
👍5😢1
При сериализации структур в бинарь можно использовать подход *(T*)ptr = value, где ptr - указатель на массив byte, а value - данные, которые мы хотим туда записать. Если вы используете managed массив, то не забудьте использовать fixed.

#unsafe
👍3
Всем привет! Я хотел бы проводить общие созвоны раз в неделю, чтобы пообщаться, рассказать о каких-нибудь проблемах, найти решение.
В какое время и в какой день вам было бы удобно это?
В комментах будет опрос про время.
Final Results
8%
Понедельник
8%
Вторник
4%
Среда
4%
Четверг
9%
Пятница
47%
Суббота
21%
Воскресенье
Метод Array.Resize не проверяет размер массива в сторону уменьшения. То есть всегда будет выделен массив необходимого размера на выходе.

#code
👍7🤡4
Если у вас в проекте есть много skinnedmesh анимаций (например, у вас по лесу бегает много животных), то их анимации можно запечь в текстуру, откуда читать шейдером. Такие анимации будут работать довольно с сильной погрешностью, но для объектов окружения этого может быть вполне достаточно. Такое решение намного производительнее, т.к. работает с одной текстурой и укладывается в один DrawCall.

#animations #rendering #shaders
👍10👌1🤡1😨1
Партиклы можно использовать в качестве рендера своих спрайтов. Для этого нужно вызвать var count = particleSystem.GetParticles(particlesArr);
изменить массив и вызвать
particleSystem.SetParticles(particlesArr, count);
Таким образом можно контролировать тысячи частиц.

На практике мы с таким столкнулись, когда нам нужно было отрисовать 4 тысячи юнитов на экране телефона, при этом каждый юнит имел по 4 спрайта, т.е. 16к спрайтов на одном экране старенького андроида в 2015м году. Тогда юнити еще толком не умела нормально контролировать партиклы и пришлось писать свои партиклы на плюсах, что повлекло за собой боль с поддержкой этого кода под все платформы (а это были PS4/XBOXONE/Switch/iOS/Android/PC(x86/x64).
И да, в итоге юнити доделали партиклы и мы с радостью избавились от этого кода, но осадочек то остался 😉

#particles #code #rendering
👍13🗿21