Game Maker - создание игр | HellRoom Games
Январь 19, 2017, 13:40:41 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
Новости: Hellroom Shoutbox Tools - JS расширение для доп. функционала в чате
 
   Начало   Game Maker Помощь Правила форума Поиск Календарь Войти Регистрация  
Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Основы оптимизации  (Прочитано 14558 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Fantom
I am... All of me
Гл. Администратор
*

Репутация: 1310
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [500 дней на форуме]За лояльность! [+1000 репутации]За отличные статьи по Game Maker!Тру Админ :DЗнаток Game Maker...
API: GameMaker Studio Master
Деятельность: Experienced Programmer
Сообщений: 5029



« : Октябрь 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 {}      //после оптимизации
// - - - - -
if life=false {} //до оптимизации
if !life {}      //после оптимизации
// -- результат обоих кодов идентичен
 Почему работает: используется уменьшение количества операций, производимых в действии. Например, if life=true - здесь операция сравнения переменной с true лишняя (аналогично с if (life=true)=true), можно сократить, взяв лишь значение самой логической переменной.
  Актуально: всегда и везде в разной степени.
  Прирост: 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
{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
  // -- результат обоих кодов идентичен
Кстати о переменных: если в коде необходимо использовать дополнительные переменные (как target), но которые впоследствии не потребуются (в качестве локальных переменных объекта), используйте временные переменные, как это показано в коде выше.
Если вспомогательные переменные всё-таки нужно сохранить на некоторое время вперёд или для других событий, после чего она не будет нужна - обнуляйте ее значение (особенно касается строковых переменных).
  Почему работает: обращение к готовому числу намного проще, чем выполнение функции. Представьте, что 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}
else if weapon=2 {стрелять2}
else if weapon=3 {стрелять3} //до оптимизации

switch (weapon)
{case 1: стрелять1; break;
 case 2: стрелять2; break;
 case 3: стрелять3; break;
}                          //после оптимизации
// -- результат обоих кодов идентичен
 Почему работает: один switch выполняется быстрее, чем несколько if.
  Актуально: для всех версий 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: проверена актуальность всех пунктов, подкреплены цифрами.
« Последнее редактирование: Декабрь 01, 2016, 23:08:22 от Fantom » Записан

MusNik
KeeVee Games
GM Pro user
*

Репутация: 709
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
3000 сообщений!За постоянность! [200 дней на форуме]За лояльность! [+500 репутации]За отличную игру Rock painting story!За помощь в развитии форума!За отличные статьи по Game Maker!...
API: GameMaker Studio 2
Сообщений: 3177


Tiny Alien :3


WWW
« Ответ #1 : Октябрь 27, 2011, 23:11:50 »

Отличная статья  Уважуха
Записан

YellowAfterlife
Is watching you.
Главный Модератор
*

Репутация: 421
Offline Offline

Пол: Мужской
Ukraine Ukraine

Награды:
Добавление и перевод новостей о Game Maker!500 сообщений!За постоянность! [200 дней на форуме]За лояльность! [+300 репутации]Настоящий игродел!Знаток Game Maker!...
API: GameMaker Studio Master
Сообщений: 716



WWW
« Ответ #2 : Октябрь 27, 2011, 23:21:14 »

Первый код из пункта 3 можно выбросить - на низком уровне (ассемблер), операции сравнения двух чисел сводятся к следующему
Код:
cmp ax, bx ; делает ax - bx с установкой нескольких флагов (знак, является ли нулем)
je метка; (je\jne\jl\jle\jg\jge)jump* - все операции различаются лишь флагами которые они проверяют.
Даже если допустить, что для jl\jg флаг "нуля" не проверяется, то разница в скорости выполнения все равно будет невероятно малой велечиной, по сравнению с временем, потраченным на интерпретацию кода. С этой точки зрения, если удалить из кода все пробелы, то это даст гораздо большее преимущество чем замена >= на >

От себя:
Операторы выполняются быстрее чем функции в GM.
Таким образом,
Код:
b = a >> 0
будет выполнен быстрее чем
Код:
b = round(a)
хоть и даст идентичный результат.
P.S.: логика работы битовых смещений в GameMaker очень искажена. Я не советую использовать их без предварительной проверки, если вы работали с ними в каком-либо другом языке программирования.
Записан

stdcout
Участник
****

Репутация: 6
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

API: Game Maker 8.0 Pro
Деятельность: GML, ActionScript 2.0, C++, CSMapping, 3ds Max 9
Сообщений: 178

Life is not pain! Life is life! (C)


WWW
« Ответ #3 : Ноябрь 01, 2011, 19:39:02 »

Статья интересная, но насколько эффективна такая оптимизация? Что она дает, насколько меньше загрузка ЦП? Не думаю что очень велика (хотя могу ошибаться)
Записан

Если решился поставить мне минус - ставь! Но не думай, что я буду играть в благородство и забуду это...
Fantom
I am... All of me
Гл. Администратор
*

Репутация: 1310
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [500 дней на форуме]За лояльность! [+1000 репутации]За отличные статьи по Game Maker!Тру Админ :DЗнаток Game Maker...
API: GameMaker Studio Master
Деятельность: Experienced Programmer
Сообщений: 5029



« Ответ #4 : Ноябрь 01, 2011, 19:43:25 »

Зависит от проекта, то есть нагрузки. Естественно, если предполагается участие большого количества объектов, то лучше оптимизировать. Тем более если планируется работа не только на самых последних новинках супер прокачанных компьютерах.

Вот "отзыв" из темы Оптимизация:
... Если запустить на нормальном компе старую и новую - различия никакого... Но если запустить на древнем компе (которому чуть меньше 10 лет)... Без оптимизации fps 2-3... А теперь 60 стабильно:)
Записан

