Авторский канал о разработке в Unity от Alex Silaev (CTO в Zillion Whales). Mushroom Wars 2 моих рук дело.
Рассказываю об интересный кейсах, делюсь лайфхаками, решениями.
Unity: Всё, что вы не знали о разработке pinned a photo
UN @unsafecsharp
Showing posts older than #41 · Back to latest

JobHandle.ScheduleBatchedJobs. Он позволяет "отправить" новую джобу на обработку. Если его не вызвать - джоба будет отправлена "когда-нибудь позже". Но не стоит его писать после шедулинга каждой джобы, т.к. это по сути форсированная отправка из локальной очереди в поток, а это занимает время.const long SOME_CONST = 1000000000L; // пример плохой записи
const long SOME_CONST = 1_000_000_000L; // пример хорошей записи
IJobParallelFor, мы туда передаем 2 параметра - количество элементов и сколько элементов будет попадать в одну итерацию. Но давайте представим ситуацию, что мы не знаем сколько элементов у нас будет (например, если у нас предыдущая джоба заполняет коллекцию). Таким образом мы не можем создать джобу. На самом деле для такого кейса существуют "отложенные джобы" ScheduleParallelForDeferArraySize. Чтобы завести такую джобу нужно передать указатель на Sequential-структуру, в которой первые 2 поля будут такие:T* list;int count;{
// block 1
}
{
// block 2
}IJobParallelForTransform. Это такая джоба, которая с удовольствием даст доступ к массиву трасформов ваших GameObject. Но существует несколько интересных моментов, которые повлияют на производительность:ReadOnly (Запускайте джобу через ScheduleReadOnly), это повлияет на выполнение джобы.GameObject и вы хотите их подвигать, то создайте N пустых GameObject и вложите в них по 64/128/256 ваших объектов. Если этого не сделать, то ваша джоба будет всегда ожидаться главным потоком независимо от отсутствия Complete.ProjectSettings, но и в файлах csc.rsp. При этом эти файлы могут располагаться как в корне (В папке Assets), так и у каждой ассембли отдельно.csc.rsp, подробнее можно почитать тут: https://docs.unity3d.com/530/Documentation/Manual/PlatformDependentCompilation.html.memcpy. В юнити это UnsafeUtility.MemCpy. Но там есть еще UnsafeUtility.MemMove. Главное отличие в том, что memcpy работает быстрее, т.к. не делает дополнительных проверок на общую область памяти, а вот memmove делает. Проще говоря, не используйте memcpy, если два блока пересекаются, т.к. это приведет к неопределенному результату. Т.е. когда вы копируете данные из одного массива в другой - память никак не пересекается и можно использовать memcpy. Но если же вы хотите "подвинуть" данные в одном массиве, то используйте memmove.Conditional, который дает возможность отключать/включать куски кода по дефайну.[Conditional("DEBUG")] void Method() {...}DEBUG. Метод должен быть void.methodInfo.GetMethodBody().GetILAsByteArray()?.Length <= 2lock, которую я использую в ME.BECSpublic static void Lock(ref int lockIndex) {
for (;;) {
if (System.Threading.Interlocked.Exchange(ref lockIndex, 1) == 0) {
break;
}
}
}
public static void Unlock(ref int lockIndex) {
System.Threading.Interlocked.Exchange(ref lockIndex, 0);
}Unlock, второй поток не пройдет через Lock. Из минусов такого подхода - если ваш код между этими вызовами упадет по исключению, то все ожидающие потоки повиснут. Для этого я написал дополнение, которое выходит из цикла с ошибкой, если мы ждем слишком долго. Как я писал выше в одном из постов, лучше вообще избегать блокировки и Interlocked, но в редких случаях без них не обойтись.int i = 123; // всегда атомарноlong j = 234L; // атомарно на x64, но кому сейчас надо x32?i++; // никогда не атомарно, т.к. мы читаем данные, увеличиваем, а потом записываемGOAP (или Goal-Oriented Action Planning)?FSM. FSM дает возможность приходить к конкретной цели, основываясь на параметрах, приобретенных при выполнении конкретных состояний, но при этом вы можете находиться в конкретном одном состоянии в определенный момент времени.Utility based AI, но о нем нужно рассказывать отдельно.var count = particleSystem.GetParticles(particlesArr);particleSystem.SetParticles(particlesArr, count);Array.Resize не проверяет размер массива в сторону уменьшения. То есть всегда будет выделен массив необходимого размера на выходе.