MonkeyBehaviour
Всем привет.
Я тут написал простенькую модель проги (фреймворк) по типу юнити, c классами GameObject, Component, MonkeyBehaviour, Transform, Sprite (и др). И меня заинтересовал вопрос про оптимизацию LateUpdate - понравился мне этот метод, хоть он нужен довольно редко. нужна ли оптимизация - не понятно, но в академических целях - почему нет. Обработка стартует со сцены (Scene), у которой есть коневой GameObject, и далее вглубь по всем дочерним объектам. В каждом объекте - проход по всем компонентам. Получается, надо прогнать 2 цикла по всему - сначала Update, затем LateUpdate. Я придумал решение - через рефлексию. Пробежать по всем компонентам, и проверить наличие метода LateUpdate, если переопределён хоть в одном классе, значит ок, будем пробегать второй раз. Проверку предполагается делать при старте/создании сцены, после юнитевского аналога Start(). Но что, если этот метод есть всего в одном скрипте? Такое размышление приводит к мысли, что можно хранить все скрипты в едином списке. Это позволит к тому же легко задать приоритет выполнения простой сортировкой списка, а также избавит от необходимости пробегать по всем дочерним элементам. Например, делаем два списка - 1й для тех кто содержит Update, 2й для LateUpdate. Конечно, если компоненты добавляются / удаляются динамически по ходу работы проги, то хз как оно будет по скорости. Можно в обёртке для скрипта помимо приоритета хранить ссылку на узел в списке, тогда быстро будет. Но динамически рефлексию не хотелось бы юзать. Да и вообще, сомнительное решение получилось.:-) |
Ответ: MonkeyBehaviour
А зачем он нужен? Пост-обновление можно реализовать и в самом методе обновления... но если уж так приспичило, то считаю оптимальным вариантом с отдельным списком объектов, которые имеют метод LateUpdate(dt#). В случае с динамическим подходом - то перед перебором всех объектов сцены, очищаем список и во время перебора добавляем к нему объекты нуждающиеся в пост-обработке. После чего, перебираем получившийся список. Ах, да... если тебе важна скорость... то, не стоит генерить линки на лету, достаточно их хранить в объекте, добавляя их в список.
|
Ответ: MonkeyBehaviour
LateUpdate любого (всех) компонента должен выполняться после всех Update компонентов, так что в самом методе обновления не сделаешь.
Применение - например следящая за объектом камера, которая движется после того как нужный объект подвигался. Аналогично - мобы с ИИ. Кстати, можно без рефлексии сделать, путём вычленения LateUpdate в отдельный интерфейс. Тогда можно будет формировать список через проверку на instanceof: 1. Для скриптов с LateUpdate наследуемся через Код:
extends MonkeyBehaviour implements ILateUpdate PHP код:
Не нужно рисование - не наследуешь IDraw, и т.п. Тоже на изврат похоже. :) |
Ответ: MonkeyBehaviour
Кому интересно взглянуть на код - репозиторий.
|
Ответ: MonkeyBehaviour
А что если сделать примерно так. Написать свой Behaviour где LastUpdate (и прочие функции) будут определены сразу как virtual и игрок при написании своего скрипта наследуется от Behaviour и переопределяет нужные ему функции. А в самом Behaviour все эти стандартные функции вызываются в любой ситуации.
Вроде в XNA что то подобное. |
Ответ: MonkeyBehaviour
Nex, сейчас так и сделано:
PHP код:
Вопрос как раз в том, чтобы не вызывать ВСЕ эти методы, а только при наличии переопределённых в коде юзера. |
Ответ: MonkeyBehaviour
Тогда как когда то pax рекомендовал делать через рефлексию и проверять используется ли функция в скрипте игрока. Так даже можно делать без virtual/override.
Просто при старте игры проверять код на наличие нужных функций и если есть, то делать из найденных функций делегат, который работает быстро в отличии от рефлексии. А там уже например в лист сохраняешь делегаты и вызываешь. Я такое пробовал использовать на c# + 2д движек. И даже без делегатов на небольших сценках все быстро работало. Цитата:
|
Ответ: MonkeyBehaviour
Цитата:
например, если завернуть Update в делегат. или ты про другой случай? какой? Также можно расширить MonoBehaviour или Component своими функциями и использовать их. Как вариант - навешивать на корневой объект сцены некий менеджер скриптов, который пробежит по всем дочерним объектам и компонентам, соберёт все экземпляры твоего переопределённого Behaviour'а, и менеджер будет в юнитевских методах Start, Update и прочих пробегать по спискам и вызывать делегаты. По части Update получается модель привычного gameloop'a, где все логики перебираются и выполняются. Однако, тогда не получим фушку с очередностью выполнения скриптов. Но можно наверное и с ней заморочиться. Это всё теория, даст ли оно профит, чтоб стоило с этим извращаться.) Пример с классом Message - тормозное решение, конечно. Да и вызов через строковое имя метода опасен - отрефакторишь имя функции и "привет". |
Ответ: MonkeyBehaviour
К знатокам юнити и прочих движков.
Как лучше считать глобальную позицию и масштаб объектов? Например, хочу сделать свойства localPosition и position. Local возвращает просто вектор, а не-local делает проход по всем родителям и вычисляет позицию с учётом родительских позиций, масштабов, поворотов. Так обычно делают или нет? UPD: второй вариант - пересчитывать трансформы дочерних элементов при изменении свойств в родителе. Для манки проблематично юзать такой подход, т.к. здесь все структуры - это классы, и нельзя запретить изменение переменных внутри структуры. То есть: Если в юнити написать transform.position.x = 200; мы получим ошибку при компиляции. За счёт этого можно перехватывать назначение переменной transform.position (а не поля "x" в структуре Vector) - и делать необходимые пересчёты. В манки так сделать нельзя из-за ограничений языка. Надо глянуть в сторону продвинутого Monkey2. |
Ответ: MonkeyBehaviour
Эм... в любом компоненте, обязательно должны быть только 3-4 метода... каждый называет их по своему, но я их назову так : Load(), Free(), Loop(dt#) и Draw() - думаю смысл их понятен. Все остальное - детали движка, которые легко реализовываются при помощи вышеописанных методов. Хотите LateUpdate() ? - Создайте хук, прицепите к нему нужный объект в методе Load() и вызывайте этот хук после всех обновлений... и выглядеть будет красиво и с ООП не придется заниматься сексом.
насчет второго вопроса... ну как бэ название говорит само за себя... localPosition - позиция объекта в локальной системе координат своего родителя. соотв. position - позиция относительно мировой системы координат. И для того, что бы узнать глобальное свойство без перебора всех родителей не обойтись ибо каждый родитель влияет на результат. |
Ответ: MonkeyBehaviour
Цитата:
У каждого объекта хранится полная трансформация в виде матрицы, а переменные позиций и углов находятся в локальных координатах. Дети обновляются только если изменилась трансформация родителя. https://github.com/clashbyte/spriteb...orld/Entity.cs |
Ответ: MonkeyBehaviour
Цитата:
Псевдокод или в рамках юнити сущностей. |
Ответ: MonkeyBehaviour
Кирпи4, в твоём коде есть Vector3 и Vec3, зачем так.
|
Ответ: MonkeyBehaviour
Цитата:
|
Ответ: MonkeyBehaviour
Модуль BlitzMax BRL.Hook :
Код:
Private 2) Вставляем объект и функцию-обработчик с помощью AddHook(LateUpdateHook, func, object, priority) 3) Ну и обработка всего этого дела - RunHooks(LateUpdateHook) |
Часовой пояс GMT +4, время: 10:52. |
vBulletin® Version 3.6.5.
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Перевод: zCarot