stdcout
Участник
****

Репутация: 6
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

API: Game Maker 8.0 Pro
Деятельность: GML, ActionScript 2.0, C++, CSMapping, 3ds Max 9
Сообщений: 178

Life is not pain! Life is life! (C)


WWW
« Ответ #5 : Ноябрь 01, 2011, 20:01:14 »

Ясно всё.
Ну, моим проектам это не грозит, у меня у самого комп 6 летней давности...
Записан

Если решился поставить мне минус - ставь! Но не думай, что я буду играть в благородство и забуду это...
GoDCrashdaY
Пользователь
***

Репутация: 0
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

API: GameMaker Studio Pro
Сообщений: 55



« Ответ #6 : Январь 17, 2013, 12: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; }

Результат будет одинаковый, а скорость выполнения? Проект очень тяжелый, таких операций куча.
Записан

Счастье не в ярлыках. Добро... Зло... Делай все с любовью!
UniversalCreator
Активный участник
*****

Репутация: 29
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
За постоянность! [10 дней на форуме]
API: Game Maker 8.0 Pro
Деятельность: Я занят!
Сообщений: 445



WWW
« Ответ #7 : Январь 17, 2013, 12:24:49 »

Молодец, FanTom, статья отличная, но почему она не в в том разделе?
Или в том?
Записан
skypo
GM Pro user
*

Репутация: 53
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
500 сообщений!За постоянность! [50 дней на форуме]
API: GameMaker Studio Pro
Сообщений: 740


WWW
« Ответ #8 : Январь 17, 2013, 12:25:09 »

хм, 5 и 6 пункты как будто противоречат друг другу  Хм...
10 пункт еще актуален для GMS?
Записан
Dmi7ry
Гл. Администратор
*

Репутация: 1162
Online Online

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [200 дней на форуме]За лояльность! [+1000 репутации]За помощь в развитии форума!Знаток Game Maker!За помощь новичкам!
API: GameMaker Studio Master
Деятельность: Code, design
Сообщений: 5470



WWW
« Ответ #9 : Январь 17, 2013, 12:25:50 »

Вот такие вопросы по оптимизации:

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 не ставьте, фигурные скобки ставьте.
без скобочек и со скобочками разница в производительности будет совершенно не заметна, но скобочки дают гораздо более читабельный код и меньшее количество багов, как следствие.
а then он избыточен, то есть он дублирует фигурные скобки {} (GML поддерживает синтаксис различных языков, в том числе си и паскаль; скобки - из си, а then из паскаля и смысла писать одно и то же, нет).
Код:
if (x<y)
{
    break
}
Записан

- А какой, собственно, командой процессора колобок ест черта?
- Командой EAT...
Справка и FAQ в правом верхнем углу...
Fantom
I am... All of me
Гл. Администратор
*

Репутация: 1310
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [500 дней на форуме]За лояльность! [+1000 репутации]За отличные статьи по Game Maker!Тру Админ :DЗнаток Game Maker...
API: GameMaker Studio Master
Деятельность: Experienced Programmer
Сообщений: 5029



