Всем привет! Я хотел бы проводить общие созвоны раз в неделю, чтобы пообщаться, рассказать о каких-нибудь проблемах, найти решение.
В какое время и в какой день вам было бы удобно это?
В комментах будет опрос про время.
В какое время и в какой день вам было бы удобно это?
В комментах будет опрос про время.
Final Results
8%
Понедельник
8%
Вторник
4%
Среда
4%
Четверг
9%
Пятница
47%
Суббота
21%
Воскресенье
Метод
#code
Array.Resize не проверяет размер массива в сторону уменьшения. То есть всегда будет выделен массив необходимого размера на выходе.#code
👍7🤡4
🥕Регистрация на событие.
Пройдет в эту субботу с 2х до 3х часов по Москве.
https://unsafecsharp.timepad.ru/event/2436586/
Пройдет в эту субботу с 2х до 3х часов по Москве.
https://unsafecsharp.timepad.ru/event/2436586/
unsafecsharp.timepad.ru
Знакомство / События на TimePad.ru
Будем знакомиться и обсуждать общие темы;)
https://news.1rj.ru/str/unsafecsharp
https://news.1rj.ru/str/unsafecsharp
👍5🤮1
Если у вас в проекте есть много skinnedmesh анимаций (например, у вас по лесу бегает много животных), то их анимации можно запечь в текстуру, откуда читать шейдером. Такие анимации будут работать довольно с сильной погрешностью, но для объектов окружения этого может быть вполне достаточно. Такое решение намного производительнее, т.к. работает с одной текстурой и укладывается в один DrawCall.
#animations #rendering #shaders
#animations #rendering #shaders
👍10👌1🤡1😨1
Партиклы можно использовать в качестве рендера своих спрайтов. Для этого нужно вызвать
изменить массив и вызвать
Таким образом можно контролировать тысячи частиц.
На практике мы с таким столкнулись, когда нам нужно было отрисовать 4 тысячи юнитов на экране телефона, при этом каждый юнит имел по 4 спрайта, т.е. 16к спрайтов на одном экране старенького андроида в 2015м году. Тогда юнити еще толком не умела нормально контролировать партиклы и пришлось писать свои партиклы на плюсах, что повлекло за собой боль с поддержкой этого кода под все платформы (а это были PS4/XBOXONE/Switch/iOS/Android/PC(x86/x64).
И да, в итоге юнити доделали партиклы и мы с радостью избавились от этого кода, но осадочек то остался 😉
#particles #code #rendering
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🗿2❤1
🥕Задачка
Представьте игру, где вы управляете большой толпой человечков, отдавая приказы кликом мышки. При этом игра сетевая, т.е. у каждого игрока большая толпа этих человечков. Например, возьмем, 1000 человечков у каждого игрока. Для простоты человечки ходят по прямой и не сталкиваются друг с другом. На карте есть препятствия, которые нужно обходить. Одним кликом вы контролируете сразу всех или выделенную часть.
Вопросы:
1. Каким образом будет устроен поиск пути?
2. Каким образом вы будете синхронизировать позиции человечков между игроками?
Представьте игру, где вы управляете большой толпой человечков, отдавая приказы кликом мышки. При этом игра сетевая, т.е. у каждого игрока большая толпа этих человечков. Например, возьмем, 1000 человечков у каждого игрока. Для простоты человечки ходят по прямой и не сталкиваются друг с другом. На карте есть препятствия, которые нужно обходить. Одним кликом вы контролируете сразу всех или выделенную часть.
Вопросы:
1. Каким образом будет устроен поиск пути?
2. Каким образом вы будете синхронизировать позиции человечков между игроками?
👍1🤔1
Как устроен
Все мы знаем деревья поведений или
В деревьях поведений же мы не ограничены одним состоянием в определенный момент, но сейчас не о них.
Есть еще
GOAP не имеет связей. Это важно. Совсем.
Простыми словами GOAP представляет собой массив простых событий, которые выполняются, если обеспечены их входные параметры, а на выходе дают необходимые эффекты. А имея такие вводные, можно без труда построить граф для достижения необходимого действия.
Как видно из названия, Goal-Oriented или ориентрир - это цель, мы ориентируемся на достижения цели. То есть мы говорим персонажу "будь сыт", а он сам добудет еду и поест. Ну или "построй дом", а он сам добудет необходимые материалы и построит дом.
Пожалуй, на этом примере можно и остановиться.
Допустим, у вас есть 3 простых действия:
1. Собирать камень
2. Рубить дерево
3. Строить дом
Строить дом - это действие, которое как результат выдает "дом построен", но на вход ему необходимо 2 камня и 4 дерева. Для того чтобы добыть 2 камня нужно иметь кирку, а чтобы добыть 4 дерева - нужен топор. Допустим, что топор и кирка у нас уже есть. Мы идем рубить дерево и добывать камень. И повторяем эти действия столько раз, пока не наберется необходимое количество.
Таким образом GOAP - это граф, который строится динамически, когда мы просим дать нам какой-то результат. Он всегда строится исходя из кратчайшего пути, т.е. если 4 дерева будет лежать на складе, то персонаж пойдет именно туда, т.к. рубить ничего не нужно.
А что вы используете в своих проектах?
#algorithms
GOAP (или Goal-Oriented Action Planning)?Все мы знаем деревья поведений или
FSM. FSM дает возможность приходить к конкретной цели, основываясь на параметрах, приобретенных при выполнении конкретных состояний, но при этом вы можете находиться в конкретном одном состоянии в определенный момент времени.В деревьях поведений же мы не ограничены одним состоянием в определенный момент, но сейчас не о них.
Есть еще
Utility based AI, но о нем нужно рассказывать отдельно.GOAP не имеет связей. Это важно. Совсем.
Простыми словами GOAP представляет собой массив простых событий, которые выполняются, если обеспечены их входные параметры, а на выходе дают необходимые эффекты. А имея такие вводные, можно без труда построить граф для достижения необходимого действия.
Как видно из названия, Goal-Oriented или ориентрир - это цель, мы ориентируемся на достижения цели. То есть мы говорим персонажу "будь сыт", а он сам добудет еду и поест. Ну или "построй дом", а он сам добудет необходимые материалы и построит дом.
Пожалуй, на этом примере можно и остановиться.
Допустим, у вас есть 3 простых действия:
1. Собирать камень
2. Рубить дерево
3. Строить дом
Строить дом - это действие, которое как результат выдает "дом построен", но на вход ему необходимо 2 камня и 4 дерева. Для того чтобы добыть 2 камня нужно иметь кирку, а чтобы добыть 4 дерева - нужен топор. Допустим, что топор и кирка у нас уже есть. Мы идем рубить дерево и добывать камень. И повторяем эти действия столько раз, пока не наберется необходимое количество.
Таким образом GOAP - это граф, который строится динамически, когда мы просим дать нам какой-то результат. Он всегда строится исходя из кратчайшего пути, т.е. если 4 дерева будет лежать на складе, то персонаж пойдет именно туда, т.к. рубить ничего не нужно.
А что вы используете в своих проектах?
#algorithms
👍24
Атомарные операции.
#threading
int i = 123; // всегда атомарноlong j = 234L; // атомарно на x64, но кому сейчас надо x32?i++; // никогда не атомарно, т.к. мы читаем данные, увеличиваем, а потом записываем#threading
👍9🥱7🤔1
Реализация
Мы заводим int поле и используем его в качестве идентификатора для операции блокирования. Другими словами, пока не будет вызван
#threading
lock, которую я использую в 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);
}Мы заводим int поле и используем его в качестве идентификатора для операции блокирования. Другими словами, пока не будет вызван
Unlock, второй поток не пройдет через Lock. Из минусов такого подхода - если ваш код между этими вызовами упадет по исключению, то все ожидающие потоки повиснут. Для этого я написал дополнение, которое выходит из цикла с ошибкой, если мы ждем слишком долго. Как я писал выше в одном из постов, лучше вообще избегать блокировки и Interlocked, но в редких случаях без них не обойтись.#threading
👍3
Рефлексия.
Можно определить отсутствие кода в методе, используя вызов
т.к. по сути там может быть 2 инструкции. Я использую этот метод только в редакторе, т.к. результат работы метода в билде будет зависеть от сборки.
#reflection
Можно определить отсутствие кода в методе, используя вызов
methodInfo.GetMethodBody().GetILAsByteArray()?.Length <= 2т.к. по сути там может быть 2 инструкции. Я использую этот метод только в редакторе, т.к. результат работы метода в билде будет зависеть от сборки.
#reflection
👍2🥴1👻1
Существует такой аттрибут
Метод будет компилироваться только если существует дефайн
#defines
Conditional, который дает возможность отключать/включать куски кода по дефайну.[Conditional("DEBUG")] void Method() {...}Метод будет компилироваться только если существует дефайн
DEBUG. Метод должен быть void.#defines
👍23🤔3🥱3🤯1
Многие встречали и даже использовали
#unsafe
memcpy. В юнити это UnsafeUtility.MemCpy. Но там есть еще UnsafeUtility.MemMove. Главное отличие в том, что memcpy работает быстрее, т.к. не делает дополнительных проверок на общую область памяти, а вот memmove делает. Проще говоря, не используйте memcpy, если два блока пересекаются, т.к. это приведет к неопределенному результату. Т.е. когда вы копируете данные из одного массива в другой - память никак не пересекается и можно использовать memcpy. Но если же вы хотите "подвинуть" данные в одном массиве, то используйте memmove.#unsafe
👍8
Дефайны можно объявлять не только в
Внутри можно делать ссылки на другие
#defines
ProjectSettings, но и в файлах csc.rsp. При этом эти файлы могут располагаться как в корне (В папке Assets), так и у каждой ассембли отдельно.Внутри можно делать ссылки на другие
csc.rsp, подробнее можно почитать тут: https://docs.unity3d.com/530/Documentation/Manual/PlatformDependentCompilation.html.#defines
Unity3D
Unity - Manual: Platform Dependent Compilation
The Unity Manual helps you learn and use the Unity engine. With the Unity engine you can create 2D and 3D games, apps and experiences.
👍24
Джобы.
Вы, наверное, слышали про
1. Если вы читаете трасформы и не меняете их - помечайте их как
2. Раскидайте элементы по нескольким рутам иерархии, группировав их по 64/128/256 штук. То есть если у вас на сцене в руте 10к
#jobs
Вы, наверное, слышали про
IJobParallelForTransform. Это такая джоба, которая с удовольствием даст доступ к массиву трасформов ваших GameObject. Но существует несколько интересных моментов, которые повлияют на производительность:1. Если вы читаете трасформы и не меняете их - помечайте их как
ReadOnly (Запускайте джобу через ScheduleReadOnly), это повлияет на выполнение джобы.2. Раскидайте элементы по нескольким рутам иерархии, группировав их по 64/128/256 штук. То есть если у вас на сцене в руте 10к
GameObject и вы хотите их подвигать, то создайте N пустых GameObject и вложите в них по 64/128/256 ваших объектов. Если этого не сделать, то ваша джоба будет всегда ожидаться главным потоком независимо от отсутствия Complete.#jobs
👍17🔥4
Используйте блоки кода вида
для того, чтобы избежать конфликтов локальных переменных и перестать выдумывать нечитаемые названия типа i, k, j, z etc 🙂
#code
{
// block 1
}
{
// block 2
}для того, чтобы избежать конфликтов локальных переменных и перестать выдумывать нечитаемые названия типа i, k, j, z etc 🙂
#code
👍19🥱4👎3🔥2😁1
Джобы.
Все знают, что есть
Т.е. указатель на массив элементов и количество этих самых элементов. Прочитаны эти данные будут только после того как все зависимости джобы будут завершены.
#jobs
Все знают, что есть
IJobParallelFor, мы туда передаем 2 параметра - количество элементов и сколько элементов будет попадать в одну итерацию. Но давайте представим ситуацию, что мы не знаем сколько элементов у нас будет (например, если у нас предыдущая джоба заполняет коллекцию). Таким образом мы не можем создать джобу. На самом деле для такого кейса существуют "отложенные джобы" ScheduleParallelForDeferArraySize. Чтобы завести такую джобу нужно передать указатель на Sequential-структуру, в которой первые 2 поля будут такие:T* list;int count;Т.е. указатель на массив элементов и количество этих самых элементов. Прочитаны эти данные будут только после того как все зависимости джобы будут завершены.
#jobs
👍16🔥1
Записывайте большие числа читаемо.
#code
const long SOME_CONST = 1000000000L; // пример плохой записи
const long SOME_CONST = 1_000_000_000L; // пример хорошей записи
#code
👍28👾3❤2🤬1💯1
Существует метод
#jobs
JobHandle.ScheduleBatchedJobs. Он позволяет "отправить" новую джобу на обработку. Если его не вызвать - джоба будет отправлена "когда-нибудь позже". Но не стоит его писать после шедулинга каждой джобы, т.к. это по сути форсированная отправка из локальной очереди в поток, а это занимает время.#jobs
👍5
Регаемся на мит, который мы проведем как и в прошлый раз в гугл мите:
https://unsafecsharp.timepad.ru/event/2439793/
Событие пройдет в эту субботу с 17:00 до 18:00 (в прошлый раз мы просидели полтора часа, так что имейте ввиду).
#event
https://unsafecsharp.timepad.ru/event/2439793/
Событие пройдет в эту субботу с 17:00 до 18:00 (в прошлый раз мы просидели полтора часа, так что имейте ввиду).
#event
👍18👎1
Существует возможность подсказать компилятору что метод должен быть заинлайнен, для этого нужно добавить аттрибут
При этом объявляю
Но нужно понимать, что аттрибут агрессинвного инлайна не гарантирует факт инлайна, он лишь подсказывает, что этот метод хорошо бы заинлайнить. Если дело касается хот частей, то лучше использовать "ручной инлайн", т.е. нужно переносить код самостоятельно.
#code
System.Runtime.CompilerServices.MethodImplAttribute(MethodImplOptions.AggressiveInlining). Я обычно пишу гораздо короче:[INLINE(256)]При этом объявляю
using INLINE = System.Runtime.CompilerServices.MethodImplAttribute.
Но нужно понимать, что аттрибут агрессинвного инлайна не гарантирует факт инлайна, он лишь подсказывает, что этот метод хорошо бы заинлайнить. Если дело касается хот частей, то лучше использовать "ручной инлайн", т.е. нужно переносить код самостоятельно.
#code
👍7🤔1