Самое слабое место Dragon Bones - класс TransformUtil
Запись от caseyryan размещена 02.02.2016 в 09:17
На днях сделал очередную предрелизную сборку игры, в которой у меня очень активно используется драгон бонс для анимации всего и вся. И, к моему величайшему расстроству, при появлении персонажей на экране, FPS довольно сильно начинает провисать. Если до их появления стабильно 60, то после появления 2 - 3 персов он падает до 35 - 40, а то и ниже. И это на довольно мощном устройстве Lenovo S90.
Еще больше огорчал тот факт, что игра уже довольно хорошо оптимизирована. Все рекомендации описанные здесь http://wiki.starling-framework.org/m...e_optimization учтены, а что касается простого флеша, тем более. Сборку для проверки всегда делаю релизную.
Решил детально поковырять игру скаутом. И пришел к выводу, что все провисания FPS происходят не из-за отрисовки текстур или их загрузки в видеопамять (как я изначально предполагал), а именно из-за математиеских расчетов, которые проивходят в драгон бонсе.
Сначала вижу, что провисает на 10 миллисекунд на top-level коде при вызове Number._convert, а дальше при вызове методов из класса dragonBones.utils.TransformUtil
Проблему мне решить удалось. И вот что я сделал:
1) Увидев в этом классе множество обращений к Math.PI, я подумал "а какого фига? это же константа" Известно же, что статики в as3 (да и не только) - штука довольно медленная. Поэтому просто заменил все вызовы этой константы на ее числовое значение 3.141592653589793
2) Так как компилятор в FD у меня ASC 2.0, то я сразу полез в Project - Properties - Compiler Options и там поменял значение свойства Inline Functions на True
3) Дальше каждому статическому методу в этом классе дописал метатег [Inline]
пример для тех кто не знает как это делается:
[Inline] public static function transformToMatrix(transform:DBTransform, matrix:Matrix):void { matrix.a = transform.scaleX * Math.cos(transform.skewY) matrix.b = transform.scaleX * Math.sin(transform.skewY) matrix.c = -transform.scaleY * Math.sin(transform.skewX); matrix.d = transform.scaleY * Math.cos(transform.skewX); matrix.tx = transform.x; matrix.ty = transform.y; }
Теперь провисания были уже далеко не такие серьезные. Но они все еще наблюдались кое где. И снова причиной был Dragon Bones. И причина крылась в том, что в методе matrixToTransform, есть вот такая (довольно странная, как по мне) конструкция:
var skewXArray:Array = []; skewXArray[0] = Math.acos(matrix.d / transform.scaleY); skewXArray[1] = -skewXArray[0]; skewXArray[2] = Math.asin(-matrix.c / transform.scaleY); skewXArray[3] = skewXArray[2] >= 0 ? 3.141592653589793 - skewXArray[2] : skewXArray[2] - 3.141592653589793; if (Number(skewXArray[0]).toFixed(4) == Number(skewXArray[2]).toFixed(4) || Number(skewXArray[0]).toFixed(4) == Number(skewXArray[3]).toFixed(4)) { transform.skewX = skewXArray[0]; } else { transform.skewX = skewXArray[1]; }
Сначла число конвертируется в строку, (что, по замерам скаута, занимает целых 10 миллисекунд!!!, и это очень много для одного кадра) а потом еще и сокращается до 4 знаков после запятой.
Решил попробовать избавиться от этого места, и просто убрал конвертации.
Пока я не заметил разницы, но уверен, что теперь эта конструкция работает не верно, так как числа явно получаются не совсем равные. Лучшей идеи мне пока не пришло. Если кто-то подскажет её, буду очень благодарен.
Вот, собственно и все! Теперь FPS не провисает ниже 59 - 60 вообще. Даже если на экране 5, 6 или даже 8 врагов (у которых довольно сложные анимации)
Всего комментариев 15
Комментарии
03.02.2016 10:14 | |
дописал метатег [Inline] - а для чего это делается?
|
03.02.2016 11:20 | |
10 mc как то нереально много.
Но вообще, производить математические вычисления через переводы в строки, как по мне - идея очень странная. Попробуй сделать ещё одну функцию для кастомного округления: И заинлайнить её. Уж точно не должно быть 10 mc. пс. Ещё вот этот массив skewXArray, если он только в функций используется, его можно создать один раз в какой нить статической переменной класса. Зачем каждый раз его создавать и удалять? А лучше вообще это через переменные функций сделать, накой там массив? Кароч, если это узкое место в программе, а там такая вакханалия творится... написавшему это нужно по рукам настучать. |
|
Обновил(-а) Tails 03.02.2016 в 11:44
|
03.02.2016 22:16 | |
Если бы не увидел коммент alatar'а, то мне бы стало любопытно, почему не заинлайнить свой MyMath.PI(). Было бы.. красивее.
Ну и, конечно, если не скован NDA – пиарь игрушку! |
04.02.2016 00:31 | |
13.02.2016 16:18 | |
Обращение к статикам становится очевидным на миллионах обращений. Ну и есть еще гении в Dragon Bones, что тут скажешь.
|
13.02.2016 16:27 | |
Цитата:
очевидным на миллионах обращений
|
25.02.2016 20:54 | |
Нет, конечно. За такой delay виновато не само по себе обращение к статик методу, а то, что в нем происходит.
|
26.02.2016 08:52 | |
Как тогда объяснить то, что то же самое содержимое, но в инлайне, дает прирост скорости раз в 6?
|
26.02.2016 12:54 | |
тесты в студию
|
27.02.2016 04:11 | |
а без Inline будет одинаково, и часто у тебя десять миллионов вызовов abs подряд?
|
|
Обновил(-а) СлаваRa 27.02.2016 в 10:24
|
Последние записи от caseyryan
- Небольшой хак для записи или удаления файлов из директории приложения (07.04.2017)
- Как я рекламу в игру внедрял (07.02.2016)
- Самое слабое место Dragon Bones - класс TransformUtil (02.02.2016)
- Разгружаем ресурсоемкие циклы на мобилах без воркеров (13.07.2015)