« Ответ #10 : Январь 17, 2013, 12: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, 12:43:21
хм, 5 и 6 пункты как будто противоречат друг другу  Хм...
Не вижу противоречий. errm
Записан

Dmi7ry
Гл. Администратор
*

Репутация: 1162
Online Online

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [200 дней на форуме]За лояльность! [+1000 репутации]За помощь в развитии форума!Знаток Game Maker!За помощь новичкам!
API: GameMaker Studio Master
Деятельность: Code, design
Сообщений: 5470



WWW
« Ответ #11 : Январь 17, 2013, 12:48:13 »

еще раз повторюсь: then и фигурные скобки - не взаимозаменяемые понятия. then служит, так сказать, для перехода от условия к действиям. Фигурные скобки
я бы уточнил в таком случае: фигурные скобки заменят then, а вот then фигурные скобки не заменит.
Записан

- А какой, собственно, командой процессора колобок ест черта?
- Командой EAT...
Справка и FAQ в правом верхнем углу...
GoDCrashdaY
Пользователь
***

Репутация: 0
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

API: GameMaker Studio Pro
Сообщений: 55



« Ответ #12 : Январь 17, 2013, 12:57:38 »

еще раз повторюсь: then и фигурные скобки - не взаимозаменяемые понятия. then служит, так сказать, для перехода от условия к действиям. Фигурные скобки
я бы уточнил в таком случае: фигурные скобки заменят then, а вот then фигурные скобки не заменит.
Надо бы это в шапку добавить, полезное замечание.

И еще вопросик:
На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ?
Записан

Счастье не в ярлыках. Добро... Зло... Делай все с любовью!
skypo
GM Pro user
*

Репутация: 53
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
500 сообщений!За постоянность! [50 дней на форуме]
API: GameMaker Studio Pro
Сообщений: 740


WWW
« Ответ #13 : Январь 17, 2013, 13:16:28 »

На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ?
ни на что не влияет. лучше ставить везде, где надо.

Добавлено: Январь 17, 2013, 13:18:13
Не вижу противоречий. errm
5. ... Если можете перевести кнопки в код - переводите.
6. Для управления желательно использовать стандартные события клавиш, вместо проверки кода в шаге (keyboard_check)

Меня все волнует 10-й пункт. Это действительно так сказывается на размере и быстродействии? Что удаленные id-шники все равно обрабатываются?
Записан
Fantom
I am... All of me
Гл. Администратор
*

Репутация: 1310
Offline Offline

Пол: Мужской
Russian Federation Russian Federation

Награды:
5000 сообщений!За постоянность! [500 дней на форуме]За лояльность! [+1000 репутации]За отличные статьи по Game Maker!Тру Админ :DЗнаток Game Maker...
API: GameMaker Studio Master
Деятельность: Experienced Programmer
Сообщений: 5029



« Ответ #14 : Январь 17, 2013, 13:29:34 »

На счет ; немного не ясно. Если в каждом присваивании x = 1 ставить ; в конце, это на что то влияет? Или можно оставлять просто x = 1 вместо x = 1; ?
ни на что не влияет. лучше ставить везде, где надо.
Подтверждаю. Лучше ставить.

Не вижу противоречий. errm
5. ... Если можете перевести кнопки в код - переводите.
6. Для управления желательно использовать стандартные события клавиш, вместо проверки кода в шаге (keyboard_check)
Кнопки = действия, а действия - это не то же самое, что события. Действия выполняются внутри событий.
Их можно сравнить с тем же условием: событие - это условие ("используйте стандартные вместо Step"), а действие - действие ("используйте код вместо кнопок").

Меня все волнует 10-й пункт. Это действительно так сказывается на размере и быстродействии? Что удаленные id-шники все равно обрабатываются?
Да, в GM8.0 это точно так, насчет GMS не в курсе.
Ради интереса можешь скачать движок GMogre, примеры в формате gmk, в каком-либо из них добавить новый скрипт, увидишь его номер (~333ооо) errm В примере такого количества скриптов нет, значит это количество учитывает и удаленные скрипты.
Затем экспортировать всё в чистый проект и разница в скорости их запуска и компилирования будет очень заметна.
Записан

Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  

Vendet | HellRoom Games © 2006-2015 All Rights Reserved
Powered by SMF 1.1.21 | SMF © 2013, Simple Machines