Unity: Всё, что вы не знали о разработке
Открыть в Telegram
Авторский канал о разработке в Unity от Alex Silaev (CTO в Zillion Whales). Mushroom Wars 2 моих рук дело. Рассказываю об интересный кейсах, делюсь лайфхаками, решениями.
Больше1 774
Подписчики
Нет данных24 часа
Нет данных7 дней
-730 день
Загрузка данных...
Похожие каналы
Облако тегов
Нет данных
Возникли проблемы? Пожалуйста, обновите страницу или обратитесь к нашему support-менеджеру .
Входящие и исходящие упоминания
---
---
---
---
---
---
Привлечение подписчиков
май '26
май '26
+10
в 0 каналах
апрель '26
+20
в 0 каналах
Get PRO
март '26
+26
в 0 каналах
Get PRO
февраль '26
+38
в 0 каналах
Get PRO
январь '26
+28
в 0 каналах
Get PRO
декабрь '25
+29
в 0 каналах
Get PRO
ноябрь '25
+18
в 0 каналах
Get PRO
октябрь '25
+45
в 0 каналах
Get PRO
сентябрь '25
+46
в 0 каналах
Get PRO
август '25
+41
в 1 каналах
Get PRO
июль '25
+35
в 0 каналах
Get PRO
июнь '25
+48
в 0 каналах
Get PRO
май '25
+48
в 0 каналах
Get PRO
апрель '25
+49
в 1 каналах
Get PRO
март '25
+50
в 1 каналах
Get PRO
февраль '25
+42
в 0 каналах
Get PRO
январь '25
+39
в 1 каналах
Get PRO
декабрь '24
+27
в 1 каналах
Get PRO
ноябрь '24
+61
в 0 каналах
Get PRO
октябрь '24
+44
в 1 каналах
Get PRO
сентябрь '24
+21
в 0 каналах
Get PRO
август '24
+30
в 0 каналах
Get PRO
июль '24
+32
в 0 каналах
Get PRO
июнь '24
+40
в 0 каналах
Get PRO
май '24
+48
в 0 каналах
Get PRO
апрель '24
+53
в 0 каналах
Get PRO
март '24
+32
в 0 каналах
Get PRO
февраль '24
+81
в 2 каналах
Get PRO
январь '24
+78
в 0 каналах
Get PRO
декабрь '23
+67
в 0 каналах
Get PRO
ноябрь '23
+28
в 0 каналах
Get PRO
октябрь '23
+46
в 0 каналах
Get PRO
сентябрь '23
+73
в 0 каналах
Get PRO
август '23
+59
в 0 каналах
Get PRO
июль '23
+907
в 0 каналах
| Дата | Привлечение подписчиков | Упоминания | Каналы | |
| 31 мая | 0 | |||
| 30 мая | +2 | |||
| 29 мая | 0 | |||
| 28 мая | 0 | |||
| 27 мая | 0 | |||
| 26 мая | 0 | |||
| 25 мая | +1 | |||
| 24 мая | +1 | |||
| 23 мая | +1 | |||
| 22 мая | +1 | |||
| 21 мая | 0 | |||
| 20 мая | 0 | |||
| 19 мая | 0 | |||
| 18 мая | 0 | |||
| 17 мая | +1 | |||
| 16 мая | +1 | |||
| 15 мая | 0 | |||
| 14 мая | 0 | |||
| 13 мая | 0 | |||
| 12 мая | 0 | |||
| 11 мая | 0 | |||
| 10 мая | 0 | |||
| 09 мая | 0 | |||
| 08 мая | +1 | |||
| 07 мая | 0 | |||
| 06 мая | 0 | |||
| 05 мая | +1 | |||
| 04 мая | 0 | |||
| 03 мая | 0 | |||
| 02 мая | 0 | |||
| 01 мая | 0 |
Посты канала
Век живи - век учись
Я вот только сегодня узнал, что оказывается можно писать не только так:
var str = $"{value}";
А еще и вот так:
var str = $$"""{{value}}""";
Или вот так:
var str = $$$"""{{{value}}}""";
Или проще говоря, от количества $ символов зависит количество скобочек. В целом довольно удобно иногда может быть.
Я вот обнаружил это только сейчас, т.к. мне всегда хватало и одного $.
#csharp #strings| 2 | Overlay
У юнити, начиная с 2022.2 появилась возможжность рисовать свой окна в SceneView, при этом не прибегая к костылям вида "подпишусь на колбэк GUI, потом нарисую хрен пойми где хрен пойми как".
UnityEditor.Overlays.Overlay - позволяет это сделать очень просто и легко.
[Overlay(typeof(SceneView), "YourUniqueId", "Caption", defaultDisplay = true)]
public class YourOverlay : Overlay {
public override VisualElement CreatePanelContent() {
return new Label("Test");
}
}
В целом довольно удобно, когда нужны какие-то настройки объектов на сцене, раньше приходилось руками рисовать, а сейчас удобная тулза.
#unity #editor #sceneview | 0 |
| 3 | Удобное API
Вы наверняка сталкивались с такой проблемой:
void Method<T>(System.Action<T> callback) {...}
То есть мы хотим вызвать метод, который вернет нам колбэк в какой-то момент. Например, что действие завершено. Все вроде хорошо, но если мы начнем это использовать, то сталкнемся с другой проблемой:
Method<MyObj>(static (obj) => {
// И вот тут нам явно не хватает данных при static
});
Отсюда 2 выхода: либо мы используем аллокации при замыкании, либо реализуем некий второй параметр, в который мы сможем положить любые данные:
void Method<T1, T2>(T1 t1, System.Action<T1, T2> callback) {...}
С точки зрения метода будем считать, что T1 - это замыкание, которое мы передаем в метод:
Method<int, MyObj>(123, static (closure, obj) => { ... });
Вроде уже неплохо, но что если у нас вместо простого int будет что-то сложнее, например, кортеж ValueTuple:
Method<ValueTuple<int, int>, MyObj>((123, 234), static (closure, obj) => { ... });
Выходит уже неприятно, а если представить, что это мы захотим передать несколько параметров разных своих типов, то будет прям совсем нечитаемо.
И тут тоже есть элегантное решение:
struct ClosureAPI<TClosure> {
public TClosure data;
public MyContainer container;
public Method<T>(System.Action<T, TClosure> callback) {
this.container.Method(this.data, callback);
}
}
ClosureAPI<TClosure> Closure<TClosure>(TClosure data) {
return new ClosureAPI<TClosure>() {
data = data,
container = this,
};
}
void Method<T1, T2>(T1 t1, System.Action<T1, T2> callback) {...}
Таким образом снаружи это будет выглядеть как:
container.Closure((123, 234)).Method<MyObj>(static (data, obj) => { ... });
Вот таким образом мы избавляемся от необходимости указывать дженерик тип, который используем.
Естественно, если вы передаете все инстансы в метод, то вам не нужно указывать типы, но если (как в примере выше) у вас тип передаете только как дженерик, то такой подход избавит от необходимости указывать дженерик замыкания.
#zeroalloc #architecture #code | 0 |
| 4 | Простые лайфхаки
Часто встречаю в разных проектах подобные конструкции (на самом деле обычно они страшнее, но я убрал все лишнее):
var result = false;
if (Method1() == true) result = true;
if (Method2() == true) result = true;
if (Method3() == true) result = true;
...
return result;
На самом деле этот код можно записать проще:
var result = false;
result |= Method1();
result |= Method2();
result |= Method3();
...
return result;
Аналогично можно делать и обратную историю:
var result = true;
result &= ...
В целом подобных штук можно найти немало, которые сэкономят время и приведут код с красивому и читаемому виду.
#lifehack #basics #code | 0 |
| 5 | Довольно интересная задачка попалась на собеседовании в гугле:
Есть матрица (массив массивов) вида
[
[1, 0, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 1],
[0, 0, 1, 0, 1, 0],
[1, 0, 0, 0, 1, 0],
[1, 0, 1, 1, 0, 0],
[1, 0, 0, 0, 0, 1]
]
Нужно реализовать метод, который найдет все острова. Островом считаются 1, которые не примыкают к границам. Диагонали не считаются за соединения.
То есть на выходе должна быть матрица такого вида:
[
[0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0]
]
Как вы бы решали такую задачу?
Доп вопросы:
- Возможно ли решить задачу без аллоцирования памяти? (Стэк константного размера не считается)
- Какая минимально возможная сложность по времени (О-нотация)?
#interview #task #algorithms | 0 |
| 6 | Unity.Profiling.IgnoredByDeepProfilerAttribute
Аттрибут, который спасет вам время, если у вас много кода, который вы точно не хотели бы видеть в профайлере.
#attributes #profiling #unity | 0 |
| 7 | Рукожопы (других слов нет) выпустили апдейт юнити, в котором отломали uitk в инспекторе.
Так что ждем хотфикс, а пока (если у вас вдруг ломается инспектор) можно отключить uitk и использовать imgui:
Project Settings -> Editor -> use IMGUI
#editor #unity | 0 |
| 8 | Всем привет ;)
Как вы могли заметить, в этом канале нет рекламы, продажи курсов и подобных историй. Так будет продолжаться и дальше.
Но я хотел бы предложить свои услуги в качестве консультаций в частном порядке, то есть мы разберем вашу проблему и найдем оптимальное для нее решение. Готов помочь с любыми проблемами на ваших текущих проектах или просто подтянуть знания по какой-то теме.
Оплата по договоренности.
Пишите в личку: @chromealex | 0 |
| 9 | NoAlias
Этот аттрибут используется для Burst и позволяет экономить на инструкциях.
Например:
int Method(ref int a, ref int b) {
b = 13;
a = 42;
return b;
}
В данном случае Burst не знает, пересекаются ли данные a и b (хранятся ли в памяти в одном месте или нет.
То есть тут будет 3 инструкции mov, 2 для установки значения, а третья - для чтения этого значения. Если же добавить аттрибут NoAlias, возврат данных будет без дополнительной загрузки:
int Method([NoAlias] ref int a, ref int b) {
b = 13;
a = 42;
return b;
}
Аттрибут можно использовать для NativeArray (контейнеров), которые не пересекаются, и в качестве возврата из методов [return: NoAlias]. При этом это имеет смысл, если метод не заинлайнен, т.к. при инлайне аттрибут не будет иметь смысла.
#noalias #burst #code | 0 |
| 10 | ResourcesAPI
В юнити 6.2 появилась классная штука, которая позволяет переопределить дефолтные методы загрузки ресурсов. И это круто, если подобным образом они будут развиваться и дальше, то когда-нибудь можно будет переписать весь движок 🙂
https://docs.unity3d.com/6000.2/Documentation/ScriptReference/ResourcesAPI.html
#unity #api #resources | 0 |
| 11 | Unity.Mathematics
На самом деле многие не поняли зачем им использовать Unity.Mathematics, если у них есть Vector2/Vector3 и Mathf, например.
Давайте разберем самый простой пример:
var a = 10;
var b = 20;
var c = 30;
var result = a * b + c; // Считаем результат
У Unity.Mathematics есть math.mad, который внутри делает тоже самое:
void mad(int a, int b, int c) => a * b + c;
И самая большая ошибка считать, что никакой разницы в коде не будет. А работает это так: при компиляции кода, вызов math.mad мапится напрямую на simd-инструкцию, то есть код превращается из 2х инструкций в одну.
Пример с math.mad - это лишь пример того, где вы можете сэкономить, в целом есть всякие select еще, которые тоже все избегают использовать.
#unity #simd #math | 0 |
| 12 | Player Loop
Вместо MonoBehaviour на сцене можно использовать инжект в текущий луп. Для этого нужно понимать в какой именно мы хотим добавить вызов своего метода. Всего есть 8 групп:
TimeUpdate = 0
Initialization = 1
EarlyUpdate = 2
FixedUpdate = 3
PreUpdate = 4
Update = 5
PreLateUpdate = 6
PostLateUpdate = 7
Использовать проще всего с инжектом при инициализации, но в принципе можно вызывать этот код когда угодно, как и удалять свою систему из обработки:
[RuntimeInitializeOnLoadMethod]
static void Inject() {
var loop = PlayerLoop.GetCurrentPlayerLoop();
var sys = new PlayerLoopSystem {
type = typeof(YourClassName),
updateDelegate = () => Debug.Log("Custom Update")
};
var index = 4; // PreUpdate (см список выше)
loop.subSystemList[index].subSystemList = loop.subSystemList[index].subSystemList.Append(sys).ToArray();
PlayerLoop.SetPlayerLoop(loop);
}
#unity #playerloop | 0 |
| 13 | CallerFilePathAttribute
Этот аттрибут позволяет получить путь к файлу, из которого происходит вызов метода:
private static void Sample(CallerFilePath] string file = null) {
UnityEngine.Debug.Log(file);
}
Еще обратите внимание, что есть CallerMemberName (из какого метода вызов) и CallerLineNumber (на какой строке).
#debug #csharp #code | 0 |
| 14 | https://youtu.be/GUVi04UCKsQ
Поговорили про AI, какие основные алгоритмы используют для этого, что из себя представляют, где что использовать
#streams #ai | 0 |
| 15 | https://youtu.be/TilgB9G1G3g
Когда-то давно я показывал видео про наброски rts, в этом видео рассматривается основная механика построения деревьев и поиск данных в них. На ее основе можно строить физику, коллизии, RVO, поиск целей и множество других интересных вещей.
#becs #trees | 0 |
| 16 | https://docs.google.com/presentation/d/1LlxyWOz88aXjAQVVJdN3Fss08E8Rnu8k/edit?usp=drivesdk&ouid=113802151767136274653&rtpof=true&sd=true
Делюсь с вами моей презой для одного из закрытых ивентов. Тут собрана база, но вполне возможно, что в вашей компании/команде вы отходите от нее, чтобы делать мир лучше :)
#events #presentation #allocations | 0 |
| 17 | Marshal.OffsetOf
С помощью этого метода я в BECS нахожу где фактически находится поле в структуре, в которое я хотел бы записать данные.
Я это использую в кодогене, когда я точно знаю название поля и хочу вписать туда данные, но использовать рефлексию для этого нет никакого желания.
Работает примерно так:
var offset = Marshal.OffsetOf(type, field.Name);
codeGenOutput.Add($"var addr = (byte*)_addressOf(ref obj) + {offset};");
codeGenOutput.Add($"*(({objType}*)addr) = new SomeStruct(...);");
В итоге получается, что мы просто записываем данные в структуру obj без рефлексии и нам не важно приватное там поле или публичное.
#unsafe #fieldoffset #marshal | 0 |
| 18 | https://www.youtube.com/watch?v=6syQWOWxUwY
Про Players и Teams
#becs #tutorials | 0 |
| 19 | https://github.com/chromealex/ME.Monitor/tree/main
Написал тут тулзу для мониторинга за серваками.
Умеет ping, tcp, rest, выводит графики, рисует маршруты. Предназначена для сборки в качестве standalone/adroid/ios билдов. Строит наглядно визуализацию расположения серверов и маршруты к ним. Для примера есть Config.json с рандомными сервисами, которые можно легко заменить на свои.
Проект написан на коленке и там ничего не структурировано, так что без поллитра вряд ли разберетесь. Тем не менее, вполне хорошее решение получилось и свою задачу выполняет отлично. Собираете билд, подменяете конфиг на свои серваки и вперед наблюдать.
Предложения принимаются :)
#unity #tools #monitoring | 0 |
| 20 | https://youtu.be/4mbOPXLfArM
Про Addressables, что такое GlobalEvents как их использовать.
#becs #tutorials | 0 |
