Название: Основы оптимизации Отправлено: Fantom от Октябрь 27, 2011, 22:48:09 Подборка правил по оптимизации проектов, проверенные на собственной "шкуре". К каждому пункту прилагается логическое обоснование, актуальность для разных версий GM и значение прироста производительности. Указанные тестовые данные могут отличаться в связи с разной сложностью кода и различными платформами (GMS). Для теста брались простые конструкции типа repeat (1000) {a=10;}. В любом случае, каждый может проверить эффективность на себе, о чем рассказано в последнем пункте статьи.
Некоторые значения прироста производительности могут показаться слишком ничтожными, но при больших количествах таких "мелочей" это может стать достаточно заметным. Привычка формировать код сразу удобным и эффективным - хорошая привычка. 1. Лесенка из условий. Разбивать условия, объединенные логическим оператором && (and), на несколько последовательных условий. Пример: Код: if a>b && b>c {} //до оптимизации Почему работает: при первой записи программа проверяет все условия в любом случае. Вторая запись уменьшает количество проверяемых условий - не всегда проверяются все условия, а, как минимум, одно.if a>b {if b>c {}} //после оптимизации // -- обе записи идентичны в плане их результата Актуально: для GM8.1 и ниже, и старых версий GMS. В новых версиях GMS разницы нет благодаря Short-Circuit, опция в Global Game Settings - General. Прирост: происходит в определенных ситуациях и зависит от сложности условий. 2. (следует из предыдущего) Ступеньки лесенки условий. При проверке составных условий на первое место ставить такие условия, которые реже всего будут истинными. Почему работает: условие реже всего выполняется, значит, следующие за ним условия будут тоже реже выполняться. Сокращается количество проверяемых условий. Актуально: всегда и везде. Прирост: происходит в более частых определенных ситуациях. 3. Сокращение количества операций. [здесь был еще неэффективный код] При проверке условий, то есть логических переменных, не сравнивать их еще раз с логическими константами. Другими словами, сокращать количество выполняемых операций. Пример: Код: if life=true {} //до оптимизации Почему работает: используется уменьшение количества операций, производимых в действии. Например, if life=true - здесь операция сравнения переменной с true лишняя (аналогично с if (life=true)=true), можно сократить, взяв лишь значение самой логической переменной.if life {} //после оптимизации // - - - - - if life=false {} //до оптимизации if !life {} //после оптимизации // -- результат обоих кодов идентичен Актуально: всегда и везде в разной степени. Прирост: GM8.1-: +11%. GMS: +2%. 4. Лучше готовый результат, чем снова функция. Если в одном коде предполагается неоднократное использование одной и той же функции (например, instance_nearest) с одними и теми же аргументами, то запишите ее результат в переменную, а при использовании обращайтесь к этой переменной. Пример: Код: if point_distance(x,y,instance_nearest(x,y,Enemy).x,instance_nearest(x,y,Enemy).y) < 500 Кстати о переменных: если в коде необходимо использовать дополнительные переменные (как target), но которые впоследствии не потребуются (в качестве локальных переменных объекта), используйте временные переменные, как это показано в коде выше.{move_towards_point(instance_nearest(x,y,Enemy).x,instance_nearest(x,y,Enemy).y,5);} //до оптимизации // - обращений к функции - 4 var target; target=instance_nearest(x,y,Enemy); if point_distance(x,y,target.x,target.y) < 500 {move_towards_point(target.x,target.y,5);} //после оптимизации // - обращений к функции - 1 // -- результат обоих кодов идентичен Если вспомогательные переменные всё-таки нужно сохранить на некоторое время вперёд или для других событий, после чего она не будет нужна - обнуляйте ее значение (особенно касается строковых переменных). Почему работает: обращение к готовому числу намного проще, чем выполнение функции. Представьте, что point_distance - это формула Корень(Квадрат(х2-х1)+Квадрат(у2-у1)). Очевидно, что взятие готового числа будет выполняться быстрее, чем выполнение этой функции. Временные переменные, определяемые словом var, существуют только в выполняемом скрипте и уничтожаются при завершении скрипта, таким образом освобождая память. Актуально: всегда и везде. Прирост: GM8.1-: +15%. GMS: +30%. 5. Совершенствование структуры. Если есть возможность не использовать скрипты - не используйте скрипты. Если можете перевести кнопки в код - переводите. Если выполнение определенных действий не особо важно для того, чтобы их выполнять в шаге - выполняйте их в циклически заводящемся сигнале (раз в 2 шага, раз в секунду, но не каждый шаг). Есть еще такие функции, которые не обязательно выполнять в шаге (или рисовании, что то же самое), а достаточно выполнить один раз. Особенно часто встречается функция draw_set_font, указанная в рисовании. Ее можно выполнить один раз в создании, как и некоторые другие функции, которые "что-то устанавливают", а не "выполняют (рисуют)" - draw_set_color, draw_set_halign, draw_set_circle_precision и другие со словом set. Почему работает: выполнение скрипта в шаге (например) происходит медленнее, чем просто код в шаге. По некоторым источникам, вызов скрипта в 5 раз медленнее использования обычного кода (не подтверждено). Кнопки работают медленнее, чем код, и к тому же могут выполнять лишние действия (для замены спрайта достаточно одного sprite_index=sprite, а кнопка выполняет еще два дополнительных действия). Между вызовом скрипта с помощью кнопки или в коде разницы нет. Вынос действий из шага в сигнал: то, что проверки выполняются не каждый шаг, а реже, уже само говорит за себя. Актуально: во всех версиях Game Maker в разной степени. Прирост: Не скрипты: GM8.1-: +22%. GMS: +10%. | Не кнопки: GM8.1-: +80%. GMS: минимальный. | Сигнал: зависит от периода, всегда ярко выражен. 6. Стандартные события. Для управления желательно использовать стандартные события клавиш, вместо проверки кода в шаге (keyboard_check). Аналогично со столкновениями с дополнительным эффектом улучшения производительности, когда столкновения не происходит (а код продолжает в это время проверять). Почему работает: стандартные события обрабатываются быстрее, чем код в шаге. Актуально: во всех версиях Game Maker. Прирост: Управление: GM8.1-: +66%. GMS: +60%. | Столкновения: GM8.1-: +38%. GMS: +30%. 7. Формирование спрайтов. Отключать точную проверку столкновений у спрайтов, если нет в ней особой необходимости. Обрезать лишнюю пустую рамку вокруг спрайтов. Почему работает: при точной проверке столкновений необходимо создавать маску по очертаниям спрайта. Если ее выключить, то берется прямоугольник, либо вписанные в него круг или ромб (можно сравнить с пунктом 4, только этот графический. Понятно, отчего эффект). Лишняя рамка вокруг спрайтов увеличивает объем потребляемой памяти спрайтом и проекта в целом. В совокупности с точной проверкой, увеличивается и время создания точной маски. Актуально: GMS. Прирост: GM8.1-: минимальный. GMS: +19%. 8. Лучше switch, чем else if. В ситуации, при которой различные действия должны выполняться в зависимости от значения переменной (например, проверка оружия и выполнение соответствующего выстрела), используйте switch вместо if {} else if {} else if .... Пример: Код: if weapon=1 {стрелять1} Почему работает: один switch выполняется быстрее, чем несколько if.else if weapon=2 {стрелять2} else if weapon=3 {стрелять3} //до оптимизации switch (weapon) {case 1: стрелять1; break; case 2: стрелять2; break; case 3: стрелять3; break; } //после оптимизации // -- результат обоих кодов идентичен Актуально: для всех версий Game Maker в разной степени. Прирост: GM8.1-: +20%. GMS: +5%. 9. Объекты -> тайлы -> частицы. Объекты, которые никаким образом не взаимодействуют с другими объектами, заменяйте их на тайлы. Если эти объекты появляются во время игры и движутся, заменяйте их на частицы, выбрав им в качестве формы собственный спрайт. Почему работает: объект - более активная сущность, чем тайл или частица. В постановке этого пункта уже сказано чем: проверками столкновений с другими объектами, а также созданием локальных переменных, проверкой других событий. Актуально: для всех версий Game Maker. Прирост: Частицы vs Объекты: GM8.1-: +46%. GMS: +970%. | Тайлы vs Объекты: GM8.1-: +15%. GMS: -3%. 10. Сборка мусора в проекте. Если у вас в проекте появились ненужные объекты, спрайты, скрипты, комнаты или прочие ресурсы, не спешите их удалять. Создайте папку для этих объектов и перемещайте их туда. А позднее вместо того, чтобы создавать новый ресурс (объект, спрайт, скрипт, комнату), можно будет использовать старый и ненужный. Проверяйте скачиваемые движки путём создания нового ресурса. Если появившийся порядковый номер значительно превосходит количество данного ресурса (script338563, а скриптов от силы тысяча-полторы), значит, движок создавался без соблюдения этого правила. Почему работает: каждый ресурс требует определенного имени (более всего похожее на id объектов, index) в проекте, к которому можно будет обращаться. После удаления ресурса, этот id всё же остается в проекте и, во-первых, увеличивает размер проекта, во-вторых, замедляет процесс компиляции и увеличивает время запуска проекта, в-третьих, возможно, точно так же действует и на производительность игры - замедляет (не подтверждено). Избавиться от "устаревших" id ресурсов позволяет экспорт всех ресурсов в чистый проект. Актуально: GM8.1 и ниже. Прирост: действует только на размер файла проекта и игры, длительность компиляции и запуска. Производительность в игре не затрагивается. 11. Самостоятельные тесты. Некоторые ситуации в коде разрешаются разными приёмами, которые могут отличаться производительностью. Если она важна для вас, проводите тестирование этих способов, выполняя код repeat (1000) {приём} в шаге или похожим способом. Актуально: всегда и везде. Прирост: измеряется самостоятельно. Автор: Fantom. Запрещается копирование данной статьи без ведома и согласия автора. UPD 11.11.2014: проверена актуальность всех пунктов, подкреплены цифрами. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: MusNik от Октябрь 27, 2011, 23:11:50 Отличная статья sm_respekt
Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: YellowAfterlife от Октябрь 27, 2011, 23:21:14 Первый код из пункта 3 можно выбросить - на низком уровне (ассемблер), операции сравнения двух чисел сводятся к следующему
Код: cmp ax, bx ; делает ax - bx с установкой нескольких флагов (знак, является ли нулем) Даже если допустить, что для jl\jg флаг "нуля" не проверяется, то разница в скорости выполнения все равно будет невероятно малой велечиной, по сравнению с временем, потраченным на интерпретацию кода. С этой точки зрения, если удалить из кода все пробелы, то это даст гораздо большее преимущество чем замена >= на >je метка; (je\jne\jl\jle\jg\jge)jump* - все операции различаются лишь флагами которые они проверяют. От себя: Операторы выполняются быстрее чем функции в GM. Таким образом, Код: b = a >> 0 будет выполнен быстрее чемКод: b = round(a) хоть и даст идентичный результат.P.S.: логика работы битовых смещений в GameMaker очень искажена. Я не советую использовать их без предварительной проверки, если вы работали с ними в каком-либо другом языке программирования. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: stdcout от Ноябрь 01, 2011, 20:39:02 Статья интересная, но насколько эффективна такая оптимизация? Что она дает, насколько меньше загрузка ЦП? Не думаю что очень велика (хотя могу ошибаться)
Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Fantom от Ноябрь 01, 2011, 20:43:25 Зависит от проекта, то есть нагрузки. Естественно, если предполагается участие большого количества объектов, то лучше оптимизировать. Тем более если планируется работа не только на самых последних новинках супер прокачанных компьютерах.
Вот "отзыв" из темы Оптимизация (http://forum.hellroom.ru/index.php?topic=1336.msg11305#msg11305): ... Если запустить на нормальном компе старую и новую - различия никакого... Но если запустить на древнем компе (которому чуть меньше 10 лет)... Без оптимизации fps 2-3... А теперь 60 стабильно:) Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: stdcout от Ноябрь 01, 2011, 21:01:14 Ясно всё.
Ну, моим проектам это не грозит, у меня у самого комп 6 летней давности... Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: GoDCrashdaY от Январь 17, 2013, 13:05:30 Вот такие вопросы по оптимизации:
1) Влияют ли на что нибудь скобки? Учитывая только 1 операцию, с 2 и более без них никак :) Пример: if (x<y) или if x<y 2) Нужно ли ставить then после if (x<y)? Пример: if (x<y) then break; или if (x<y) break; 3) Нужно ли ставить { } после if (x<y) then? Пример: if (x<y) then break; или if (x<y) then { break; } Результат будет одинаковый, а скорость выполнения? Проект очень тяжелый, таких операций куча. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: UniversalCreator от Январь 17, 2013, 13:24:49 Молодец, FanTom, статья отличная, но почему она не в в том разделе?
Или в том? Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: skypo от Январь 17, 2013, 13:25:09 хм, 5 и 6 пункты как будто противоречат друг другу :hm:
10 пункт еще актуален для GMS? Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Dmi7ry от Январь 17, 2013, 13:25:50 Вот такие вопросы по оптимизации: скобочки ставьте, then не ставьте, фигурные скобки ставьте.1) Влияют ли на что нибудь скобки? Учитывая только 1 операцию, с 2 и более без них никак :) Пример: if (x<y) или if x<y 2) Нужно ли ставить then после if (x<y)? Пример: if (x<y) then break; или if (x<y) break; 3) Нужно ли ставить { } после if (x<y) then? Пример: if (x<y) then break; или if (x<y) then { break; } Результат будет одинаковый, а скорость выполнения? Проект очень тяжелый, таких операций куча. без скобочек и со скобочками разница в производительности будет совершенно не заметна, но скобочки дают гораздо более читабельный код и меньшее количество багов, как следствие. а then он избыточен, то есть он дублирует фигурные скобки {} (GML поддерживает синтаксис различных языков, в том числе си и паскаль; скобки - из си, а then из паскаля и смысла писать одно и то же, нет). Код: if (x<y) { break } Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Fantom от Январь 17, 2013, 13:40:18 Вот такие вопросы по оптимизации: Все три пункта вряд ли каким-либо образом действуют на производительность.1. Ставить или не ставить скобки при одном условии - кому как удобно. При двух и нескольких условиях их тоже можно избежать, если условия несложные. 2. then не нужен, добавлен, возможно, для тех, кто изучал Паскаль. 3. Фигурные скобки при одном действии тоже кому как удобно, можно ставить, можно не ставить (всегда ставлю), но еще раз повторюсь: then и фигурные скобки - не взаимозаменяемые понятия. then служит, так сказать, для перехода от условия к действиям. Фигурные скобки (аналог begin end Паскаля, которые тоже присутствуют в GML) позволяют выполнять несколько операций при выполнении условия. Пример: Код: if (a=0) {x=5; y=10;} // - - - if (a=0) x=5; y=10; // результаты разные. В первом случае выполняются два действия по условию, во втором - одно Добавлено: Январь 17, 2013, 13:43:21 хм, 5 и 6 пункты как будто противоречат друг другу :hm: Не вижу противоречий. :errm:Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Dmi7ry от Январь 17, 2013, 13:48:13 еще раз повторюсь: then и фигурные скобки - не взаимозаменяемые понятия. then служит, так сказать, для перехода от условия к действиям. Фигурные скобки я бы уточнил в таком случае: фигурные скобки заменят then, а вот then фигурные скобки не заменит.Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: GoDCrashdaY от Январь 17, 2013, 13:57:38 еще раз повторюсь: then и фигурные скобки - не взаимозаменяемые понятия. then служит, так сказать, для перехода от условия к действиям. Фигурные скобки я бы уточнил в таком случае: фигурные скобки заменят then, а вот then фигурные скобки не заменит.И еще вопросик: На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ? Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: skypo от Январь 17, 2013, 14:16:28 На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ? ни на что не влияет. лучше ставить везде, где надо.Добавлено: Январь 17, 2013, 14:18:13 Не вижу противоречий. :errm: 5. ... Если можете перевести кнопки в код - переводите.6. Для управления желательно использовать стандартные события клавиш, вместо проверки кода в шаге (keyboard_check) Меня все волнует 10-й пункт. Это действительно так сказывается на размере и быстродействии? Что удаленные id-шники все равно обрабатываются? Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Fantom от Январь 17, 2013, 14:29:34 На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ? ни на что не влияет. лучше ставить везде, где надо.Не вижу противоречий. :errm: 5. ... Если можете перевести кнопки в код - переводите.6. Для управления желательно использовать стандартные события клавиш, вместо проверки кода в шаге (keyboard_check) Их можно сравнить с тем же условием: событие - это условие ("используйте стандартные вместо Step"), а действие - действие ("используйте код вместо кнопок"). Меня все волнует 10-й пункт. Это действительно так сказывается на размере и быстродействии? Что удаленные id-шники все равно обрабатываются? Да, в GM8.0 это точно так, насчет GMS не в курсе.Ради интереса можешь скачать движок GMogre (http://forum.hellroom.ru/index.php?topic=640.0), примеры в формате gmk, в каком-либо из них добавить новый скрипт, увидишь его номер (~333ооо) :errm: В примере такого количества скриптов нет, значит это количество учитывает и удаленные скрипты. Затем экспортировать всё в чистый проект и разница в скорости их запуска и компилирования будет очень заметна. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: skypo от Январь 17, 2013, 15:03:36 Сильно сомневаюсь (практически уверен, что не), что этот движок с примерами по нему вообще пойдет под GMS. Надо будет посмотреть айдишники в танкисте. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: MusNik от Январь 17, 2013, 20:29:23 GMS очищает айдишники после перезагрузки.
Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: likstalkera от Январь 31, 2013, 03:34:51 Если записывать код из шага в рисование, то сильно ли это повлияет на производительность?
Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Dmi7ry от Январь 31, 2013, 06:39:38 Если записывать код из шага в рисование, то сильно ли это повлияет на производительность? От перестановки переменных сумма не меняется. События всего лишь определяют порядок выполнения кода, производительность от этого не поменяется.Другое дело, что при этом нужно довольно чётко понимать, что мы делаем. Например, изменение координат других объектов в draw может привести к непредсказуемым дёрганиям спрайтов. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: nectarine от Февраль 15, 2013, 04:42:17 Спасибо за статью, очень познавательно :)
В связи с прочитанным, у меня такой вопрос: допустим, нужно нарисовать гуй, в котором довольно много кода получится в событии draw. Что будет быстрее, оставить весь код draw в одном объекте, контролирующем гуй (в котором помимо draw есть и другие события), или же вынести код draw в, скажем, P.S. код из draw иногда обращается к значениям переменных внутри других событий. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: skypo от Февраль 15, 2013, 09:25:18 Спасибо за статью, очень познавательно :) В связи с прочитанным, у меня такой вопрос: допустим, нужно нарисовать гуй, в котором довольно много кода получится в событии draw. Что будет быстрее, оставить весь код draw в одном объекте, контролирующем гуй (в котором помимо draw есть и другие события), или же вынести код draw в, скажем, P.S. код из draw иногда обращается к значениям переменных внутри других событий. меньше объектов - лучше. в draw лучше ничего помимо собсно отрисовки не держать (т.е. все расчеты - в step'ах). в случае ГУИ можно обойтись без объектов вообще - сделать тайлами и организовать их замену через скрипт Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Briginas от Март 14, 2013, 16:48:29 Интересует такой вопрос. Какой вариант лучше в плане оптимизации?
Код: (1 Вариант) if a = b {c += d} Код: (2 Вариант) c += d*(a = b) С виду кажется, что второй вариант более оптимизованный, но: В первом варианте действие с переменной выполняется только если условие истинно, во втором же выполняется и условие, и действие переменной, не зависимо от условия (к переменной каждый шаг прибавляется 0). И второй вопрос. Есть ли разница использования + и * вместо || и && ? Код: (1 Вариант) if (a = b) + (c = d) {e += f} Код: (2 Вариант) if (a = b) || (c = d) {e += f} Т.к. любое число выше 0.5 возвращает true, то условие истинно, но есть ли разница со вторым вариантом? Аналогичный вопрос с && и *Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Fantom от Март 14, 2013, 17:25:01 1. Первое лучше, и читается удобнее, чем второй вариант. Следуя второму варианту, рано или поздно появятся такие выражения, в которых не будет понятно, где "главное" равно, а где складываемые (или где левая часть выражения, а где правая) :errm:
Во втором варианте тоже используется сравнение, как и в первом, поэтому у первого меньше нагрузка. (к переменной каждый шаг прибавляется 0). Еще и умножение выполняется. Одна-две операции в первом варианте против трех во втором.2. || - логическое сложение, && - логическое умножение. Разница в слове "логическое" :xD: В приведенных примерах (и с умножением если тоже привести) разницы в результате нет, но практика таких выражений опять же может привести к запутыванию кода (обфускация, с одной стороны плюс, с другой минус) и к привыканию. Одно дело - GML это спокойно принимает, другое дело - другие языки не смогут, разрешая выполнять только логические операции с логическими переменными, и ожидая только логическую переменную после if. Название: Re: Простые правила оптимизации кода / игры в целом Отправлено: Briginas от Март 14, 2013, 17:46:46 Понятно, значит лучше использовать "классические" методы.
Как я понял Код: if a = b {c = d} else {c = 0} Будет так же выполняться быстрее, чемКод: c = d*(a = b) Ведь else не является сравнением, а всего лишь выполняется при ложном значении условия. Я прав?Название: Re: Основы оптимизации Отправлено: AlexBel от Февраль 02, 2016, 14:01:05 Привет всем!
Думаю, было бы хорошо включить в эту тему рекомендации по выбору разрешения для игры и масштабирования с точки зрения производительности. Например, если планируется работа игры на разных разрешениях экрана (например, на Android), то как следует подойти к выбору размера комнат? Если при масштабировании картинка увеличивается, то как это скажется на производительности? Или как скажется уменьшение? В какой-то из тем обсуждение данного вопроса встречал, но сейчас не могу найти. Не сочтите за некропостинг, думаю, вопрос имеет прямое отношение к теме и создавать новую нет смысла. |