Название: F.A.Q. для начинающих
Отправлено: DeatHSoul от Ноябрь 28, 2010, 00:41:32
GameMaker F.A.Q. Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы. Комментирование разрешено, пожелания и новые вопросы принимаются! >> Скачать FAQ в формате .chm << (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1701) (доработанный и дополненный по сравнению с online-версией) >> Сленг и Терминология << (http://forum.hellroom.ru/index.php?topic=2877.0)
Итак, перед вами список наиболее часто задаваемых вопросов по Game Maker и GML. Навигация: I - Теория - в этом разделе вы можете найти теоретическую информацию о Game Maker, GML и игростроении в целом. - "Старт" - в этом подразделе находятся вопросы, которые могут возникнуть у игродела перед началом работы в Game Maker.
- "Программа" - в этом подразделе находятся вопросы, которые могут возникнуть у игродела при работе непосредственно с Game Maker'ом.
- "Игрострой" - в этом разделе находится теоретическая информация о Gama Maker'е.
II - Практика - в этом разделе вы можете найти все наиболее часто задаваемые вопросы (и ответы на них, конечно) касающиеся реализации чего-либо в Game Maker. - "Базовая работа с кодом и простые решения" - очень простые вопросы.
- "Движение и столкновения" - все вопросы, касающиеся перемещения чего-либо и проверки столкновений.
- "Рисование" - все вопросы, касающиеся отображения графики и данных.
- "Другое" - все вопросы, которые не подходят под тематику остальных подразделов.
- "Оптимизация" - все вопросы, связанные с оптимизацией.
- "ИИ" - все вопросы, связанные с написанием искусственного интеллекта.
III - Примеры - список примеров, созданных для этого FAQ. VI - Шаблон - простой шаблон для создания своих вопросов-ответов. FAQ может и должно постоянно пополняться, так что пишите вопросы, которые на ваш взгляд должны находиться в FAQ. Если я буду с вами солидарен, то я могу сам написать к ним ответ и разместить их в нужной категории. Также, наверняка, во время чтения вы замечаете массу опечаток, так что если вы заметили какую-то ошибку в FAQ, опечатку или что-либо ещё - не стесняйтесь, напишите мне в ЛС, и я всё поправлю. Жду ваших предложений по улучшению FAQ. Помните, даже незначительные изменения могут упростить использование FAQ. Авторы, которые приложили руку к созданию этого FAQ: Автором всех остальных ответов являюсь я сам, как же и всех примеров, кроме тех, авторы которых обозначены (смотрите III раздел). Категорически запрещается копирование материалов (вопросов, ответов) статьи и размещение их на стороннем ресурсе без разрешения автора проекта - DeatHSoul'а.I - ТЕОРИЯ 1) СтартI.1.1. Что такое Game Maker? Ответ: Game Maker — один из самых известных конструкторов игр. Это не движок. Первую версию GM Разработал Марк Овермарс в 1999 году, однако, начиная с версии 7.0 разработкой GM занимается команда YoYo Games. Официальный сайт конструктора на данный момент - yoyogames.com (http://www.yoyogames.com). Скачать Game Maker для Windows и Mac можно здесь: http://www.yoyogames.com/gamemaker/try
I.1.2. Что такое GML? Ответ: Game Maker Language (GML) — это интерпретируемый язык программирования, встроенный в Game Maker. Он предлагает значительно большую функциональность, чем встроенные действия lib библиотек GM.
I.1.3. Какая последняя версия Game Maker? Ответ: На данный момент, последняя версия GM - 8.1. Впрочем, постоянно выходят обновления, исправляющие баги текущей версии и добавляющие новые возможности.
I.1.4. На каких платформах работают GM-игры? Ответ: На данный момент существует версия Game Maker для Windows и Mac (http://www.yoyogames.com/gamemaker/try). У YoYo Games так же имеется конвертер для портирования GM игр на PSP, iOS (iPhone, iPad), Android и HTML5. Так же, в планах у YoYo Games выпустить продукт под названием "GameMaker Studio", некую особую версию GameMaker, включающую возможность портирования игр на различные платформы.
I.1.5. Что такое Pro и Lite версии Game Maker? Какая стоимость Game Maker? Ответ: Начиная с GameMaker версии 8.1, обычная Pro версия стала называться Standart (а Lite сохранила свое название). До первого июня 2011 года GameMaker Standart можно купить за $25, однако после этого стоимость GameMaker повыситься до $39.99. Покупка GameMaker 8.x будет действительна для всех версий 8.х Информация из русифицированного справочного руководства к Game Maker 8.0 (http://gmakers.ru/gamemaker_help/): Game Maker предоставляется в двух версиях, Lite Edition (облегченная редакция) и Pro Edition (профессиональная редакция). Lite Edition подходит для тех, кто только делает первые шаги в разработке игр. Она совершенно бесплатна, но имеет ограниченную функциональность. Также при запуске игр показывается логотип, а при использовании программы будет постоянно выходить напоминание о возможности обновления. Если Вы собираетесь пользоваться Game Maker регулярно, Вам настойчиво рекомендуется обновить программу до Pro Edition. В Pro Edition значительно расширена функциональность и не показываются логотипы и сообщения. Конкретно в Pro Edition доступны следующие возможности: - Не показывается логотип Game Maker при запуске игр.
- Не показываются всплывающие сообщения о возможности обновления.
- Возможность отрисовывать повернутые, окрашенные и прозрачные спрайты.
- Дополнительные опции в редакторах спрайтов и изображений.
- Дополнительные действия, такие как проигрывание CD музыки, рисование повернутого текста и окрашенных форм.
- Использование звуковых эффектов и позиционирования источников звука.
- Использование загрузочных экранов с фильмами, изображениями, веб страницами, текстом и т. д.
- Система частиц для эффектов взрыва, салюта, пламени, снега, дождя и других.
- Дополнительные продвинутые функции рисования, например, для отрисовки окрашенного текста и текстурированных полигонов.
- Возможность создание 3D игр, при использовании функций для 3D графики.
- Возможность создания многопользовательских проектов для игры через интернет или локальную сеть.
- Возможность задавать свои собственные эффекты перехода между комнат.
- Вы можете использовать функции для создания, загрузки и изменения ресурсов (спрайтов, фонов и т.д.) "на лету", прямо во время игры.
- Доступны функции для работы с различными структурами данных.
- Функции для планирования движения.
- Возможность вложения файлов в исполняемые файлы игр, которые можно использовать во время запуска игр.
- Функциональные возможности можно улучшать пакетами расширений. Их может сделать любой человек и распространять, как правило, совершенно бесплатно.
- Три таких пакета расширения уже включены в дистрибутив, они добавляют новые эффекты перехода между комнатами, диалоги windows и функции для принтера.
- Вы можете определять свои собственные события триггера.
- Вы можете импортировать и экспортировать ресурсы, что поможет Вам легко совмещать ваши проекты.
Обновление с версии Lite Edition до Pro Edition стоит 20 Евро или US $25. Этот взнос делается один раз и будет действительным, как минимум, для всех версий Game Maker 8.x. Информация из официального справочного руководства к Game Maker 8.1.69:
GameMaker comes in two editions, the Lite Edition and Standard Edition. The Lite Edition is meant for those that take their first steps on the path of developing games. It can be used for free but is limited in its functionality. Also it shows a popup logo when running games and will regularly remind you of upgrading the program. When you are using GameMaker regularly you are strongly recommended to upgrade from the Lite Edition. Standard Edition contains considerably more functionality and does not display any logos or popup messages. More precisely, Standard Edition has the following additional functionality: - No GameMaker logo is shown when running a game.
- No GameMaker TV logo in the corner of a game.
- No GameMaker advert screen on exit.
- No regular popups remind you of upgrading.
- You can use color blended sprites, which can be used for many special effects and easy shadows.
- There are additional options in the sprite and image editors.
- There are additional actions for e.g. CD music, rotated text, and colorized shapes.
- You can use special sound effects and positional sound.
- You can create splash screens with movies, images, webpages, texts, etc.
- There is a particle system to create explosions, fireworks, flames, rain, and other effects.
- A number of advanced drawing functions are available, for example colorized text and textured polygons.
- It is possible to create 3D games using functions for 3D graphics.
- It is possible to create multiplayer games that can be played over a network.
- You can define your own room transitions.
- You can use functions to create, load, and modify resources (sprites, backgrounds, etc.) while the game is running.
- There is a collection of functions to create and use data structures.
- There are functions for motion planning.
- You get the possibility to include additional files in the game executables that can be used when the game is run.
- Standard Edition can be easily extended using extension package. These can be made by everybody and will in general be provided free of
- charge.
- Three such extension packages are included adding many room transitions, windows dialogs, and printing facilities.
- You can define your own trigger events.
- You can export and import resources, which makes it easier to collaborate on games.
Upgrading from Lite Edition costs only $39.99 (subject to change). This is a one-time fee that will be valid for all versions 8.x of GameMaker. When you are running the Lite Edition, you can upgrade by going to the Help menu, and selecting Upgrade from Lite Edition. If you purchased GameMaker before (and hence, have an license key), you can go to the Help menu, and pick Enter License Key. Once you have entered a valid, your copy of GameMaker will be upgraded. You must be connected to the internet for the upgrade to work. While GameMaker itself does not require an internet connection, it will require occasional access to maintain the license. If you can not connect your computer to the internet, you can download the license check file from YoYo Games website, and point the auto update system to it. if you fail to provide a valid file, or an internet connection when requested, your copy of GameMaker will be downgraded to Lite until such time as you do. I.1.6. Можно ли создавать на Game Maker программы? Ответ: Да. Достаточно посмотреть коснтруктор игр Noobster (http://game-maker.ru/infusions/pro_download_panel/download.php?did=927), HTML редактор HyperPage (http://www.yoyogames.com/games/71096-hyperpage), браузер GMB (http://www.yoyogames.com/games/122183), музыкальный проигрыватель visual music (http://www.game-maker.ru/infusions/pro_download_panel/download.php?did=351) и торрент-клиент GMTorrent (http://gmc.yoyogames.com/index.php?showtopic=482966).
I.1.7. Можно ли создавать на Game Maker 3D игры? Ответ: Безусловно. Взгляните на гоночные симуляторы SWERVE (http://www.yoyogames.com/games/113439-swerve) и Park Racer Game (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1038), gta-подобные игры Total Anarchy (http://gmc.yoyogames.com/index.php?showtopic=467300) и Crimelife 3 (http://gmc.yoyogames.com/index.php?showtopic=393243), онлайн шутер Metroid online (http://game-maker.ru/infusions/pro_download_panel/download.php?did=850), оффлайн шутер Ice Arena 3d (http://www.yoyogames.com/games/20640-ice-arena-3d), клон портала - Power Gates (http://www.yoyogames.com/games/20333-power-gates), авиасимулятор Aces High Over verlor Island (http://www.yoyogames.com/games/105-aces-high-over-verlor-island) и вестерн Guns and Spurs (http://www.yoyogames.com/games/126583-guns-and-spurs)!
I.1.8. Можно ли создавать на Game Maker онлайн игры? Ответ: Да. Можете сыграть в Arcane Adventures (http://gmc.yoyogames.com/index.php?showtopic=462962), Almora Online (http://gmc.yoyogames.com/index.php?showtopic=312634) и Gang Garrison 2 (http://www.yoyogames.com/games/149093-gang-garrison-2).
I.1.9. Где найти русское справочное руководство к Game Maker 8? Ответ: Вы можете скачать его здесь: http://gmakers.ru/index.php?action=tpmod;dl=get220 Или прочитать онлайн здесь: http://gmakers.ru/gamemaker_help/ 2) ПрограммаI.2.1. У меня появились / я скачал файлы с расширением *.gb1 - *.gb9. Что это? Ответ: Это бэкап-файлы (http://ru.wikipedia.org/wiki/Резервное_копирование) игр, сделанных на GM. Каждый раз когда вы сохраняетесь - бэкап файлы обновляются. В случае, если сохранили игру с критической ошибкой - вы можете удалить текущий исходник и работать с бэкап файлом. Для этого просто откройте его с помощью GM (ПКМ -> Открыть с помощью -> Game Maker 8). Выбрав пункт Preferences в меню File - вы увидите окно настроек GM, где во вкладке General вы можете либо вовсе отключить создание бэкапов, убрав флажок с "Keep backup copies of files", либо изменить их количество, изменив значение "Maximum number of backups".
I.2.2. Текст в редакторе кода стал меньше / больше. Как восстановить нормальный размер? Ответ: Используйте функциональные клавиши F7 и F8 (только для Game Maker 8).
I.2.3. Меню-помощи в редакторе кода перестало появляться. Что делать? Ответ: Нажмите F11 (только для Game Maker 8).
I.2.4. Что такое *.lib файлы? Я скачал lib файл, как мне его установить в Game Maker? Ответ: lib файлы - библиотеки действий GM. То есть, файлы, содержащие в себе описания "квадратиков", "пиктограмм" - называйте как хотите. Изначально в Game Maker их 7: move, main1, main2, control, score, extra и draw. Чтобы установить *.lib файл - достаточно положить его в папку lib, которая находится в директории Game Maker (к примеру: "C:\Program Files\Game_Maker8\lib") и перезапустить GM, чтобы изменения вступили в силу. Чтобы деинсталлировать либ-библиотеку - просто удалите файл из папки.
I.2.5. Могу ли я создавать свои *.lib файлы? Ответ: Да. Для этого используйте программу Library Maker, которую можно скачать по ссылке: http://www.yoyogames.com/downloads/extensions/extmaker.zip
I.2.6. Я скачал файлы с расширением *.gex, что это? Ответ: Это пакеты расширений, возможность использования которых была добавлена в Game Maker 7. После их установки - в ваш проект добавляются новые функции и/или либ-библиотеки.
I.2.7. Как использовать функции пакета расширения? Ответ: Перед тем как добавить пакет расширения в ваш проект - вам нужно установить его в Game Maker. Выберете из меню Resources пункт Select Extension Packages (Shift+Ctrl+E). Перед вами появится окно, в котором вы можете добавить какой-то пакет расширения в вашу игру или просмотреть информацию о нём / прочитать справочное руководство. Жмите кнопку "Install". В открывшемся окне вы можете удалить из Game Maker выбранный пакет расширения, нажав кнопку "Uninstall" и установить новый, нажав кнопку "Install" и выбрав *.gex файл. После установки пакетов расширений вы можете добавить какие-то из них себе в проект. Для этого вернитесь в первое окно (нажмите "OK"), выберите имя пакета в списке справа, и нажмите на появившуюся кнопку между списками. Убрать пакет расширения из вашего проекта вы можете аналогичным образом. Функции пакетов расширений в данном проекте можно посмотреть, выбрав из меню Scripts пункт Show Extension functions. Подробнее здесь: http://gmakers.ru/gamemaker_help/source/files/215_00_extensions.php I.2.8. Могу ли я создавать свои *.gex файлы? Ответ: Да. Для этого используйте программу Extension Maker, которую можно скачать по ссылке: http://www.yoyogames.com/downloads/extensions/extmaker.zip
I.2.9. Сохраняются ли шрифты в GMK файле? Ответ: Нет. Если в исходнике используется шрифт, которого нет на данном компьютере - в игре будет использован Arial. Исполняемый файл игры (*.exe) напротив, хранит все шрифты в себе.
I.2.10. Как защитить exe от декомпиляции? Ответ: Можно использовать антидекомпилятор: http://gmc.yoyogames.com/index.php?showtopic=422511 (работает с играми созданными на GM8.0, GM7.0 и GM6.1 (предварительно конвертированными для запуска на Windows Vista (http://wiki.yoyogames.com/images/7/77/GM_Convert_Game.zip)), а так же программу MoleBox (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1060).
I.2.11. Как изменить меню, которое появляется при нажатии на F2 в редакторе кода? Ответ: К папке с установленным Game Maker 8 вы можете найти файл "snippets.txt" (по умолчанию: C:\Program Files\Game_Maker8\snippets.txt). Теперь вы можете создать свои собственные шаблоны кода - это бывает очень полезно.
I.2.12. У меня Windows Vista/7, и любая, даже содержащая пустую комнату игра грузится очень долго, подолгу застревая на "Preparing Sounds". Как это исправить? Ответ: Откройте Диспетчер Устройств и из списка аудиоустройств удалите все, кроме последнего. Возможно, это придется делать после каждого выключения компьютера.
3) ИгростройI.3.1: Что такое шаг, что такое скорость комнаты? Ответ: В Game Maker за секунду проходит определённое количество шагов. Это количество определяет переменная room_speed (её можно задать в свойствах комнаты: settings -> Speed). Событие step event называется событием шага именно потому, что оно выполняется каждый шаг. К примеру, если в событии step event объекта вы напишете код "score += 1", и установите скорость комнаты на 30 шагов, то за секунду переменная score увеличится на 30. Таким же образом, если вы напишите "image_speed = 1", то за секунду у спрайта сменится 30 кадров, потому что переменная image_speed хранит в себе значение, на которое изменяется кадр спрайта каждый шаг. То же относится и ко времени. Если вы напишете "alarm[0] = 1", то событие таймера произойдёт через 1/30 секунды (для общего случая - 1/room_speed).
I.3.2. Что такое FPS? Это тоже самое, что и скорость комнаты? Ответ: В идеале, за секунду должно выполнится <room_speed> шагов, но иногда скорость выполнения шага медленнее, чем нужно. В этом случае время на выполнение шага превышает "1000/room_speed" миллисекунд (секунда состоит из 1000 миллисекунд, всего должно выполниться <room_speed> шагов). Количество шагов, которые выполняются за секунду, показывает переменная fps (Frames Per Second – количество кадров в секунду, не путать с First-Person Shooter). Например, если скорость комнаты - 30 шагов, а fps - 23, то в среднем шаг выполняется 43.4 миллисекунды(1000/23). В идеале, он должен выполняться меньше чем 33,(3) миллисекунды. Не забывайте, что в событие шага входит не только те действия, которые вы вписали в step event, но и отображение изображения на экране, обработка событий и др. Если fps меньше чем room_speed - значит нужно оптимизировать код в постоянно повторяющихся, или часто вызываемых событиях (особенно стоит обратить внимание на step, end step, begin step и draw events). Обратите внимание, что fps обновляется только раз в секунду. FPS можно отобразить в заголовке окна, написав такой код в step event какого-либо объекта: "room_caption = 'fps: ' + string(fps) + ' / ' + string(room_speed);"
I.3.3. Как работают функции рисования в GM? Что делают функции screen_redraw, screen_refresh? Ответ: Для начала следует понять, что вызывая функции рисования - вы рисуете не прямо на экране, а на внутренний буфер. В начале события draw внутренний буфер очищается, а в конце - отображается на экран. Рисуя что либо, к примеру, в step event - вы рисуете на внутренний буфер, но он не отображается на экран. Функция screen_refresh предназначена для того, чтобы обновить изображение на экране - она отображает внутренний буфер. Функция screen_redraw сначала выполняет все события рисования - заполняет внутренний буфер цветом фона, рисует фоны, вызывает события рисования всех объектов, а затем обновляет изображение на экране (отображает внутренний буфер). Механизм использования глубины можно описать следующим образом. В начале события draw event строится приоритетная очередь, в которой роль значения играет индекс объекта/тайла, а приоритет - глубина. Далее вся графика отображает в порядке приоритета, именно потому глубину рисования нельзя менять в draw event - приоритетная очередь уже построена. В случае с 3D - используется буфер глубины, и там ситуация немного иная. Безусловно, мы не можем знать наверняка, как всё устроено в Game Maker'е, если только сами разработчики нам об этом не расскажут. Это не точное описание внутренних механизмов GM, это лишь общий принцип работы функций рисования, и все факторы указывают на то, что он именно такой. I.3.4. Что такое комната? Что такое persistent комнаты, game save и game load? Ответ: Давайте поразмышляем. Что такое комната? Комната - это набор определённых настроек, опции видов и фонов, список всех объектов и тайлов. На самом деле, самая первая, "нулевая" комната - это комната загрузки. В ней, загружается движок GM и все внутренние ресурсы , инициализируется окно игры и загружается первая игровая комната. Под фразой "загружается комната" я подразумеваю следующие действия: 1) Назначаются значения всем переменным комнаты: 1.1) Индекс комнаты - room 1.2) Заголовок комнаты - room_caption 1.3) Ширина и высота комнаты - room_width и room_height 1.4) Скорость комнаты - room_speed 1.5) Постоянность комнаты - room_persistent 1.6) Цвет фона и его видимость - background_color и background_showcolor 2) Загружается массив видов: 2.1) Видимость в момент начала комнаты - view_visible[0..7]. 2.2) Позиция, ширина и высота вида: view_xview[0..7], view_yview[0..7], view_wview[0..7] и view_hview[0..7]. 2.3) Позиция, ширина и высота порта: view_xport[0..7], view_yport[0..7], view_wport[0..7] и view_hport[0..7]. 2.4) Граница вокруг преследуемого объекта: view_hborder[0..7] и view_vborder[0..7]. 2.5) Вертикальная и горизонтальная скорость: view_hspeed[0..7] и view_vspeed[0..7]. 2.6) Преследуемый объект - view_object[0..7]. 2.7) * Поворот вида - view_angle[0..7]. 3) Загружается массив фонов: 3.1) Видимость в момент начала комнаты - background_visible[0..7] 3.2) Отображать ли фон над объектами - background_foreground[0..7] 3.3) Индекс фонового изображения - background_index[0..7] 3.4) Позиция - background_x[0..7] и background_y[0..7] 3.5) Замощение комнаты по горизонтали/вертикали - background_htiled[0..7] и background_vtiled[0..7] 3.6) Вертикальная и горизонтальная скорость - background_hspeed[0..7] и background_vspeed[0..7] 3.7) Масштаб фона - background_xscale[0..7] и background_yscale[0..7] 3.8) * Цвет смешивания для фона - background_blend[0..7] 3.9) * Непрозрачность фона - background_alpha[0..7] 4) Создаются все тайлы: 4.1) Позиция тайла - x, y. 4.2) Индекс фона - background. 4.3) Часть фона - left, top, width, height. 4.4) Глубина тайла 4.5) id тайла, начинается с 10 000 001 (включительно) 5) Создаются все объекты, вычисляется instance_count и заполняется массив instance_id: 5.1) Позиция - x, y. 5.2) Индекс объекта - object_index. 5.3) id, начинается с 100 001 (включительно) 6) ^ Выполняется creation code объектов (который задаётся в комнате) 7) ^ Выполняется creation event объектов 8) # Game start (Выполняется только в момент начала игры) 9) ^ Room creation code (выполняется код, задаваемый в настройках комнаты) 10) Room start event
Действия не обозначенные символами выполняются в любом случае - при загрузке самой первой комнаты, при загрузке сохранения, при загрузке persistent комнаты и т.д. Действия, обозначенные символом "^" - выполняются только при первом попадании в комнату, а так же для всех не persistent комнат. Если вы вышли из постоянной комнаты, а потом вернулись - эти действия не выполнятся. Действия, обозначенные символом "*" - выполняются только при сохранении/загрузке игры или сохранении данных/загрузке постоянной комнаты. Эти настройки нельзя изменить в редакторе комнат, потому, при первом попадании в комнату они не загружаются, а получают значения по умолчанию. Действие же обозначенное символом "#" - событие начала игры, выполняются только один раз, при первой загрузке самой первой комнаты. Обратите внимание, что вне зависимости от того, является ли комната постоянной - событие Room start выполняется всегда.
Этот список действий может внести некоторую ясность в то, что конкретно происходит в начале игры и как реализован механизм сохранения постоянных комнат.
Если установлен persistent, при переходе в другую комнату - все данные о текущем состоянии комнаты перезапишутся: массивы видов, фонов, списки объектов и тайлов и т.п., а так же все локальные переменные всех объектов (стоит учесть, хотя массивы сохраняются, динамические структуры данных - нет). При сохранении игры сохраняются данные обо всех persistent комнатах, включая текущую (вне зависимости, постоянная она или нет) + глобальные переменные и, наверняка, что-то ещё. Сурфейсы, новые объекты, загруженные спрайты, фоны, звуки, изменения в действиях объектах (objext_event_*), динамические структуры данных, позиции проигрывания звуков, настройки игры (полноэкранность и т.п.), частицы - всё это НЕ сохраняется стандартным механизмом сохранения GM. Что же происходит при загрузке? Всего лишь заменяются данные для всех persistent комнат, включая текущую (не зависимо, постоянная ли она). Я лично предполагаю, что все значения локальных переменных записываются в creation code объектов, и этот код выполняется всегда. Однако, я всё равно обозначил его символом "^", так как знать наверняка не могу.
Написать свой механизм сохранения проще, чем кажется, стоит только всё продумать. I.3.5. Что такое lengthdir_x и lengthdir_y и как им пользоваться? Ответ: Чтобы вам легче было разобраться - начнём с небольшой задачи. Есть позиция, (x1,y1), направление - angle, и расстояние - dis. Как вычислить позицию (x2,y2), расположенную на расстоянии dis от позиции (x1,y1) в указанном направлении? (http://savepic.org/1206681.jpg) ссылка на изображение, размер: 23.4 кбайт, 160 x 160 точек (http://savepic.org/1206681.htm) Сейчас немного теории. Прямоугольный треугольник: Прямоугольный треугольник - это треугольник с углом 90° (прямым углом). Катет - одна из двух сторон прямоугольного треугольника, образующая прямой угол. Гипотенуза - сторона прямоугольного треугольника, противоположная прямому углу. Синус и Косинус: Из школьного курса геометрии вам должно быть известно два определения синуса: 1) синус острого угла это отношение катета, лежащего напротив этого угла к гипотеузе. 2) синус это ордината (y-координата, если кто забыл) точки, лежащей на единичной окружности. Косинус так же имеет два общеизвестных определения: 1) косинус острого угла это отношение катета, выходящего из этого угла (прилежащего катета), к гипотенузе. 2) косинус это абсцисса точки, лежащей на единичной окружности. Единичная окружность - это окружность с радиусом 1. Так как косинус (cos(angle)) по определению - (x2-x1)/dis, стаёт очевидно, что x2-x1 мы можем найти умножив значение косинуса на dis: cos(angle)*dis, а y2-y1 с помощью синуса: sin(angle)*dis. Однако, в декартовой системе координат абцисса направлена вверх, а не вниз, как в Game Maker. Потому, следует отразить координату y, отнять её от нуля или просто изменить её знак: -sin(angle)*dis. (http://savepic.org/1205657.jpg) ссылка на изображение, размер: 24.5 кбайт, 160 x 160 точек (http://savepic.org/1205657.htm) Но, что если угол angle не острый и не удаётся построить прямоугольный треугольник как нужно? Смотрим второе определение: (http://savepic.org/1211801.jpg) ссылка на изображение, размер: 29.4 кбайт, 160 x 160 точек (http://savepic.org/1211801.htm) т.е. в любом случае cos и sin будут работать как надо. Итак, формулы верны. Что же такое lengthdir_x и lengthdir_y? lengthdir_x(len, angle) = cos(angle)*dis; lengthdir_y(len, angle) = -sin(angle)*dis; Подведём итог: x2 = x1 + lengthdir_x(dis, angle); y2 = y1 + lengthdir_y(dis, angle); I.3.6. Что за переменная image_single, которой нет в справке? Ответ: Эту переменную оставили для совместимости с играми, разрабатываемыми в старых версиях Game Maker. Она изменяет кадр и автоматически устанавливает скорость анимации на 0. К примеру, вместо image_single = 3; Можно написать: image_index = 3; image_speed = 0; Не смотря на её удобность в некоторых случаях - рекомендуется использовать image_index и image_speed. I.3.7. Что это за функции, которые начинаются с приставки action_ и которые не описаны в справке? Ответ: Это встроенные функции в Game Maker, точно повторяющие действия стандартных *.lib библиотек. Они не имеют описания в справочном руководстве и для них не показывается подсказка в редакторе кода. Их рекомендуется использовать только новичкам, которые только-только перешли на код. В этом документе можно увидеть полный список этих функций: http://www.blackratstudios.com/games/DD_to_GML_7/Drag%20and%20Drop%20Icons%20and%20their%20GML%20Equals_Ver%207.html
I.3.8. Как работает оператор mod? Ответ: Оператор mod - это деление по модулю. Операция деление по модулю это нахождение остатка от деления одного числа на другое, т.е. той части числа, которая не поделилась нацело. К примеру, если поделить число 90 на 11 - получим 8.(18). Остаток же от деления будет 2 - число 90 можно записать как 11*8 + 2: 90 / 11 = 8.18181818... 90 div 11 = 8 90 mod 11 = 2 90 = (90 div 11) * 11 + (90 mod 11) I.3.9. Зачем нужен оператор var? Ответ: Когда вы создаёте объект - вы автоматически создаёте 50 локальных переменных и один массив: id object_index persistent solid depth mask_index visible
xstart ystart xprevious yprevious x y
hspeed vspeed speed direction friction gravity gravity_direction
sprite_index sprite_width sprite_height sprite_xoffset sprite_yoffset
image_index image_xscale image_yscale image_angle image_blend image_alpha
image_number image_speed image_single
bbox_left bbox_right bbox_bottom bbox_top
path_endaction path_index path_orientation path_position path_positionprevious path_scale path_speed
timeline_index timeline_loop timeline_position timeline_running timeline_speed
alarm Заданные локальные переменные в этом объекте остаются с ним до удаления или до конца игры. Если вы объявляете какие-то переменные в скрипте, а потом вызываете этот скрипт в объекте - все новые переменные остануться с этим экземпляром, захламляя собой память. Оператор var предназначен для объявления временных переменных, которые будут удалены по завершению выполнения этого скрипта. Эти переменные не являются локальными для данного экземпляра объекта, а общие для всех. К примеру, такой код не выдаст ошибки: var i; // Объявляем временную переменную i = 100; with o_test // Обращаемся к другому объекту a += i; // Используем временную переменную в этом объекте Создавать временные переменные можно не только в скриптах, но и в действиях объектов, коде создания комнаты, триггерах и т.п. I.3.10. Когда следует использовать switch, а когда if? Ответ: Оператор switch следует использовать в том случае, когда количество вариантов значения одной переменной превышает 2-3 раза. Конечно, многое зависит от ситуации, иногда даже четыре проверки удобно записать оператором if. Пример использовать оператора switch: switch varible { case value0: action1(); break; case value1: action2(); break; case value2: action3(); break; case value3: action4(); break; default: action5(); } Оператор if: if varible == value0 then action1() else if varible == value1 then action2() else if varible == value2 then action3() else if varible == value3 then action4() else action5();
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Декабрь 21, 2010, 13:50:08
II - ПРАКТИКА 1) Базовая работа с кодом и простые решенияII.1.1. Как ограничить значение переменной? Ответ: Для начала, следует учесть, что вы можете получить небольшой, но всё же выигрыш в производительности, проверяя значение переменной исключительно фактически после её изменения. То есть, если жизни игрока уменьшаются при столкновении с монстром и с огнём - немного производительней будет поставить две проверки в эти события, чем писать одну в step event, которая будет выполнятся каждый шаг. Однако, не стоит злоупотреблять этим в ущерб сопровождаемости кода. К примеру, если вам понадобится как-то изменить событие смерти игрока - вам придётся менять его в двух событиях (в лучшем случае), а не в одном (в случае со step event). Чтобы этого не происходило, лучше выносите повторяющиеся куски кода в скрипты или user events. Последние можно выполнить с помощью команды event_user(номер_события). Итак, при увеличении или уменьшении вы можете использовать такие простые проверки: variable += x; if variable > variable_max // Если переменная больше указанного значения, то... variable = variable_max; // Устанавливаем переменной максимальное значение variable -= x; if variable < variable_min variable = variable_min; Слегка понизив читабельность можно добится большей компактности кода, используя функции min и max: variable = min(variable + x, variable_max); // Если variable_min + x больше variable_max - выбираем меньшее, то есть, variable_max. variable = max(variable - x, variable_min); Часто в различных примерах вы можете встретить такую запись: variable = max(variable_min, min(variable, variable_max)); Однако, есть способ лучше, который я и предпочитаю использовать: variable = median(variable_min, variable, variable_max); // Находим среднее из значений, если variable < variable_min - средним становится variable_min и аналогично для variable_max. Например, если вы хотите ограничить передвижение игрока некоторыми рамками, скажем, сделать, чтобы он не выходил за границы комнаты - вы можете написать так: x = median(0, x, room_width - sprite_width); y = median(0, y, room_height - sprite_height); II.1.2. Мне нужно написать текст с указанием значения переменной, как? Ответ: Пропишите отдельному объекту в событие draw, такой код: draw_text (x, y, ' Текст до переменной ' + string(переменная) + ' Текст после'); Не забудьте, что переменная может быть названа только на английском языке, без пробелов и начинаться она должна с буквы. Так же, если переменная всегда хранит текстовое значение - её не обязательно заносить в string(). II.1.3. Как сделать, чтобы герой TDS смотрел на мышь? Ответ: Так как направление 0 - вправо, нужно повернуть спрайт игрока вправо и прописать такой код в step event объекту: image_angle = point_direction (x, y, mouse_x, mouse_y); Так же убедитесь, что в draw event вы не рисуете спрайт объекта без использования переменной image_angle. К примеру, если вы рисуете спрайт таким образом: draw_sprite(sprite_index, image_index, x, y); следует заменить эту строку на: draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); II.1.4. Как запросить имя игрока, и в последствии использовать его в сообщениях и диалогах? Ответ: Запросить имя можно таким образом: global.Hero_name = get_string('Как вас зовут?', 'DeatHSoul'); После этого введённое имя игроком будет хранится в глобальной переменной Hero_name, которая будет сохранять свое значение во всех комнатах, и вы можете использовать её, чтобы получить имя игрока. Например, так: show_message('Привет ' + global.Hero_name + '!'); II.1.5. Как программно отразить спрайт по вертикали или горизонтали? Ответ: Чтобы отразить спрайт по горизонтали - нужно написать: "image_xscale = -1;", по вертикали: "image_yscale = -1;". Однако, убедитесь, что ваш спрайт рисуется с использованием переменных image_xscale и image_yscale. т.е. если вы рисуете спрайт функцией draw_sprite - замените её на функцию draw_sprite_ext.
II.1.6. Как повернуть комнату? Ответ: Используйте view_angle[0..7], и убедитесь, что у вас включен указанный вид. Если вы хотите, чтобы вид поворачивался вместе с игроком - учтите, что его нужно поворачивать в противоположную сторону. Вместо: view_angle[0] = direction; пишите: view_angle[0] = -direction; II.1.7. Как сделать паузу между выстрелами? Ответ:create event: shooting_ready = 1; // Указываем, что игрок готов стрелять step event: if (shooting_ready) // Если игрок готов стрелять { // ... // Стреляем alarm[0] = room_speed*<количество_секунд>; // Устанавливаем время, через которое игрок снова будет готов стрелять shooting_ready = 0; // Указываем, что игрок более не может стрелять } alarm 0 event: shooting_ready = 1; // После истечения времени указываем, что игрок готов стрелять II.1.8. Как получить имя объекта по его id? Ответ: [gml]name = object_get_name(ID.object_index);[/gml] Где ID - id объекта, имя которого требуется получить. II.1.9. Как получить индекс объекта по его имени (строка)? Ответ: [gml]object = execute_string('return '+string(obj_name));[/gml]
II.1.10. Как сделать простую паузу одной кнопкой? Ответ: Один из самых простых алгоритмов состоит в использовании функции keyboard_wait (код нужно вставить в событие нажатия соответствующей клавиши): /// Отрисовка сообщения о паузе игры draw_set_color(c_black); draw_set_alpha(0.3); draw_rectangle(0, 0, view_wview, view_hview, 0); // Отрисовка фона. Если у вас не используются виды - замените view_wview и view_hview на room_width и room_height соответственно. draw_set_alpha(1); draw_set_halign(fa_center); draw_set_valign(fa_middle); draw_text(view_xview + view_wview/2, view_yview + view_hview/2, 'PAUSE'); // Отрисовка текста. Если у вас не рисует русский текст - посмотрите вопрос II.4.6.
// Обновляем экран screen_refresh(); // Эта функция в действительности отображает на экране всё то, что мы нарисовали ранее
// Останавливаем игру до нажатия какой-либо клавиши keyboard_wait(); Если вы хотите, чтобы игра продолжалась только при нажатии какой-то конкретной клавиши, к примеру, клавиши P (или, скажем, клике мыши) - замените последнюю строку скрипта (keyboard_wait()) на: io_clear(); // Очищаем состояние клавиатуры
while true // Запускаем вечный цикл { if keyboard_check_pressed(ord('P')) break; // Если игрок нажал Р - выходим из цикла keyboard_wait(); // Ожидаем нажатия какой-нибудь клавиши }
io_clear(); // Снова очищаем состояние клавиатуры, чтобы пауза не влючилась сразу же после выключения II.1.11. Как сделать, чтобы значение переменной сохранялось между комнатами? Ответ: Первый способ - сделать переменную глобальной.Пример объявления глобальных переменных: global.variable = 100; globalvar variable2; variable2 = 100; Второй способ - сделать объект, в котором объявляется переменная - постоянным (persistent). Все глобальные переменные можно посмотреть в дебаг режиме: Tools -> Show Global Variables. II.1.12. Как определить, на какую кнопку в сообщении нажал пользователь? Ответ:Вариант 1: switch show_message_ext('Text', 'button 1', 'button 2', 'button 3') { case 1: show_message('button 1'); break; case 2: show_message('button 2'); break; case 3: show_message('button 3'); break; } Вариант 2: var message; message = show_message_ext('Text', 'button 1', '', 'button 2'); if message == 3 { show_message('button 2'); } Вариант 3: if show_message_ext('Text', 'button 1', '', 'button 2') == 3 { show_message('button 2'); } и так далее... II.1.13. Как выполнить действие, только если объект находится в определённом радиусе? Ответ: Для того, чтобы проверить, находится ли объект в определённом радиусе - можно использовать функцию point_distance. Проверяя, на каком расстоянии находится объект - мы получим определённый радиус. Пример: if point_distance(x, y, some_object.x, some_object.y) < 200 // 200, в данном случае, радиус { // Выполняем действия } II.1.14. Как выполнить действие, только если герой собрал все монеты/ресурсы и т.п.? Ответ: Для этого нужно проверить кол-во объектов в комнате. Пример: if instance_number(o_star) == 0 { // Выполняем нужные действия } II.1.15. Я устанавливаю image_speed на единицу, но кадр спрайта меняется мгновенно, а не один раз в секунду! Почему? Ответ: Присвоив переменной image_speed единицу, вы устанавливает смену кадра спрайта каждый шаг. То есть, если у вас скорость комнаты - 30 шагов, то за секунду у спрайта сменится 30 кадров. Если вам нужно, чтобы за секунду менялся один кадр, пишите: image_speed = 1/room_speed; Тогда каждую секунду кадр будет изменяться на 1/30 (если у вас скорость комнаты - 30 шагов), и за секунду кадр всего изменится на 30/30, то есть, на 1. II.1.16. Я устанавливаю таймер на единицу, но действие таймера происходит мгновенно, а не через одну секунду! Почему? Ответ: Таймеры измеряется в шагах, и установив таймеру время в единицу - он выполнится через один шаг, то есть, через 1/room_speed секунды. Для того, чтобы таймер выполнился через одну секунду, нужно писать так: alarm[0] = room_speed;; Таким образом, событие таймера выполнится через room_speed шагов, а room_speed шагов составляют одну секунду. 2) Движение и столкновенияII.2.1. Как сделать, чтобы при падении игрока сверху на монстра - монстр умирал, а просто при столкновением его с монстром - умирал игрок? Ответ: При столкновении с монстром нужно проверять позицию игрока. Если игрок выше монстра - убиваем монстра, иначе - наносим урон игроку. Пример, при столкновении игрока с монстром: if (yprevious + bbox_bottom - y < other.bbox_top) // здесь bbox_bottom — переменная, которая хранит в себе значение y-позиции нижней границы маски спрайта, bbox_top — соответственно, верхней { with (other) instance_destroy(); // убийство монстра } else { // Наносим урон игроку. } II.2.2. Как сделать фон, двигающийся относительно позиции игрока? Ответ: Пример, end step event: background_x[0] = view_xview[0] * 0.75; II.2.3. Как заставить следовать один объект за другим? Ответ: Если вы хотите, чтобы объект не останавливался при столкновении с другими объектами - пропишите ему в step event такой код: speed = скорость; direction = point_direction (x, y, объект.x, объект.y); Если вы хотите, чтобы объект останавливался при контакте с любым / только с твёрдым объектом - используйте такой код: mp_linear_step(объект.x, объект.y, скорость, checkall); Если вместо checkall вы впишите истину, то экземпляр объекта остановится при контакте с экземпляром любого объекта. Если ложь, то он остановиться только при контакте только с твёрдыми экземплярами объекта. Если же вы хотите, чтобы объект огибал препятствия на пути к цели - используйте функцию mp_potential_step аналогично предыдущему способу. II.2.4. Как сделать разгон для машины, как сделать чтобы игрок постепенно разгонялся и тормозил? Ответ: На самом деле, на разгон и торможение машины влияет масса показателей. Для общего случая - нужно задать скорость разгона, силу торможения, силу трения и максимальную скорость движения (это касается любого абстрактного игрока, как машини так и реального героя). Простая схема механизма разгона / торможения для машины будет выглядеть примерно так: if keyboard_check(vk_up) { скорость += скорость_разгона; // Увеличиваем скорость машины. } else if keyboard_check(vk_down) { скорость -= сила_торможения; // Уменьшаем её скорость. } else { скорость -= сила_трения; }
скорость = median(0, скорость, максимальная_скорость); // Ограничиваем скорость, чтобы она не могла быть отрицательной и не превышала максимальный порог. Управление игроком в плафтормере будет выглядеть несколько иначе, хотя и сохраняет основную схему: // В платформере скорость может принимать отрицательное значение - движение влево (соответственно положительное - движение вправо). if keyboard_check(vk_left) spd = median(-speed_max, spd - 0.5 , speed_max); else if keyboard_check(vk_right) spd = median(-speed_max, spd + 0.5 , speed_max); else spd = max(abs(spd) - 0.2, 0) * sign(spd); // Короткая запись довольно большого куска кода. Если вы не можете понять его значение - вы можете увидеть расшифровку чуть ниже.
if place_free(x + spd, y) // Если ничто не преграждает путь игроку { x += spd; // Двигаем игрока } else { var dir; if spd > 0 // Самый простой код, позволяющий определить направление движения. dir = 0; else dir = 180; move_contact_solid(dir, speed_max); // Пододвигаем игрока вплотную к стене. spd = 0; // Обнуляем скорость. } speed_max в этом коде - максимальная скорость игрока по горизонтали. spd - текущая скорость игрока. Эта строка: spd = max(abs(spd) - 0.2, 0) * sign(spd); Скрывает в себе весь этот код: if spd > 0 { spd -= 0.2; if spd < 0 spd = 0; } else { spd += 0.2; if spd > 0 spd = 0; } То есть, она уменьшает скорость передвижения героя, сохраняя направление (знак числа). II.2.5. При повороте мой герой застревает в стене. Я использую "image_angle = point_direction(x, y, mouse_x, mouse_y);", в чём причина? Ответ: Переменная image_angle поворачивает не только картинку, но и маску объекта. Чтобы маска не поворачивалась - нужно использовать свою переменную, к примеру, angle. Пример: create event: angle = 0; step event: angle = point_direction(x, y, mouse_x, mouse_y); draw event: draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, angle, image_blend, image_alpha); II.2.6. Почему быстрые пули могут пролетать через стенку? Ответ: Для начала, нужно понять, почему это происходит. Дело в том, что за один шаг пуля мгновенно перемещается на некоторое расстояние, хотя столкновение проверяется только в новой позиции - при большой скорости пуля может запросто "перескачить" стенку. Как вариант, можно использовать такой код в step пули: var i; for (i = sprite_width; i <= speed; i += sprite_width) { if place_meeting(x + lengthdir_x(i,direction), y + lengthdir_y(i,direction), o_wall) // Если в этой позиции есть стена, то... { x += lengthdir_x(i, direction); // Двигаемся к позиции столкновения y += lengthdir_y(i, direction); event_perform(ev_collision, o_wall); // Вызываем событие столкновения со стеной } } II.2.7. Как сделать, чтобы игрок в tds двигался по диагонали с той же скоростью, что и по прямой? Ответ: Проблема состоит в том, что диагональ квадрата больше стороны квадрата. При чём тут квадрат? А вот в при чём: когда сдвигаем героя просто вверх, просто влево, вправо или вниз - он сдвигается на n пикселей, когда же мы сдвигаем его по диагонали - наш герой в действительности сдвигается на размер диагонали квадрата со стороной в n пикселей (к примеру, если мы сдвигаем героя на 100 пикселей влево и 100 пикселей вправо - герой в действительности сдвигается на ~141 пиксель). Соотношение диагонали квадрата к его стороне примерно равно 0.707. Чтобы получить нормальный сдвиг - нужно поделить скорость на корень из двух (~1.41) или умножить на 0.707 (1/sqrt(2)). Рисунок: http://savepic.org/1031650.htm Скачать пример: tds move.gmk (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2565)
II.2.8. Как сделать плавный поворот турели? Ответ: Для этого нужно добавить два скрипта. Первый, get_angle_difference - вычисляет разницу между двумя направлениями: /*************************************************** Скрипт возвращает разницу между двумя направлениями. argument0 - первое направление; argument1 - второе направление направление; ***************************************************/ var diff; diff = (argument1 - argument0) mod 360; if diff < 0 diff += 360; if diff > 180 return -(360 - diff); else return diff; Второй, smooth_angle (здесь название может быть любым) - вычисляет новое направление: /* Скрипт плавно изменяет направление башни до требуемого Возвращает полученное направление argument0 - текущее направление argument1 - требуемое направление argument2 - скорость изменения направления */ var diff; diff = get_angle_difference(argument0, argument1); if abs(diff) < argument2 return argument1;
return argument0 + argument2 * sign(diff); Пример использования, step event: image_angle = smooth_angle(image_angle, point_direction(x, y, mouse_x, mouse_y), 3); II.2.9. Как сделать движущиеся платформы в платформере? Ответ: На самом деле, в этом нет ничего сложного, нужно только хорошенько подумать. Если вы используете встроенные механизмы движения, вроде vspeed и gravity - позиция игрока измениться после step event и до end step event. Значит, платформа, как и игрок сдвинется после step'а игрока. Итак, в step event игрока мы проверяем, нет ли платформы под игроком. Если под игроком есть подвижная платформа - мы записываем её id в переменную, чтобы двигать игрока за ней. В end step игрока мы сдвигаем игрока относительно платформы, на которой он стоит. Далее мы проверяем, если игрок всё же столкнулся с платформой (к примеру, когда горизонтальная платформа наехала на игрока) - мы возвращаем платформу на предыдущую позицию и меняем её направление движения - буквально "выталкиваем" из игрока. В коде это выглядит примерно так: create event игрока: platform = noone; // Изначально игрок не стоит на подвижной платформе step event игрока: //... platform = instance_place(x, y + 1, o_moving_platform); // Определяем id платформы под игроком, если под игроком нет платформы - функция возвратит значение noone, -4. id всегда начинается с 100001, что значит - можно использовать проверку "if platform", что аналогично "if platform >= 0.5". Если для вас эта проверка в новинку, можете писать "if platform != noone" end step event игрока: //... if platform // Если игрок стоит на платформе, то... { x += platform.hspeed; // Двигаем игрока относительно платформы y += platform.vspeed; }
platform = instance_place(x, y, o_moving_platform); if platform // Если на игрока наехала платформа, то... { with platform { x = xprevious; // Возвращаем платформу на предыдущую позицию y = yprevious; hspeed *= -1; // Инвертируем скорость, если платформа двигалась влево - она будет двигаться вправо и т.п. vspeed *= -1; } } P.S: если у вас возникают проблемы со столкновениями, залипания игрока в платформах и т.п. - советую вам отказаться от использования vspeed и hspeed, так как встроенный механизм движения автоматически останавливает объект при столкновении c solid объектом. II.2.10. Как сделать движение по неровной поверхности в платформере? Ответ: Здесь тоже нет ничего сложного. Проблема в том, что иногда игроку может препятствовать всего один пиксель, и чтобы на него взобраться - приходится прыгать. Потому, нужно создать некоторую имитацию "ног человека" - за один шаг игрок может взобраться на несколько пикселей, без прыжка. Итак, сначала задаётся максимальная высота, на которую может взобраться игрок - обычно 4-8 пикселей, во время движения в цикле проверяется сначала позиция прямо возле игрока, потом на один пиксель выше, на два пикселя выше, и так до максимальной высоты, на которую может взобраться игрок за один шаг. Эта картинка наглядно демонстрирует метод: http://savepic.net/1109905.jpg В коде это будет выглядеть примерно так: step event: var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. { if place_free(x - spd, y - i) // Если данная позиция свободна, то... { x -= spd; // Двигаем игрока y -= i; break; // Завершаем цикл } } }
//... Где vdis_max - максимальная высота, на которую может взобраться игрок за один шаг, spd - скорость передвижения игрока. В случае, если нужно реализовать ещё и быстрый спуск по ступенькам вниз - код будет выглядеть примерно так: var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. if place_free(x - spd, y - i) // Если данная позиция свободна { x -= spd; // Двигаем игрока y -= i; if place_free(x, y + 1) // Если игрок не стоит на платформе, if !place_free(x, y + vdis_max2 + 1) // Но она под ним есть! for (i = 0; i < vdis_max2 + 1; i += 1) // Проверяем все позиции немного ниже его { if !place_free(x, y + i) // Если в данная позиция занята твёрдым объектом { y += i - 1; // Двигаем игрока вплотную к этому объекту break; // Завершаем цикл } } break; // Завершаем цикл } } Собственно, эти циклы - самописные аналоги функций move_outside_solid и move_contact_solid. При желании их можно заменить встроенными функциями. II.2.11. Как сделать, чтобы игрок запрыгивал на платформы снизу? Ответ: Идея проста: выполнять событие столкновения с платформой только если игрок находится выше платформы. Переменная bbox_bottom - нижняя граница прямоугольника, ограничивающего спрайт объекта. bbox_top, соответственно, верхняя. Можно было бы просто сравнить bbox_bottom игрока и bbox_top платформы - но часто бывает так, что событие столкновения вызывается уже тогда, когда игрок непосредственно пересекается с платформой, и проверка может не сработать. Потому, поверку в событии столкновения игрока с платформой можно записать так: if bbox_bottom-vspeed <= other.bbox_top // Если в предыдущей позиции игрок был выше платформы, а теперь столкнулся с ней, то... { // Выполняем события столкновения... (можно вернуть игрока на предыдущую позицию, и с помощью move_contact_solid сдвинуть его вплотную к платформе) } Так же обратите внимание, что объекты, которые движутся с помощью стандартных механизмов движения GM - автоматически останавливаются при контакте с solid объектами. II.2.12. Как сделать, чтобы игрок скользил по неровным стенам в tds игре? Ответ: Используется тот же принцип, что и с движением по неровной поверхности в платформере, только реализуется немного иначе. Если позиция перед игроком занята - пытаемся изменить направление игрока так, чтобы позиция была свободна - на 10 градусов влево/вправо, на 20 градусов влево/вправо и т.д. Пример реализации: var spd, dir, angle, angle_step, lx, ly, i; spd = 8; // Скорость движения игрока dir = -1; angle = 90; // Максимальный поворот игрока angle_step = 5; // Величина, на которую увеличивается направление в шаге цикла
if keyboard_check(ord('W')) dir = 90; // В зависимости от того, какую клавишу нажал пользователь - определяем направление игрока if keyboard_check(ord('A')) dir = 180; if keyboard_check(ord('S')) dir = 270; if keyboard_check(ord('D')) dir = 0;
if dir != -1 // Если игрока нужно подвинуть, то... { for (i = 0; i < angle; i += angle_step) // Цикл отклонения. В начале - проверяем позицию прямо перед игроком, затем +-angle_step, +-angle_step*2 и т.д. { lx = lengthdir_x(spd, dir + i); // Вычисляем смещение игрока ly = lengthdir_y(spd, dir + i); if place_free(x + lx, y + ly) // Если эта позиция свободна, то... { x += lx; // Двигаем игрока y += ly; break; // Завершаем цикл } lx = lengthdir_x(spd, dir - i); // Проверяем позицию левее; действия и проверки аналогичны ly = lengthdir_y(spd, dir - i); if place_free(x + lx, y + ly) { x += lx; y += ly; break; } } } Для ускорения работы алгоритма можно увеличить значение angle_step и/или уменьшить значение angle. Для увеличения точности нужно уменьшать значение angle_step. II.2.13. Как прикрепить башню танка к самому танку? Ответ: Во-первых, позицию башни танка нужно изменять исключительно после изменения позиции танка, чтобы она не отставала. Прикрепить башню можно двумя способами, либо написать примерно такой код в step event башни: x = o_panzer.x; // Изменяем позицию башни y = o_panzer.y; Либо в draw event сразу рисовать спрайт башни в нужной позиции: draw_sprite_ext(sprite_index, image_index, o_panzer.x, o_panzer.y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); II.2.14. Как сделать, чтобы интерфейс не отставал от вида при движении? Ответ: Позицию элементов интерфейса нужно менять после изменения позиции объекта, за которым следит вид - в end step event либо в draw event.
II.2.15. Как определить позицию столкновения? Как определить, в какую сторону ударил снаряд? Ответ: Определить позицию столкновения часто бывает довольно сложно, если снаряд и противник имеют сложную форму. Вычислить позицию столкновения можно двумя способами: относительно пули, и относительно объекта, с котором столкнулась пуля. Если пуля круглая или всё время повёрнута в сторону полёта - проще всего. Для начала нам нужно определить расстояние от центра спрайта до точки столкновения при повороте 0 градусов (для круглой пули поворот не учитывается). Если пуля использует bbox для проверки столкновений - ограничивающий прямоугольник, формула может выглядеть так: len = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index) Событие столкновения часто вызывается уже тогда, когда пуля непосредственно над объектом. Потому, перед поиском точки столкновения нужно выполнить такой код: x = xprevious; // Возвращаем пулю на предыдущую позицию y = yprevious; move_contact_solid(direction, speed); // Пододвигаем её вплотную к объекту (объект должен быть твёрдым) Итак, если направление пули - direction, код будет выглядеть так: var len, xx, yy; x = xprevious; y = yprevious; move_contact_solid(direction, speed);
len = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index); xx = x + lengthdir_x(len, direction); yy = y + lengthdir_y(len, direction); Где xx, yy - полученная точка столкновения. Если пуля неровная, но объект, с которым она столкнулась повёрнут в ней, либо он круглый - выполняем те же действия, только для объекта-преграды. В случае, когда таким способом точку столкновения обнаржуить не удаётся - вам придётся придумывать собственные формулы, для вашего конкретного случая. II.2.16. Как сделать, чтобы герой в игре жанра "лабиринт" (в игре с видом сверху) мог толкать ящики? Ответ: Реализация возможности двигать ящики зависит от того, как реализовано управление игроком. Если он двигается за счёт speed и direction, можно поставить такой код в событие столкновения ящика с игроком: if place_free(x + lengthdir_x(other.speed, other.direction), y + lengthdir_y(other.speed, other.direction)) // Если ящик можно сдвинуть (позиция свободна) { x += lengthdir_x(other.speed, other.direction); // Двигаем ящик по направлению движения игрока y += lengthdir_y(other.speed, other.direction); } else // Если ящик нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию, чтобы он не застрял в ящике { x = xprevious; y = yprevious; speed = 0; } } Если игрок двигается за счёт vspeed и hspeed, можно использовать такой код (практически аналогичный предыдущему): if place_free(x + other.hspeed, y + other.vspeed) { x += other.hspeed; y += other.vspeed; } else { with other { x = xprevious; y = yprevious; vspeed = 0; hspeed = 0; } } В случае, если игрок двигается непосредственно через x и y - можно использовать такой код: var dx, dy; // Объявляем временные переменные dx = other.x - other.xprevious; // Вычисляем dy = other.y - other.yprevious;
if place_free(x + dx, y + dy) // Если ящик можно сдвинуть { x += dx; // Двигаем ящик по направлению движения игрока y += dy; } else // Если ящик нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию { x = xprevious; y = yprevious; } } Можно усовершенствовать код, используя функцию move_contact_solid, для того, чтобы придвинуть игрока к ящику. Ещё можно вычислять скорость игрока и сдвигать ящик на вдвое меньшее расстояние, чтобы создать эффект тяжести. II.2.17. Как сделать, чтобы пуля вылетала из дула? Ответ: Нужно использовать lengthdir_x и lengthdir_y. Предположим, у нас есть такой спрайт: (http://savepic.org/1202587.jpg) ссылка на изображение, размер: 19.2 кбайт, 160 x 160 точек (http://savepic.org/1202587.htm) Красный крест - центр спрайта. Пуля должна создаваться на конце дула: (http://savepic.org/1188251.jpg) ссылка на изображение, размер: 21.6 кбайт, 160 x 160 точек (http://savepic.org/1188251.htm) Для того, чтобы она создавалась в нужном месте нужно: 1) Записать координаты центра спрайта и позиции, в которой нужно создать объект; 2) Вычислить расстояние между этими двумя координатами; 3) Вычислить направление между этими двумя координатами. Тепрь, пулю можно создавать в этой позиции: xx = x + lengthdir_x(len, direction + dir); yy = y + lengthdir_y(len, direction + dir); Где len - расстоние между двумя точками, direction - текущее направление объекта, dir - направление от центра спрайта к точке на конце дула. Расстояние и направление можно вычислить с помощью функций point_distance и point_direction. Для более лёгкого расчёта координат можно использовать программу (http://forum.hellroom.ru/index.php?topic=2416.msg18972#msg18972). II.2.18. Как реализовать мгновенные пули? Ответ: Для реализации мгновенных пуль нужно либо написать свой алгоритм, аналогичный collision_line, либо использовать move_contact_solid. К примеру, при стрельбе вы могли бы использовать подобный алгоритм: var i, temp_x, temp_y; // Объявляем временные переменные for(i = 0; i < shoot_distance; i += 4) { temp_x = x + lengthdir_x(i, direction); // Вычисляем новую позицию temp_y = y + lengthdir_y(i, direction); obj = collision_circle(temp_x, temp_y, 2, all, 0, 0); if obj != noone // Если в этой позиции находится какой-то объект { if obj.object_index = o_enemy // Если это враг, то... { with obj hp -= 10; // Уменьшаем его кол-во жизней } if obj != id // Если это не тот объект, кто стреляет, то... { break; // Завершаем цикл } } } Где shoot_distance - максимальная дистанция, которую может достигнуть пуля, direction - направление полёта пули и o_enemy - объект врага. Заметьте, что hp не изначально определённая переменная, и она использована здесь для примера. Для оптимизации скрипта - можно увеличить кол-во пикселей, на которое смещается позиция проверки каждый шаг (4 по умолчанию), или заменить проверку collision_circle чем-то вроде collision_point. Обратите внимание, что проверка производиться для всех объектов, но, если, к примеру, в одной позиции будет одновременно находится объект врага и объект, скажем, решётки на полу - может возникнуть баг, так как пуля может не проверить столкновение с врагом. В таком случае - для всех объектов, с которыми происходит действие пули - можно создать родитель (parent), и заменить all в коде на его имя. Другой вариант - делать несколько проверок для каждого объекта. Стоит учесть, что это далеко не единственный способ реализации мгновенной стрельбы. 3) РисованиеII.3.1. Как отобразить объект для конкретного игрока, в случае, если у меня включено два вида? Ответ: Используйте переменную view_current. Пример: if view_current = 0 { draw_text(view_xview[view_current], view_yview[view_current], 'Игрок 1'); }
if view_current = 1 { draw_text(view_xview[view_current], view_yview[view_current], 'Игрок 2'); }
II.3.2. Я отрисовываю на экране, к примеру, текст, но когда я двигаюсь - он улетает за границы экрана. Как сделать так, чтобы текст оставался в исходной позиции? Ответ: На самом деле, позиция текста не меняется, однако координаты вида, напротив, изменяются. Вид - область, которую нужно отрисовать на экране. Чтобы отрисовать что-либо на виде - к координатам x и у нужно прибавлять view_xview и view_yview соответственно. Например: draw_text(view_xview + 16, view_yview + 32, "Text"); Чтобы отрисовывать текст, например, над главным героем - можно написать так: draw_text(o_player.x + 16, o_player.y - 32, "Text"); II.3.3. Я пишу в событие draw event в объекте игрока отображение жизней (например). Но в игре спрайт игрока не отображается. В чём причина? Ответ: Если событие draw event пусто - GM автоматически отрисовывает спрайт объекта, в случае, если он находится в пределах вида. Если же вы задали в этом событии какие-то действия - GM не может знать, находится ли ваша графика в пределах вида, или вне его. Потому, эти действия выполняются в любом случае, а спрайт объекта не отображается. Чтобы нарисовать спрайт вручную - нужно дописать такой код в начало события draw event: draw_sprite_ext(sprite_index, image_index, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha); Эта функция использует встроенные переменные для изменения масштаба, прозрачности, поворота и тд. спрайта, но если вы не используете эти функции - вы можете писать просто draw_sprite(sprite_index, image_index, x, y); При использовании GameMaker: Studio, можно использовать специальную функцию draw_self() II.3.4. Как изменить глубину объекта в draw event? Ответ: Глубину объекта прямо в событии draw изменить нельзя. Можно использовать несколько объектов с разной глубиной или просто переставить действия в событии рисования (если вы используете 3D - почитайте про d3d_set_depth(depth) (http://gmakers.ru/gamemaker_help/source/files/415_02_drawing.php)).
II.3.5: Вопрос 1: Как сделать, чтобы когда герой был ниже дерева - он был над ним, а когда выше - за ним? Вопрос 2: Какую нужно использовать формулу, чтобы вычислить глубину объекта в изометрии или в играх с видом как в классических jrpg? Ответ: Для игр с видом как в классических jrpg обычно используется формула depth = -y; при условии, что центр спрайта находится в точке столкновения объекта с землёй, а не в (0,0). Эту код нужно поставить в create event статических объектов, и step event динамических. Чем ниже объект, тем меньше его глубина, тем выше он рисуется. Для изометрии можно использовать формулу depth = -(y - sprite_yoffset + (sprite_height + H) / 2), где H - высота объекта над уровнем земли. Если у одного и того же спрайта высота точек спрайта над уровнем земли разная - нужно использовать буфер глубины, то есть - 3D технологии. II.3.6. Как сделать ссылку / Текст, при клике на который выполнялось бы определённое действие? Ответ: Можно использовать следующий скрипт: /*************************************************** Скрипт рисует ссылку. argument0 - х; argument1 - y; argument2 - текст; Возвращает 1, если игрок кликнул на текст, иначе - 0. ***************************************************/ var xx, yy, str, width, height; // Задаём временные переменные xx = argument0; yy = argument1; str = argument2; width = string_width(str); height = string_height(str);
if mouse_x > xx and mouse_y > yy and mouse_x < xx + width and mouse_y < yy + height // Если пользователь навёл на мышку, то... { draw_set_color(c_red); // Устанавливаем цвет, с которым рисуется выделенная ссылка draw_text(xx, yy, str); // Рисуем текст draw_line(xx, yy + height, xx + width, yy + height); // Рисуем подчёркивание if mouse_check_button_released(mb_left) // Если пользователь кликнул на ссылку, то... { return 1; // Возвращаем 1, и завершаем работу скрипта } } else { draw_set_color(c_blue); // Рисуем ссылку обычным цветом draw_text(xx, yy, str); }
return 0; // Возвращаем 0 - пользователь не кликал на ссылку Пример использования, draw event: if draw_text_button(0, 0, 'button') { execute_shell("http://google.com/", 0); } Для открытия web страницы в игровом окне можно использовать функцию splash_show_web. II.3.7. Можно ли для хелсбара использовать спрайт, а не цвет? Ответ: Конечно! draw_sprite(s_healthbar, 0, view_xview + 8, view_yview + 8) //Рисуем фон draw_sprite_part(s_healthbar, 1, 0, 0, sprite_get_width(s_healthbar) * (Health / Health_max), sprite_get_height(s_healthbar), view_xview + 8, view_yview + 8) //Рисуем жизни на фоне s_healthbar - спрайт хелсбара, первый кадр должен быть фоном хелсбара, а второй кадр - картинка полностью заполненного жизнями хелбара. Health - текущее кол-во жизней, Health_max - максимальное кол-во жизней. view_xview + 8, view_yview + 8 - позиция хелсбара II.3.8. Как сделать, чтобы при наведении на объект высвечивалась информация о нём? Ответ: В draw event объекта, при наведении на который должна высвечиваться информация следует добавить такой код: if position_meeting(mouse_x, mouse_y, id) // Если в позиции мышки находится данный экземпляр объекта, то... { // Рисуем нужную информацию. } Так же не стоит забывать, что если добавить какой-то код в событие draw - GM перестанет автоматически рисовать спрайт объекта, так что его отрисовку нужно добавить вручную (с помощью функции draw_sprite, к примеру). II.3.9. Как повернуть сурфейс относительно его центра? Ответ: Нужно использовать 3D-преобразования, которые отлично работают и в 2D. Пример: d3d_transform_add_translation(-surface_get_width(surface)/2, -surface_get_height(surface)/2, 0); // Устанавливаем сурфейс в центр d3d_transform_add_rotation_z(image_angle); // Поворачиваем его на величину image_angle d3d_transform_add_translation(x, y, 0); // Сдвигаем в нужную позицию, там, где будет рисоваться сурфейс draw_surface(surface, 0, 0); // Рисуем сурфейс d3d_transform_set_identity(); // Отключаем все преобразования, установленные пользователем II.3.10. Как полностью перекрасить спрайт в другой цвет? Ответ: Для того, чтобы перекрасить спрайт в чёрный цвет - можете использовать image_blend, тот же параметр color в функциях для отображения спрайтов. Кстати, это довольно полезная функция, к примеру - с её помощью можно легко создать тень, пример: draw_sprite_ext(sprite_index, 0, x + 2, y + 2, 1, 1, 0, c_black, 0.3); // Рисуем тень с непрозрачностью 0.3 draw_sprite(sprite_index, 0, x, y); // Рисуем сам спрайт Чтобы полность перекрасить спрайт в цвет, отличный от чёрного - используйте функцию для создания тумана в 3D играх. Пример: d3d_set_fog(true, c_white, 0, 0); draw_sprite(sprite_index, 0, x, y); d3d_set_fog(false, c_white, 0, 0); Ну, а если вы хотите создать полноценный эффект "Fade" - используйте dll для работы с пиксельными шейдерами в GM, где это реализуется очень легко: http://gmc.yoyogames.com/index.php?showtopic=492876 II.3.11. Как убрать курсор с помощью кода? Как изменить курсор? Как сделать свою картинку курсора? Ответ: Изменить стандартное изображение можно с помощью функции window_set_cursor(curs), в которой можно использовать следующие константы: cr_default cr_none cr_arrow cr_cross cr_beam cr_size_nesw cr_size_ns cr_size_nwse cr_size_we cr_uparrow cr_hourglass cr_drag cr_nodrop cr_hsplit cr_vsplit cr_multidrag cr_sqlwait cr_no cr_appstart cr_help cr_handpoint cr_size_all Чтобы убрать курсор - следует выбрать константу cr_none. Чтобы показывалась картинка игрового курсора, можно использовать переменную cursor_sprite. Обратите внимание, если скорость комнаты меньше 60 - ваш собственный курсор будет немного "тормозить", потому что частота обновления экрана значительно больше 30.
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Январь 10, 2011, 03:09:16
4) ДругоеII.4.1. Как добавить в игру ману? Как отрисовать кол-во маны на экране? Ответ: Для жизней можно использовать стандартную переменную health. А вот для маны потребуется завести свою. В событии create event поставьте серый квадратик с именем "VAR" (control -> Variables -> Set Variable). В первом поле (variable) запишите название своей переменной на английском языке, без пробелов и начиная с буквы, например, mana. Если вы хотите изменить значение переменной (в данном случае - маны, к примеру, после использования эликсира) - поставьте тот же квадратик, и введите в него имя переменной и требуемое значение. Вариант кодом: "mana = 0;". Чтобы отобразить значение переменной на экране (в данном случае - количество маны), в событие draw event поставьте светло-жёлтый квадратик с именем "VAR" (control -> Variables -> Draw Variable), в нём введите имя вашей переменной и желаемые координаты. Возможный вариант кодом: draw_text(/*ваши координаты*/, /*ваши координаты*/, "мана: " + string(mana)); II.4.2. Как мне изменить вид стандартных серых окон GM? Ответ: Используйте функции message_*: message_background(back) message_alpha(alpha) message_button(spr) message_text_font(name,size,color,style) message_button_font(name,size,color,style) message_input_font(name,size,color,style) message_mouse_color(col) message_input_color(col) message_caption(show,str) message_position(x,y) message_size(w,h)
P.S: за описанием - в справку. II.4.3. Хелсбар не показывает больше 100 жизней, хотя health у меня равно 200! Как мне установить максимальное значение health? Ответ: В функции draw_healthbar в аргументе amount нужно использовать такую формулу: (health / health_max) * 100 Где health - переменная жизней, health_max - максимальное кол-во жизней. II.4.4. Как определить наивысший объект под мышкой? Ответ: Скрипт опеределения наивысшего объекта в конкретной позиции выглядит так: /*************************************************** Скрипт определяет наивысший экземпляр объекта в указанной позиции. Возвращает id экземпляра объекта, если он существует, в противном случае - noone. argument0 - x; argument1 - y; argument2 - объект; ***************************************************/ var high_object; high_object = noone; with argument2 // Обращаемся ко всем экземплярам объекта { if position_meeting(argument0, argument1, id) // Если объект находится в нужной позиции, то... { if other.high_object = noone // Если мы ещё не выбрали ни один объект, то... { other.high_object = id; // Запоминаем текущий объект. } else { if depth < other.high_object.depth // Если текущий объект выше чем выбранный, то... { other.high_object = id; // Запоминаем объект. } } } }
return high_object; // Возвращаем id найденного объекта. В этом скрипте идёт обращение ко всем экземплярам искомого объекта. Вначале каждый из них проверяется на столкновение с указанной позицией, то есть, проверяется, находится ли он в ней. Если да, тогда его глубина сравнивается с глубиной записанного объекта (тут и далее подразумевается экземпляр объекта). Если его глубина меньше - этот объект заменяет ранее записанный. Конечно, если ни один объект ещё не был записан - глубина не проверяется, а объект сразу записывается. Скачать пример. (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2032)
II.4.5. Почему при повороте спрайта с использованием image_angle его изображение искажается и выглядит некрасиво? Ответ: Включите в настройках игры интерполяцию (global game setting -> graphics -> interpolate color between pixel).
II.4.6. Как мне нарисовать русский текст? Почему я его не вижу? Ответ: В Game Maker 8 по умолчанию встроен шрифт Arial 12, с ограниченным набором символов: начиная от 32 до 127. Русский алфавит в этот диапазон не входит, поэтому, чтобы рисовать русский текст, вам понадобится добавить свой шрифт, в котором нужно выставить максимальный диапазон символов, для поддержки кириллицы. Итак, выберите пункт "Create Font" из меню "Resources", или просто нажмите соответствующую кнопку на панели инструментов. Затем дайте имя своему шрифту в игре (я лично предпочитаю что-то вроде font_menu_button или font_arial10b), выберите сам шрифт, установите нужный размер и нажмите на кнопку "All" (Все), которая устанавливает максимальный диапазон символов. Наконец, вам нужно установить для использования этот шрифт в игре, для этого перед рисованием текста вызовите функцию draw_set_font: draw_set_font(имя_вашего_шрифта_в_игре); draw_text(...); Для GameMaker: Studio нужно добавить диапазон 1040-1103 (это без буквы "ё"). Ещё вариант - нажать "From Code" или "From File", тогда диапазон символов будет взят непосредственно из кода проекта, либо из указанного текстового файла (он должен быть в кодировке UTF-8). Если вы всё равно не увидили русские буквы - значит выбранный вами шрифт не поддерживает кириллицу. II.4.7. Скорость смены кадров у меня 0.3. Я хочу, чтобы на втором кадре появлялся взрыв. Для этого я пишу: "if image_index = 2 then instance_create(x, y, o_explosion);" Но взрыв не появляется! В чём причина? Ответ: Перед тем, как я покажу вам путь решения - я хочу уведомить вас о ошибке, сделанной в официальном справочном руководстве (а точнее - в GM). Во главе "Спрайты и изображения", подраздела "Игровая графика" раздела "Gama Maker Language (GML)" мы можем увидеть такую строчку: image_index Содержит номер кадра спрайта текущего экземпляра объекта, с которого следует начать проигрывание анимации. Эта переменная указывает к настоящему времени нарисованный кадр (нумерация начинается с 0). Вы можете изменить текущее изображение изменением этой переменной. Программа продолжит повторение, начиная с новым индексом. (Значение может иметь дробную часть. В этом случае, оно всегда будет округлено в меньшую сторону, чтобы получить кадр, который рисуется.) Однако, тут допущена важная ошибка, так как округление воспроизводится и не в меньшую сторону и не в большую, т.е. если, скажем, image_index равно 1.4, то после округления мы получим 1, а если оно равно 1.5 - получим 2. Это важно учитывать, так как мы увидим второй кадр на экране, когда округлённое значение image_index фактически будет равно 1 (нумерация начинается с 0, так что второй кадр - 1). А потому, следует написать так: if round(image_index) = 1 then instance_create(x, y, o_explosion); P.S: если вас смущают русские цитаты - загляните в английскую справку, это не ошибка переводчиков. II.4.8:Вопрос 1: Как запросить у игрока код, к примеру, для открытия двери? Вопрос 2: Как сделать чит-коды? Ответ: Обе задачи решаются очень просто, с помощью функции get_string. Запросить код можно следующим образом: var text; text = get_string('Введите код для открытия двери:', '****'); // Запрашиваем у игрока код. if text = '1234' // Сравниваем его с правильным кодом. { // Действия, которые выполняются, если игрок ввёл правильный код. } else { show_message('Код неверен.'); // Выводим сообщение об ошибке. } Чит-коды можно организовать следующим образом: var text; text = get_string('Введите чит-код:', ''); // Запрашиваем у игрока чит-код. switch (text) // Сравнивем введённый игроком текст со всеми чит-кодами. Не забудьте break в конце каждой проверки! { case 'lives': lives = 100; break; case 'gold': score += 1000000; break; default: show_message('Такого чит-кода не существует!'); } II.4.9. Как изменить размер текущей комнаты? Ответ: Размер текущей комнаты напрямую изменить нельзя. Как вариант, можно перейти в другую комнату, изменить размер нужной комнаты, а затем вернуться в изначальную. Чтобы не перезапускать комнату - можно использовать свои переменные для хранения и изменения её размера. К примеру, в каком-нибудь контроллере объявляем глобальные переменные level_width и level_height. room_width и room_height везде заменяем на level_width и level_height соответственно. После этого нужно написать свой алгоритм движения вида - в событии begin step сначала двигаем объект, за которым следит вид (к примеру, героя), а затем сдвигаем вид по такому алгоритму: var xx, yy; xx = x; // Устанавливаем позицию, к которой должен двигаться вид yy = y;
if xx < view_xview[0] + view_hborder[0] view_xview[0] -= min(view_hspeed[0], view_xview[0] + view_hborder[0] - xx); if yy < view_yview[0] + view_vborder[0] view_yview[0] -= min(view_vspeed[0], view_yview[0] + view_vborder[0] - yy);
if xx > view_xview[0] + view_wview[0] - view_hborder[0] view_xview[0] += min(view_hspeed[0], xx - (view_xview[0] + view_wview[0] - view_hborder[0])); if yy > view_yview[0] + view_hview[0] - view_vborder[0] view_yview[0] += min(view_vspeed[0], yy - (view_yview[0] + view_hview[0] - view_vborder[0]));
view_xview[0] = median(0, view_xview[0], level_width - view_wview[0]); // Ограничиваем позицию вида view_yview[0] = median(0, view_yview[0], level_height - view_hview[0]); Где xx и yy - координаты точки, за которой следит вид. Все настройки вида в комнате можно оставить без изменений, только нужно обязательно убрать объект, за которым следует вид - установаить <no object> (опция находится в закладке view, object following). Теперь, можно свободно изменять переменные level_width и level_height, не перезапуская комнату. II.4.10. Как определить время компьютера? Как отобразить текущее время на экране? Ответ: Все функции можно посмотреть в справке: GML -> Игровой процесс -> Синхронизация (http://gmakers.ru/gamemaker_help/source/files/403_07_timing.php): current_time* Количество миллисекунд, которые прошли с тех пор, как система была запущена. current_year* Текущий год. current_month* Текущий месяц. current_day* Текущий день. current_weekday* Текущий день недели (1=воскресенье, ..., 7=суббота). current_hour* Текущий час. current_minute* Текущая минута. current_second* Текущая секунда. Отобразить дату и время компьютера можно следующим образом: draw_text(x, y, string(current_hour) + ':' + string(current_minute) + ':' + string(current_second) + ' / ' + string(current_day) + '.' + string(current_month) + '.' + string(current_year)); II.4.11. Как защитить счёт в игре от артмани? Ответ:Метод 1:Можно хранить в памяти не то значение которое выводится на экран - тогда пользователь не сможет узнать, по какому именно значению проводить поиск. Пример реализации: create event: score = 0; keyboard press space event: score += irandom(5) * 0.456; draw event: draw_text(x, y, score / 0.456); Таким образом, на экране отображается одно значение, а в памяти хранится всего 456/1000 от него. Конечно, желательно использовать более сложные формулы, чем просто деление и умножение. Метод 2:Можно создать ещё одну переменную для проверки счёта. Пример реализации: create event: score = 0; score_prev = score + 240.764; step event: if score != score_prev - 240.764 { show_message('Не пытайтесь взломать нашу игру. Это бесполезно.') game_end(); } keyboard press space event: score += irandom(5) * 0.456; score_prev = score + 240.764; draw event: draw_text(x, y, score); Таким образом, как только пользователь изменит кол-во счёта с помощью сторонних программ - игра сразу же это обнаружит. II.4.12. Как сделать паузу игры при открытии меню? Ответ: Есть несколько способов это сделать. Если меню текстовое, с управлением на клавиатуре - можно использовать рекурсию. Если же меню создано объектами - есть два основных способа: 1) В первую очередь, нужно установить текущей комнате persistent. Перед выходом в меню нужно сохранить скриншот игры в глобальную переменную, после этого - перейти в комнату меню. В комнате меню устанавливаем как фон скриншот игры. При клике на "Продолжить" - просто возвращаемся в комнату с игрой и удаляем скриншот игры. Всё просто. Базовый код этого метода: // Выход в меню: global.game_screen = background_create_from_screen(0, 0, view_wview, view_hview, 0, 0); // Создаём скриншот экрана room_goto(rm_menu); // Переходим в меню
// Room creation code комнаты rm_menu (settings -> Creation code): background_index[0] = global.game_screen; background_visible[0] = 1;
// Возвращение в игру: background_delete(global.game_screen); room_goto(rm_game); 2) Перед выходом в меню нужно сделать скриншот игры, после чего деактивировать все объекты (кроме тех, что нужны для работоспособности меню). Когда объекты деактивируются - они перестают отрисовывать свой спрайт, потому то нам и нужно запечатлить текущее состояние игры. После деактивации нужно создать кнопки и в draw event какого-нибудь контроллера отрисовывать скриншот игры как фон для меню (плавное затемнение и всякие эффекты для фона - это уже детали). При возвращении в игру активировать все объекты, удалить кнопки, убрать рисование скриншота игры и удалить сам скриншот. Вот базовый код этого метода: // Выход в меню: global.game_screen = sprite_create_from_screen(0, 0, view_wview, view_hview, 0, 0, 0, 0); // Создаём скриншот экрана instance_deactivate_all(true); // Деактивируем все объекты, кроме текущего instance_activate_object(o_menu_controll); // Активируем контроллеры, нужные для работы меню o_menu_controll.draw_game_screen = 1; // Указываем, чтобы объект o_controll рисовал скриншот игры на фоне instance_create(view_xview, view_yview, o_button); // Создаём кнопки
// Возвращение в игру: sprite_delete(global.game_screen); // Удаляем скриншот игры instance_activate_all(); // Активируем все объекты o_menu_controll.draw_game_screen = 0; // Указываем, чтобы объект o_controll более не рисовал скриншот игры на фоне with o_button instance_destroy(); // Удаляем все кнопки
// Draw event объекта o_menu_controll: if draw_game_screen { draw_sprite(global.game_screen, 0, view_xview, view_yview); } II.4.13. Как сделать респавн монстров через определённое время за границами комнаты в зависимости от счета игрока? Ответ: Чтобы сделать респавн монстров через определённое время можно использовать алармы. Для начала нужно в create event объекта, который будет создавать монстров написать такой код: alarm[0] = room_speed; // Монстры появятся через 1 секунду В событии alarm 0 пишем такой код: var xx, yy; repeat score*0.5 + 10 { switch irandom(3) { case 0: xx = -32; yy = random(room_height); break; case 1: xx = room_width + 32; yy = random(room_height); break; case 2: xx = random(room_width); yy = -32; break; case 3: xx = random(room_width); yy = room_height + 32; break; } instance_create(xx, yy, o_enemy); } alarm[0] = 5 * room_speed; // Следующая волна монстров будет через пять секунд II.4.14. Как сделать разброс пуль? Ответ: Всё очень просто, следует только использовать random_range для некоторой случайной неточности. Например, код создание пули в игроке можно составить таким образом: var bull; bull = instance_create(x, y, o_bullet); // Создаём пулю bull.direction = direction + random_range(-20, 20); // Максимальное отклонение - 20 градусов II.4.15. Вопрос 1: Как проверить, чётное ли число? Вопрос 2: Как проверить, кратно ли одно число другому? Ответ: Если проверка value mod 2 возвращает 0 - число чётное, в другом случае - число нечётное. Пример: if value mod 2 == 0 { show_message('Число чётное.'); } else { show_message('Число нечётное.'); } Для проверки кратности используется та же проверка, только вместо 2 - делитель. II.4.16. Как сделать бесконечную комнату? Движущуюся вниз/вверх. Ответ: Обычно эффект бесконечности достигается посредством движением фона и объектов - движется фон, а игроку кажется, что движутся объекты. Предположим, что фон двигается со скоростью -5 - каждый шаг двигается на 5 пикселей вверх. Тогда недвижимый объект на экране падает со скорость 5 пикселей, так как относительно фона каждый шаг он сдвигается на 5 пикселей вниз. Объект, который движется вверх со скоростью 5 пикселей - завис в воздухе, так как относительно фона он не сдвигается. Таким образом, создавая за нижней границей комнаты объекты и устанавливая им отрицательную вертикальную скорость - получим бесконечный поток объектов. Не стоит забывать, что все объекты нужно удалять, если они пересекли верхнюю границу комнаты.
II.4.17. Как сделать, чтобы при переходе в другую комнату в текущей сохранялись все изменения? Ответ: Нужно установить persistent в настройках комнаты, вкладка settings. Так же для этого можно использовать функцию room_set_persistent и переменную room_persistent.
II.4.18. Как загрузить спрайт/звук/фон из папки, как загрузить анимацию, как проверить существование файла? Ответ: Для загрузки спрайтов используются следующие функции: sprite_add (загружает новый спрайт в игру), sprite_replace (заменяет существующий спрайт), sprite_add_sprite (добавляет спрайт в формате gmspr) и sprite_replace_sprite (заменяет существующий спрайт спрайтом в формате gmspr). Аналогичные функции для загрузки фонов: background_add, background_replace, background_add_background, background_replace_background. И функции для загрузки звуков: sound_add (добавляет музыку/звук), sound_replace (заменяет музыку/звук). Чтобы сохранить анимацию в png формате - спрайт нужно сохранить как стрип: Edit Sprite -> File -> Save as PNG File (Game Maker автоматически объединит все кадры). Чтобы загрузить полученную картинку в игру - в аргументе imgnumb, функции для загрузки спрайта нужно указать кол-во кадров анимации. В редакторе изображений GM загружать стрип следует выбрав пункт "Create from Strip" в меню "File". Советую проверять на существование каждый внешний файл. Для этого используется функция file_exists. Так же обязательно убедитесь, что вы не загружаете один и тот же ресурс более одного раза, и так же примите во внимание, что загруженные ресурсы не сохраняются при вызове функции game_save. II.4.19. Как узнать путь к папке windows, appdata и т.д.? Ответ: Для этого следует использовать Переменные среды (http://ru.wikipedia.org/wiki/Переменные_среды) / Environment variables (http://en.wikipedia.org/wiki/Environment_variable). Пример: AppDataDir = environment_get_variable('AppData'); II.4.20. Вопрос 1: Как сделать, чтобы при столкновении отнимались не сразу все три жизни, а только одна? Вопрос 2: Как сделать, чтобы событие столкновения происходило через определённые промежутки времени? Ответ: Чтобы жизни отнимались не сразу все три, а только через определённые промежутки времени - достаточно установить таймер, который идёт во время столкновения и сбрасывается на 0, если столкновения нет. К примеру, можно написать такой код в step event противника:: var obj; obj = instance_place(x, y, o_player); if obj != noone // Если противник столкнулся с игроком { if alarm[0] == -1 // Если таймер не запущен { with obj hp -= 1; // Уменьшаем кол-во жизней игрока alarm[0] = 15; // Через 1/2 секунды противник сможет атаковать ещё раз. } } else { alarm[0] = -1; // Если столкновения нет - сбрасываем таймер } alarm 0 противника: // Противник может атаковать Ещё один вариант - после атаки делать игрока на время бессмертным. Тогда код примет примерно такой вид: step event противника: var obj; obj = instance_place(x, y, o_player); if obj != noone { if obj.alarm[0] == -1 { with obj { hp -= 1; alarm[0] = 15; // Через 1/2 секунды игрок перестанет быть бессмертным. } } } alarm 0 event игрока: // Игрока можно атаковать II.4.21. Как определить, в какой ячейке произвольной сетки расположена конкретная позиция? Ответ: Предположим, что сетка начинается с координат start_x, start_y. Ширина и высота сетки в ячейках - grid_width и grid_height соответственно. Ширина и высота ячейки в пикселях - cell_width, cell_height. Данная позиция - xx, yy. Итак, получаем такой код: if xx >= start_x and yy >= start_y and xx <= start_x + grid_width*cell_width and yy <= start_y + grid_height*cell_height { cell_x = (xx - start_x) div cell_width; cell_y = (yy - start_y) div cell_height; } else { cell_x = -1; cell_y = -1; } К примеру, если сетка начинается в координатах 0,0 и она никак не ограничена, в том числе номера её ячеек могут принимать отрицательные значения, то поиск ячейки, на которой расположена позиция xx,yy будет выглядеть так: cell_x = xx div cell_width; cell_y = yy div cell_height; II.4.22. Как сделать у противников разные жизни? Я пишу для одного противника health = 0, а умирают все. Ответ: health - глобальная переменная, обычно используемая для кол-ва жизней игрока. Чтобы у каждого противника были свои жизни - следует использовать локальные переменные. У каждого противника в create event нужно объявить локальную переменную hp: hp = 100; // Изначальное кол-во жизней - 100 При столкновении противника с пулей, к примеру, можно написать примерно такой код: hp -= 15; // Уменьшаем hp противника with other instance_destroy(); // Удаляем пулю if hp <= 0 // Если жизни противника меньше или равны нулю, то... { instance_destroy(); // Удаляем противника // Создаём кровь и т.д. } Иногда hp противника уменьшается не только в событиях столкновения, но и как результат различных бонусов и т.д. Чтобы не писать код уничтожения противника во всех местах, где hp противника уменьшается - можно поставить такой код в step противника: if hp <= 0 // Если жизни противника меньше или равны нулю, то... { instance_destroy(); // Удаляем противника // Создаём кровь и т.д. } II.4.23. Как сначала проиграть анимацию до конца, а затем запустить наоборот? Ответ: В step event объекта можно поставить приблизительно такой код: if round(image_index + image_speed) >= image_number // Если анимация дошла до конца, то... image_speed = - 1/room_speed; // Устанавливаем отрицательную скорость анимации if image_index < 0 // Если анимация в обратную сторону закончилась, то... instance_destroy(); // Удаляем объект II.4.24. Как вычислить разницу между направлениями? Ответ: Пожалуй, стоит разобраться с этим на примере, шаг за шагом разрабатывая искомый скрипт. 1. Предположим, у нас есть три направления: (http://savepic.org/1181608.jpg) ссылка на изображение, размер: 34.0 кбайт, 192 x 192 точек (http://savepic.org/1181608.htm) Очевидно, что для вычисления разницы между синим и красным направлениями нужно от синего отнять красное: (135° - 45°) = 90°. Как может показаться вначале, разница между красным и синим направлениями равна разнице между синим и красным. Однако, в нашем случае, разница может принимать отрицательно значение. Поэтому, разница между красным и синим направлениями равна -90°, а не 90°. На самом деле, вы получаете значение, которое нужно добавить ко второму направлению, чтобы получить первое. Добавляя 90 градусов к 45° получается 135°, ровно как и вычитая 90 градусов из 135° получается 45°. 2. Однако с зелёным и красным направлениями такая простая операция не даст желаемого результата. Скрипт должен возвращать "ближайшую разницу", не 270 градусов (которые можно получить, вычитая 45 градусов из 315°), а 90°: (http://savepic.org/1239979.jpg) ссылка на изображение, размер: 31.3 кбайт, 192 x 192 точек (http://savepic.org/1239979.htm) Требуется вычислить угол a° - он обозначен оранжевым цветом на картинке. Очевидно, что его можно получить, вычитая из 360 345° (зелёное направление), и прибавив к нему 45° (красное направление): dir = dir1 + (360 - dir2); // 45 + (360 - 315) = 90 Где dir - угол a°, dir1 - меньший угол (45° на картинке) и dir2 - больший угол (315 градусов на картинке). Итак, если разность направлений меньше 180 - можно просто отнять от одного направления другое, как в случае с синим и красным направлениями. Если же разность больше или равна 180 - нужно вычислять направление посредством вышеприведённой формулы, или вот так: dir = 360 - (dir2 - dir1); Этот код аналогичен предыдущему, в нём лишь переставлены значения, хотя логика сохранена. 3. Итого, скрипт вычисления разницы между двумя направлениями можно записать так: var diff; diff = argument1 - argument0; // Вычисляем разность между направлениями if abs(diff) > 180 // Если разность по модулю больше 180 return 360 - diff; // Возвращаем разность "через ноль" else return diff; // Возвращаем обычную разность Мы уже вплотную приблизились к решению задачи. Однако, этот скрипт полностью рабочий только когда argument1 больше argument0. К примеру, если argument1 = 15°, а argument0 = 215°, получим соответственно 360° - (15° - 215°) = 560 градусов. Потому, нужно изменить скрипт так, чтобы этой ошибки не возникало: // argument0 - первое направление // argument1 - второе направление var diff; diff = argument1 - argument0; if abs(diff) > 180 return (360 - abs(diff)) * -sign(diff); // Сначала находим разность между направлениями "через ноль", а потом устанавливаем нужный знак else return diff; Этот скрипт полностью рабочий и готов к использованию. Он возвращает значение, на которое больше / меньше направление argument1 чем направление argument0. Если argument1 = 135, а argument0 = 45, то получим 90. Если же argument1 = 315, а argument0 = 45, получим -90, так как 315 на 90 градусов меньше чем 45, считая "через ноль" (извините за каламбур, но это так): (http://savepic.org/1216428.jpg) ссылка на изображение, размер: 38.1 кбайт, 192 x 192 точек (http://savepic.org/1216428.htm) 4. Есть однако ещё одна проблема. Иногда направления бывают отрицательные, и часто превышают 360. Поэтому, желательно обработать входящие данные должным образом, чтобы не возникало непредвиденных ошибок: dir = dir mod 360; Эта строка вычисляет остаток от деления указанного направления на 360. То есть, если направление 370, то остаток от деления на 360 будет 10, если направление -740, то получим -20 и т.п. Таким образом, направление будет всегда меньше 360. После этого отрицательное направление нужно преобразовать в положительное. Сделать это, очевидно, можно так: if dir < 0 dir += 360; 5. К слову, все три вышенаписаные строки можно записать всего одной: dir = (dir mod 360 + 360) mod 360; Поясню этот код. Вначале направление приводится к виду от -360 до 360 (не включительно), с помощью оператора mod: "dir mod 360". Далее, если направление отрицательное - она преобразовывается в положительное, после прибавления к нему 360 градусов. К примеру: "-20 + 360" это тоже самое что "360 - 20", то есть, 340 - получаем нормальное положительное направление. Далее вычисляется остаток деления направление на 360, если направление было отрицательным - ничего не изменится, так как 340 mod 360 = 340, а если положительным - оно вернётся к изначальному: (20 + 360) mod 360 = 380 mod 360 = 20. Если вас эта сокращённая запись чем-то смущает, либо вы не можете с нею разобраться, либо же вам просто лень морочить себе голову, то используйте обычный код: dir = dir mod 360; if dir < 0 dir += 360; 6. В результате всех манипуляций с направлениями, скрипт вычисления разницы между двумя направлениями приобрёл следующий вид: /*************************************************** Скрипт возвращает разницу между двумя направлениями. argument0 - первое направление; argument1 - второе направление направление; ***************************************************/ var diff; diff = (argument1 - argument0) mod 360; if diff < 0 diff += 360; if abs(diff) > 180 return (360 - abs(diff)) * -sign(diff); else return diff; 7. На этом можно было бы закончить, однако есть способ записать весь этот скрипт в одну строку, только для самых "крутых" программистов. Я хочу вам рассказать про этот способ. Идея, на самом деле, довольно простая, только очень запутанная. Для начала нужно вычислить разницу двух направлений, просто вычитая одно из другого. Далее, нужно добавит 180 к полученному направлению. Если разность была меньше 180 - она так и останется меньше 360, а если больше - мы получим направление большее 360. После этого находим остаток от деления на 360, и снова отнимаем 180. Когда это написано сухими словами - понять это довольно сложно, так что снова попробуем разобраться на примере: (http://savepic.org/1212333.jpg) ссылка на изображение, размер: 35.6 кбайт, 192 x 192 точек (http://savepic.org/1212333.htm) Итак, мы "поворачиваем" наше направление (225 на рисунке) на 180 градусов, после чего вычисляем, на сколько полученное направление больше нуля (mod 360), в результате чего, получаем 45 градусов (серая стрелка на рисунке, a°). После этого вычитаем из полученного направления 180 градусов, вроде бы как "возвращая" направление назад, получая тоже, что и -(360 - dir) или dir - 360. На рисунке: (http://savepic.org/1203117.jpg) ссылка на изображение, размер: 28.2 кбайт, 192 x 192 точек (http://savepic.org/1203117.htm) Если dir (разность направлений) меньше 180 - в результате всех операций получаем тоже направление, так как (dir + 180) mod 360 - 180 = dir (при условии, что dir меньше 180). Итого, получаем вот такую страшную строку: return (((argument1 - argument0) mod 360 + 360) mod 360 + 180) mod 360 - 180; "((argument1 - argument0) mod 360 + 360) mod 360" - приводим разность направлений к виду 0 - 360, чтобы избежать ошибок. "(... + 180) mod 360 - 180" - если направление меньше 180, то ничего не меняется, если больше - получаем отрицательную разность (то, что я описывал выше). Можно заметить, что в этой строке есть пара повторяющихся действий, которые можно было бы объединить в одно: "((... + 360) mod 360 + 180) mod 360" тоже что и "(... + 540) mod 360" Итого, получаем такой скрипт: return ((((argument1 - argument0) mod 360) + 540) mod 360) - 180; и выглядит он именно так, как на сайте www.gmlscripts.com: /* ** usage: ** diff = angle_difference(angle1,angle2); ** ** given: ** angle1 first direction in degrees, real ** angle2 second direction in degrees, real ** ** returns: ** difference of the given angles in degrees, -180 to 180 ** ** GMLscripts.com */ { return ((((argument0 - argument1) mod 360) + 540) mod 360) - 180; } Вы можете использовать уже готовый скрипт в одну строку - а можете использовать более простой скрипт для понимания, составленный нами выше. 5) ОптимизацияII.5.1. Что быстрее выполняется, sqrt(sqr(x2-x1)+sqr(y2-y1)) или point_distance(x1, y1, x2, y2)? Ответ: Встроенные функции GM выполняются быстрее самописных. point_distance будет работать быстрее.
II.5.2. Что быстрее выполняется, функции lengthdir_x(len, dir) и lengthdir_y(len, dir), или cos(degtorad(dir))*len и -sin(degtorad(dir))*len? Ответ: Как и в случае с point_distance, lengthdir_x и lengthdir_y будет работать быстрее.
II.5.3. Что выполняется быстрее, стандартные проверки GM в объекте (на подобии add event -> Keyboard -> <Left>), или собственные проверки в step event (вроде keyboard_check)? Ответ: Стандартные события GM выполняются немного быстрее проверок в шаге. Вероятно, из-за того, что интерпретация кода, каким-бы простым он ни был - занимает довольно много времени. То есть, использование стандартных GM событий покажет большую производительность, чем многочисленные собственные проверки в step event. Однако, разница в скорости выполнения не столь велика, чтобы злоупотреблять этим. P.S: я лично, например, чаще всего вручную пишу большинство проверок в step event объекта. II.5.4. Если одно из выражений в условии ложно, будет ли проверяться остальная часть условия? Ответ (для GM8): В отличии от большинства языков программирования, в GML проверяется всё условие, вне зависимости, является ли одно из выражений ложным. То есть, условие написанное так: if is_picture_grayscale(temp) { if is_picture_fractal(temp) { // ... } } Будет выполнятся быстрее условия, записанного так: if is_picture_grayscale(temp) and is_pisture_fractal(temp) { // ... } (названия скриптов взяты наобум) В GameMaker: Studio реализована политика неполных проверок условий (short circuit evaluation), а потому будет выполняться минимально возможное количество условий (можно отключить такое поведение, сняв соответствующую галочку в настройках проекта). II.5.5. Почему не стоит выносить действия в событиях step/draw в скрипты? Ответ: Механизм вызова скриптов в GM невероятно медленный. Допустим, у нас есть два куска кода: a = b; И script0(); script0 такого содержания: a = b; Первый код, повторенный 100 раз выполнялся 0.044 миллисекунды, второй (скрипт) - 0.341 миллисекунды (то есть, примерно в семь раз дольше!). Первый код, повторенный 1000000 раз выполнялся 5401 миллисекунду, второй (скрипт) - 9864 миллисекунды. Очевидно, что вызов скрипта занимает довольно много времени. На деле, при большом количестве использования скриптов в постоянно повторяющихся событиях (как step и draw) - fps значительно падает. Обратите внимание, что в GMS значительно улучшена производительность и данный совет для неё не актуален. 6) ИИII.6.1. Как сделать, чтобы противники двигались к игроку? (вид сверху) Ответ: Заставить противников двигаться к игроку есть множество способов. Если противники должны просто следовать за игроком по прямой, можно использовать следующий код: if instance_exists(объект_игрока) { if point_distance(x, y, объект_игрока.x, объект_игрока.y) > скорость_движения { move_towards_point(объект_игрока.x, объект_игрока.y, скорость_движения); // Двигаемся к игроку } else { x = объект_игрока.x; y = объект_игрока.y; } } Условие "if instance_exists(объект_игрока)" нужно для того, чтобы не появлялась ошибка, когда объекта игрока почему-то нет (например, когда он был удалён после смерти). Проверка point_distance требуется для того, чтобы противник не мог пройти позицию цели. К примеру, если скорость противника - 10 пикселей, а цель находится от него на расстоянии в два пикселя, то он попросту проскочит её, сдвинувшись на 10 пикселей в направлении цели. С проверкой он сдвинется точно к позиции цели, не перескакивая её. Если противники должны двигаться к игроку, огибая стены, можно использовать следующий код: if instance_exists(объект_игрока) { if point_distance(x, y, объект_игрока.x, объект_игрока.y) > скорость_движения { mp_potential_step(объект_игрока.x, объект_игрока.y, скорость_движения, checkall); } else { x = объект_игрока.x; y = объект_игрока.y; } } О значении последнего аргумента (checkall) читайте в справке. II.6.2. Зарезервировано. Ответ:
II.6.3. Зарезервировано. Ответ:
II.6.4. Зарезервировано. Ответ:
II.6.5. Зарезервировано. Ответ:
II.6.6. Зарезервировано. Ответ:
II.6.7. Как сделать, чтобы противники "видели" игрока только на определённом расстоянии? Ответ: Для этого нужно проверить расстояние между игроком и противником, делается это с помощью функции point_distance: if instance_exists(объект_игрока) { if point_distance(x, y, объект_игрока.x, объект_игрока.y) < радиус_зрения_противника { // Действия противника, когда игрок попал в поле зрения. } } О необходимости проверки instance_exists читайте в предыдущем вопросе. II.6.8. Как сделать, чтобы противники видели игрока только под определённым углом? Ответ: Используйте скрипт для вычисления разницы между двумя направлениями, создание которого подробно описывается в вопросе II.4.24. Если разница между направлением взгляда противника и направлением от него к игроку превышает половину от угла обзора противника, значит противник не видит игрока. К примеру, если противник имеет угол обзора в 120 градусов, то разница между направлением его взгляда и направлением от него к игроку должна по модулю не превышать 60 градусов (это значит, что противник видит игрока). В коде это выглядит примерно так: var dir; dir = point_direction(x, y, объект_игрока.x, объект_игрока.y); if abs(dir_difference(image_angle, dir)) <= угол_обзора / 2 { // Действия противника, если игрок находится в его поле зрения. } II.6.9. Как сделать, чтобы противники не видели игрока через стены? Ответ: Для этого нужно проверить, есть ли между противником и игроком стена. Используйте функцию collision_line: if instance_exists(объект_игрока) // Если объект игрока существует { if !collision_line(x, y, объект_игрока.x, объект_игрока.y, объект_стены, 0, 0) { // Действия противника, когда между ним и игроком нет стены. } } Восклицательный знак перед функцией - это знак отрицания, то есть, он сменяет true на false и false на true. Иначе говоря, без него проверка на русском языке звучала бы как "Если между игроком и противником есть стена", а с ним: "Если между игроком и противником нет стены". II.6.10. Как сделать, чтобы противник двигался за ближайшим союзным персонажем игрока, или к самому игроку (если он ближе всех)? Ответ: Так как объектов союзных персонажей может быть много, нам нужно обращаться к какому-то одному объекту, а не к каждому по отдельности. Для этого нужно использовать так называемых объектов-родителей (parent). Для начала нужно создать новый объект, родитель для всех союзных персонажей игрока и для него самого, после чего назначить его родителем всем нужным объектам. При обращении к родителю мы будем обращаться ко всем его дочерним объектам - ко всем союзным персонажам и игроку одновременно. Для определения ближайшего объекта можно использовать функцию instance_nearest. Если ни одного экземпляра искомого объекта в комнате нет - функция возвратит noone, поэтому функцию instance_exists можно не использовать. Код будет выглядеть примерно так: var obj; obj = instance_nearest(x, y, родительский_объект); // Определяем ближайшего персонажа if obj != noone // Если существует хотя бы один экземпляр объекта родительский_объект (или дочернего объекта), то... { /// Двигаемся к нему: if point_distance(x, y, obj.x, obj.y) > скорость_движения { mp_potential_step(obj.x, obj.y, скорость_движения, checkall); } else { x = obj.x; y = obj.y; } } II.6.11. Как сделать, чтобы башня стреляла в ближайшего противника (речь о жанре "Башенная защита")? Ответ: Код будет практически аналогичен тому, который представлен в предыдущем вопросе: var obj; obj = instance_nearest(x, y, объект_противника); // Определяем ближайшего противника. if obj != noone // Если существует хотя бы один противник, то... { var bull; bull = instance_create(x, y, объект_пули); // Создаём пулю. with bull { move_towards_point(obj.x, obj.y, скорость_пули); // Направляем её к противнику. } } III - ПримерыПлатформеры:- motion in platformer.gmk (10.6) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3033) - базовый пример двжения в платформере.
- rough surface.gmk (13.5 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3036) - пример движения по неровной поверхности.
- stairs.gmk (12.2 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3035) - пример лестниц. Автор: Лер.
Другое:- momemtary bullets.gmk (11.6 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3034) - пример мгновенных пуль, собственных жизней у противников и хелсбаров.
- healthbar and gradual turn.gmk (14.4 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3032) - пример спрайтового хелбара и плавного поворота.
- depth example.gmk (25.2 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2032) - пример определения наивысшего объекта в области мышки.
- tds move.gmk (9.83 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2565) - пример движение по диагонали с той же скоростью, что и обычно.
IV - ШАБЛОН[b]xx.xx.xx.[/b] <Вопрос> [spoiler][b]Ответ:[/b] <Ответ>[hr][/spoiler] [b]xx.xx.xx.[/b] [b]Вопрос 1:[/b] <1 вопрос> [b]Вопрос 2:[/b] <2 вопрос> [spoiler][b]Ответ:[/b] <Ответ>[hr][/spoiler]
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Январь 10, 2011, 03:09:45
Обновление от Декабря 21, 2010, 12:50:08: Итак, благодаря подбадриваниям и похвалам со стороны читателей - я поверил, что это всё-таки кому-то нужно, и что хотя бы 1 или 2 человека это прочтут. :angel: Когда-нибудь. Встречайте, 21 новый вопрос и 2 новых раздела: "Оптимизация" и "ИИ". sm_oo6 P.S: всего, кажется, моими усилиями было собрано 66 вопросов! Были добавлены следующие вопросы: I.2.9. Сохраняются ли шрифты в GMK файле? Ответ: Нет. Если в исходнике используется шрифт, которого нет на данном компьютере - в игре будет использован Arial. Исполняемый файл игры (*.exe) напротив, хранит все шрифты в себе. I.2.10. Что такое "исходник"? Ответ: Это исходный файл проекта - *.gmk, *.gm6 и т.д. Иногда, под исходником так же подразумевают бэкап-файлы: *.gb1 - *.gb9 I.2.11. Как защитить exe от декомпиляции? Ответ: Можно использовать антидекомпилятор: http://gmc.yoyogames.com/index.php?showtopic=422511 (работает с играми созданными на GM8.0, GM7.0 и GM6.1 (предварительно конвертированными для запуска на Windows Vista (http://wiki.yoyogames.com/images/7/77/GM_Convert_Game.zip)), а так же программу MoleBox (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1060). II.1.10. Как сделать простую паузу одной кнопкой? Ответ: Один из самых простых алгоритмов состоит в использовании функции keyboard_wait (код нужно вставить в событие нажатия соответствующей клавиши): // Рисуем сообщение о паузе игры draw_set_color(c_black); draw_set_alpha(0.3); draw_rectangle(view_xview, view_yview, view_xview + view_wview, view_yview + view_hview, 0); draw_set_alpha(1); draw_set_halign(fa_center); draw_set_valign(fa_middle); draw_text(view_xview + view_wview/2, view_yview + view_hview/2, 'PAUSE');
// Обновляем экран screen_refresh();
// Останавливаем игру до нажатия какой-либо клавиши keyboard_wait(); Если вам нужно запускать игру только при нажатии клавиши P, или, скажем, клике мыши - замените keyboard_wait(); на while 1 { if keyboard_check_pressed('P') break; } II.1.11. Как сделать, чтобы значение переменной сохранялось между комнатами? Ответ: Первый способ - сделать переменную глобальной.Пример объявления глобальных переменных: global.variable = 100; globalvar variable2; variable2 = 100; Второй способ - сделать объект, в котором объявляется переменная - постоянным (persistent). Все глобальные переменные можно посмотреть в дебаг режиме: Tools -> Show Global Variables. II.1.12. Как определить, на какую кнопку в сообщении нажал пользователь? Ответ:Вариант 1: switch show_message_ext('Text', 'button 1', 'button 2', 'button 3') { case 1: show_message('button 1'); break; case 2: show_message('button 2'); break; case 3: show_message('button 3'); break; } Вариант 2: var message; message = show_message_ext('Text', 'button 1', '', 'button 2'); if message == 3 { show_message('button 2'); } Вариант 3: if show_message_ext('Text', 'button 1', '', 'button 2') == 3 { show_message('button 2'); } и так далее... II.2.7. Как сделать, чтобы игрок в tds двигался по диагонали с той же скоростью, что и по прямой? Ответ: Проблема состоит в том, что диагональ квадрата больше стороны квадрата. При чём тут квадрат? Когда сдвигаем героя просто вверх, просто влево, вправо или вниз - он сдвигается на n пикселей. Когда же мы сдвигаем его по диагонали - наш герой в действительности сдвигается на размер диагонали квадрата со стороной в n пикселей (к примеру, если мы сдвигаем героя на 100 пикселей влево и 100 пикселей вправо - герой в действительности сдвигается на ~141 пиксель). Соотношение диагонали квадрата к его стороне примерно равно 0.707. Чтобы получить нормальный сдвиг - нужно поделить скорость на корень из двух (~1.41) или умножить на 0.71 (1/sqrt(2)). Рисунок: (http://savepic.org/1031650.htm) Скачать пример: tds move.gmk (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2565) II.3.4. Как изменить глубину объекта в draw event? Ответ: Глубину объекта прямо в событии draw изменить нельзя. Можно использовать несколько объектов с разной глубиной или просто переставить действия в событии рисования (если вы используете 3D - почитайте про d3d_set_depth(depth) (http://gmakers.ru/gamemaker_help/source/files/415_02_drawing.php)). II.3.5. Какую нужно использовать формулу, чтобы вычислить глубину объекта в изометрии или в играх с видом как в классических jrpg? Ответ: Для игр с видом как в классических jrpg обычно используется формула depth = -y; при условии, что центр спрайта находится в точке столкновения объекта с землёй, а не в (0,0). Для изометрии можно использовать формулу depth = -(y - sprite_yoffset + (sprite_height + H) / 2), где H - высота объекта над уровнем земли. Если у одного и того же спрайта высота точек спрайта над уровнем земли разная - нужно использовать буфер глубины, то есть - 3D технологии. II.3.6. Как сделать ссылку / Текст, при клике на который выполнялось бы определённое действие? Ответ: Можно использовать следующий скрипт: /*************************************************** Скрипт рисует ссылку. argument0 - х; argument1 - y; argument2 - текст; Возвращает 1, если игрок кликнул на текст, иначе - 0. ***************************************************/ var xx, yy, str, width, height; // Задаём временные переменные xx = argument0; yy = argument1; str = argument2; width = string_width(str); height = string_height(str);
if mouse_x > xx and mouse_y > yy and mouse_x < xx + width and mouse_y < yy + height // Если пользователь навёл на мышку, то... { draw_set_color(c_red); // Устанавливаем цвет, с которым рисуется выделенная ссылка draw_text(xx, yy, str); // Рисуем текст draw_line(xx, yy + height, xx + width, yy + height); // Рисуем подчёркивание if mouse_check_button_released(mb_left) // Если пользователь кликнул на ссылку, то... { return 1; // Возвращаем 1, и завершаем работу скрипта } } else { draw_set_color(c_blue); // Рисуем ссылку обычным цветом draw_text(xx, yy, str); }
return 0; // Возвращаем 0 - пользователь не кликал на ссылку Пример использования, draw event: if draw_text_button(0, 0, 'button') { game_restart(); } II.4.9. Как изменить размер текущей комнаты? Ответ: Размер текущей комнаты напрямую изменить нельзя. Как вариант, можно перейти в другую комнату, изменить размер нужной комнаты, а затем вернуться в изначальную. Чтобы не перезапускать комнату - можно использовать свои переменные для хранения и изменения её размера. К примеру, в каком-нибудь контроллере объявляем глобальные переменные level_width и level_height. room_width и room_height везде заменяем на level_width и level_height соответственно. После этого нужно написать свой алгоритм движения вида - в событии begin step сначала двигаем объект, за которым следит вид (к примеру, героя), а затем сдвигаем вид по такому алгоритму: var xx, yy; xx = x; // Устанавливаем позицию, к которой должен двигаться вид yy = y;
if xx < view_xview[0] + view_hborder[0] view_xview[0] -= min(view_hspeed[0], view_xview[0] + view_hborder[0] - xx); if yy < view_yview[0] + view_vborder[0] view_yview[0] -= min(view_vspeed[0], view_yview[0] + view_vborder[0] - yy);
if xx > view_xview[0] + view_wview[0] - view_hborder[0] view_xview[0] += min(view_hspeed[0], xx - (view_xview[0] + view_wview[0] - view_hborder[0])); if yy > view_yview[0] + view_hview[0] - view_vborder[0] view_yview[0] += min(view_vspeed[0], yy - (view_yview[0] + view_hview[0] - view_vborder[0]));
view_xview[0] = median(0, view_xview[0], level_width - view_wview[0]); // Ограничиваем позицию вида view_yview[0] = median(0, view_yview[0], level_height - view_hview[0]); Где xx и yy - координаты точки, за которой следит вид. Все настройки вида в комнате можно оставить без изменений, только нужно обязательно убрать объект, за которым следует вид - установаить <no object> (опция находится в закладке view, object following). Теперь, можно свободно изменять переменные level_width и level_height, не перезапуская комнату. II.4.10. Как определить время компьютера? Ответ: Все функции можно посмотреть в справке: GML -> Игровой процесс -> Синхронизация (http://gmakers.ru/gamemaker_help/source/files/403_07_timing.php): current_time* Количество миллисекунд, которые прошли с тех пор, как система была запущена. current_year* Текущий год. current_month* Текущий месяц. current_day* Текущий день. current_weekday* Текущий день недели (1=воскресенье, ..., 7=суббота). current_hour* Текущий час. current_minute* Текущая минута. current_second* Текущая секунда. II.4.11. Как защитить счёт в игре от артмани? Ответ:Метод 1:Можно хранить в памяти не то значение которое выводится на экран - тогда пользователь не сможет узнать, по какому именно значению проводить поиск. Пример реализации: create event: score = 0; keyboard press space event: score += irandom(5) * 0.456; draw event: draw_text(x, y, score / 0.456); Таким образом, на экране отображается одно значение, а в памяти хранится всего 456/1000 от него. Конечно, желательно использовать более сложные формулы, чем просто деление и умножение. Метод 2:Можно создать ещё одну переменную для проверки счёта. Пример реализации: create event: score = 0; score_prev = score + 240.764; step event: if score != score_prev - 240.764 { show_message('Не пытайтесь взломать нашу игру. Это бесполезно.') game_end(); } keyboard press space event: score += irandom(5) * 0.456; score_prev = score + 240.764; draw event: draw_text(x, y, score); Таким образом, как только пользователь изменит кол-во счёта с помощью сторонних программ - игра сразу же это обнаружит. II.4.12. Как сделать паузу игры при открытии меню? Ответ: Есть несколько способов это сделать. Если меню текстовое, с управлением на клавиатуре - можно использовать рекурсию. Если же меню создано объектами - есть два основных способа: 1) В первую очередь, нужно установить текущей комнате persistent. Перед выходом в меню нужно сохранить скриншот игры в глобальную переменную, после этого - перейти в комнату меню. В комнате меню устанавливаем как фон скриншот игры. При клике на "Продолжить" - просто возвращаемся в комнату с игрой и удаляем скриншот игры. Всё просто. Базовый код этого метода: // Выход в меню: global.game_screen = background_create_from_screen(0, 0, view_wview, view_hview, 0, 0); // Создаём скриншот экрана room_goto(rm_menu); // Переходим в меню
// Room creation code комнаты rm_menu (settings -> Creation code): background_index[0] = global.game_screen; background_visible[0] = 1;
// Возвращение в игру: background_delete(global.game_screen); room_goto(rm_game); 2) Перед выходом в меню нужно сделать скриншот игры, после чего деактивировать все объекты (кроме тех, что нужны для работоспособности меню). Когда объекты деактивируются - они перестают отрисовывать свой спрайт, потому то нам и нужно запечатлить текущее состояние игры. После деактивации нужно создать кнопки и в draw event какого-нибудь контроллера отрисовывать скриншот игры как фон для меню (плавное затемнение и всякие эффекты для фона - это уже детали). При возвращении в игру активировать все объекты, удалить кнопки, убрать рисование скриншота игры и удалить сам скриншот. Вот базовый код этого метода: // Выход в меню: global.game_screen = sprite_create_from_screen(0, 0, view_wview, view_hview, 0, 0, 0, 0); // Создаём скриншот экрана instance_deactivate_all(true); // Деактивируем все объекты, кроме текущего instance_activate_object(o_menu_controll); // Активируем контроллеры, нужные для работы меню o_menu_controll.draw_game_screen = 1; // Указываем, чтобы объект o_controll рисовал скриншот игры на фоне instance_create(view_xview, view_yview, o_button); // Создаём кнопки
// Возвращение в игру: sprite_delete(global.game_screen); // Удаляем скриншот игры instance_activate_all(); // Активируем все объекты o_menu_controll.draw_game_screen = 0; // Указываем, чтобы объект o_controll более не рисовал скриншот игры на фоне with o_button instance_destroy(); // Удаляем все кнопки
// Draw event объекта o_menu_controll: if draw_game_screen { draw_sprite(global.game_screen, 0, view_xview, view_yview); } II.5.1. Что быстрее выполняется, sqrt(sqr(x2-x1)+sqr(y2-y1)) или point_distance(x1, y1, x2, y2)? Ответ: Встроенные функции GM выполняются быстрее самописных. point_distance будет работать быстрее. II.5.2. Что производительней использовать, lengthdir_x(len, dir) и lengthdir_y(len, dir) или cos(degtorad(dir))*len и -sin(degtorad(dir))*len? Ответ: Как и в случаее с point_distance, lengthdir_x и lengthdir_y будет работать быстрее. II.5.3. Что выполняется быстрее - стандартные проверки GM в объекте (на подобии mouse -> left button), или собственные проверки в step event? Ответ: Стандартные события GM выполняются быстрее проверок в шаге. Вероятно, из-за того, что интерпретация кода, каким-бы простым он ни был - занимает больше времени. Вывод: производительней будет активней использовать стандартные гм события, чем писать собственные проверки в step event. Однако, разница в скорости выполнения не столь велика, чтобы злоупотреблять этим. P.S: я лично, например, обычно вручную пишу большинство проверок в step event объекта. II.5.4. Если одно из выражений в условии ложно, будет ли проверяется условие всё целиком? Ответ: В отличии от большинства языков программирования, в GML проверяется всё условие, вне зависимости, является ли одно из выражений ложным. То есть, условие написанное так: if is_picture_grayscale(temp) { if is_pisture_fractal(temp) { // ... } } будет выполнятся быстрее условия, записанного так: if is_picture_grayscale(temp) and is_pisture_fractal(temp) { // ... } (названия скриптов взяты наобум) II.6.1. Как сделать, чтобы противники видели игрока только на определённом расстоянии, и не смотрели сквозь стены? Ответ: Для того, чтобы определить дистанцию между игроком и противником можно использовать функцию point_distance. Чтобы определить, есть ли между противником и игроком препятствие - можно ипользовать функцию coolision_line. Стоит принять во внимание, что объекта игрока может и не быть в комнате (к примеру, если его убили), потому - нужно проверить, существует ли он. Код будет выглядеть примерно так: if instance_exists(o_player) // Если объект игрока существует { if point_distance(x, y, o_player.x, o_player.y) < 300 // 300 - радиус зрения противника { if !collision_line(x, y, o_player.x, o_player.y, o_wall, 0, 0) // Если между игроком и ботов нет стен, то... { // Идём к игроку, стреляем или выполняем любые другие действия. } } } II.6.2. Как сделать, чтобы зомби двигался за игроком или союзным персонажем обходя препятствия? Ответ:Для начала нужно проверить, есть ли в комнате хотя бы один союзный юнит. Для этого всем союзным юнитам и игроку в том числе устанавливаем родителем объект o_friend (parent). После этого, находим ближайшего из юнитов и, если он находится в радиусе видимости, двигаемся к нему. if instance_exists(o_friend) // Если существует хотя бы один экземляр объекта o_friend (или дочерного объекта), то... { var obj, dis; obj = instance_nearest(x, y, o_friend)); // Определяем ближайшего юнита dis = point_distance(x, y, obj.x, obj.y); // Определяем расстояние к нему if dis < 300 and dis > 16 // Если он в пределах видимости { mp_potential_step(obj.x obj.y, spd, 0); // Двигаемся к нему со скоростью spd, обходя все твёрдые объекты } } II.6.3. Как сделать, чтобы башня стреляла в ближайшего противника (речь о жанре "Башенная защита")? Ответ:var obj; obj = instance_nearest(x, y, o_enemy); if obj != noone { var bull; bull = instance_create(x, y, o_bullet); with (bull) { move_towards_point(obj.x, obj.y, spd); } } Где spd - скорость пули, o_enemy - объект противника.
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Январь 10, 2011, 03:27:30
Привет, друзья! sm_milo Как и ожидалось, кроме FanTom'а и Лера свои вопросы/ответы никто не добавляет, так что приходится тянуть всё самому :) Однако, благодаря моральной поддержке со стороны читателей - новое обновление выходит в свет! Особенно хочется поблагодарить Vendet'а, Dva_Kota, Ogion'а, Макасина, и, конечно же, Лера! Без их подбадриваний вам бы пришлось ещё долго ждать обновления :) Как и раньше, автором всех ответов остаюсь я. В этом обновлении были затронуты такие темы как: движущиеся платформы, запрыгивание на платформы снизу, неровная поверхность, мгновенные пули, плавный поворот, определение позиции столкновения, движение ящиков, разные показатели жизней у противников, проигрывание анимации наоборот и вылетание пули из дула! В общем, множество вопросов, которые постоянно волнуют новичков, как волновали меня когда-то. ) Для продвинутых пользователей могу посоветовать заглянуть в группу вопросов I.3 - там много полезной информации, включая "I.3.5. Что такое lengthdir_x и lengthdir_y и как им пользоваться?". Кроме новых вопросов-ответов так же был создан новый раздел - "Примеры". В нём находится список примеров, созданных специально для FAQ, в этом обновлении было добавлено 5 примеров. В создании примеров поучаствовал мой товарищ Лер, за что ему выражаю большую благодарность! Он молодец ;] После этого обновления будет долгая пауза, после которой я надеюсь написать три_раза_уже_обещанные статьи. Они будут значительно информативнее, чем ответы в faq и их тема будет разжёванна до мелочей. Так же, торжественно объявляю, что кол-во вопросов в FAQ перевалило за сотню! С этим обновлением в FAQ добавляется 40 новых вопросов. На данный момент faq насчитывает 105 вопросов! С вопросами вышла небольшая непонятка. Когда я их дописал - их было 42. Когда я выбрал, куда их ставить - их стало 40. А когда вставил в FAQ - кажется, их стало 39. Мне остаётся только гадать, в чём причина :errm: И да, смотрим новую шапку темы (http://forum.hellroom.ru/index.php/topic,2035.0.html)! Итак, были добавлены следующие вопросы: I.2.11. Как изменить меню, которое появляется при нажатии на F2 в редакторе кода? Ответ: К папке с установленным Game Maker 8 вы можете найти файл "snippets.txt" (по умолчанию: C:\Program Files\Game_Maker8\snippets.txt). Теперь вы можете создать свои собственные шаблоны кода - это бывает очень полезно. I.3.3. Как работают функции рисования в GM? Что делают функции screen_redraw, screen_refresh? Ответ: Для начала следует понять, что вызывая функции рисования - вы рисуете не прямо на экране, а на внутренний буфер. В начале события draw внутренний буфер очищается, а в конце - отображается на экран. Рисуя что либо, к примеру, в step event - вы рисуете на внутренний буфер, но он не отображается на экран. Функция screen_refresh предназначена для того, чтобы обновить изображение на экране - она отображает внутренний буфер. Функция screen_redraw сначала выполняет все события рисования - заполняет внутренний буфер цветом фона, рисует фоны, вызывает события рисования всех объектов, а затем обновляет изображение на экране (отображает внутренний буфер). Механизм использования глубины можно описать следующим образом. В начале события draw event строится приоритетная очередь, в которой роль значения играет индекс объекта/тайла, а приоритет - глубина. Далее вся графика отображает в порядке приоритета, именно потому глубину рисования нельзя менять в draw event - приоритетная очередь уже построена. В случае с 3D - используется буфер глубины, и там ситуация немного иная. Безусловно, мы не можем знать наверняка, как всё устроено в Game Maker'е, если только сами разработчики нам об этом не расскажут. Это не точное описание внутренних механизмов GM, это лишь общий принцип работы функций рисования, и все факторы указывают на то, что он именно такой. I.3.4. Что такое комната? Что такое persistent комнаты, game save и game load? Ответ: Давайте поразмышляем. Что такое комната? Комната - это набор определённых настроек, опции видов и фонов, список всех объектов и тайлов. На самом деле, самая первая, "нулевая" комната - это комната загрузки. В ней, загружается движок GM и все внутренние ресурсы , инициализируется окно игры и загружается первая игровая комната. Под фразой "загружается комната" я подразумеваю следующие действия: 1) Назначаются значения всем переменным комнаты: 1.1) Индекс комнаты - room 1.2) Заголовок комнаты - room_caption 1.3) Ширина и высота комнаты - room_width и room_height 1.4) Скорость комнаты - room_speed 1.5) Постоянность комнаты - room_persistent 1.6) Цвет фона и его видимость - background_color и background_showcolor 2) Загружается массив видов: 2.1) Видимость в момент начала комнаты - view_visible[0..7]. 2.2) Позиция, ширина и высота вида: view_xview[0..7], view_yview[0..7], view_wview[0..7] и view_hview[0..7]. 2.3) Позиция, ширина и высота порта: view_xport[0..7], view_yport[0..7], view_wport[0..7] и view_hport[0..7]. 2.4) Граница вокруг преследуемого объекта: view_hborder[0..7] и view_vborder[0..7]. 2.5) Вертикальная и горизонтальная скорость: view_hspeed[0..7] и view_vspeed[0..7]. 2.6) Преследуемый объект - view_object[0..7]. 2.7) * Поворот вида - view_angle[0..7]. 3) Загружается массив фонов: 3.1) Видимость в момент начала комнаты - background_visible[0..7] 3.2) Отображать ли фон над объектами - background_foreground[0..7] 3.3) Индекс фонового изображения - background_index[0..7] 3.4) Позиция - background_x[0..7] и background_y[0..7] 3.5) Замощение комнаты по горизонтали/вертикали - background_htiled[0..7] и background_vtiled[0..7] 3.6) Вертикальная и горизонтальная скорость - background_hspeed[0..7] и background_vspeed[0..7] 3.7) Масштаб фона - background_xscale[0..7] и background_yscale[0..7] 3.8) * Цвет смешивания для фона - background_blend[0..7] 3.9) * Непрозрачность фона - background_alpha[0..7] 4) Создаются все тайлы: 4.1) Позиция тайла - x, y. 4.2) Индекс фона - background. 4.3) Часть фона - left, top, width, height. 4.4) Глубина тайла 4.5) id тайла, начинается с 10 000 001 (включительно) 5) Создаются все объекты, вычисляется instance_count и заполняется массив instance_id: 5.1) Позиция - x, y. 5.2) Индекс объекта - object_index. 5.3) id, начинается с 100 001 (включительно) 6) ^ Выполняется creation code объектов (который задаётся в комнате) 7) ^ Выполняется creation event объектов 8) # Game start (Выполняется только в момент начала игры) 9) ^ Room creation code (выполняется код, задаваемый в настройках комнаты) 10) Room start event
Действия не обозначенные символами выполняются в любом случае - при загрузке самой первой комнаты, при загрузке сохранения, при загрузке persistent комнаты и т.д. Действия, обозначенные символом "^" - выполняются только при первом попадании в комнату, а так же для всех не persistent комнат. Если вы вышли из постоянной комнаты, а потом вернулись - эти действия не выполнятся. Действия, обозначенные символом "*" - выполняются только при сохранении/загрузке игры или сохранении данных/загрузке постоянной комнаты. Эти настройки нельзя изменить в редакторе комнат, потому, при первом попадании в комнату они не загружаются, а получают значения по умолчанию. Действие же обозначенное символом "#" - событие начала игры, выполняются только один раз, при первой загрузке самой первой комнаты. Обратите внимание, что вне зависимости от того, является ли комната постоянной - событие Room start выполняется всегда.
Этот список действий может внести некоторую ясность в то, что конкретно происходит в начале игры и как реализован механизм сохранения постоянных комнат.
Если установлен persistent, при переходе в другую комнату - все данные о текущем состоянии комнаты перезапишутся: массивы видов, фонов, списки объектов и тайлов и т.п., а так же все локальные переменные всех объектов (стоит учесть, хотя массивы сохраняются, динамические структуры данных - нет). При сохранении игры сохраняются данные обо всех persistent комнатах, включая текущую (вне зависимости, постоянная она или нет) + глобальные переменные и, наверняка, что-то ещё. Сурфейсы, новые объекты, загруженные спрайты, фоны, звуки, изменения в действиях объектах (objext_event_*), динамические структуры данных, позиции проигрывания звуков, настройки игры (полноэкранность и т.п.), частицы - всё это НЕ сохраняется стандартным механизмом сохранения GM. Что же происходит при загрузке? Всего лишь заменяются данные для всех persistent комнат, включая текущую (не зависимо, постоянная ли она). Я лично предполагаю, что все значения локальных переменных записываются в creation code объектов, и этот код выполняется всегда. Однако, я всё равно обозначил его символом "^", так как знать наверняка не могу.
Написать свой механизм сохранения проще, чем кажется, стоит только всё продумать. I.3.5. Что такое lengthdir_x и lengthdir_y и как им пользоваться? Ответ: Чтобы вам легче было разобраться - начнём с небольшой задачи. Есть позиция, (x1,y1), направление - angle, и расстояние - dis. Как вычислить позицию (x2,y2), расположенную на расстоянии dis от позиции (x1,y1) в указанном направлении? (http://savepic.org/1206681.jpg) ссылка на изображение, размер: 23.4 кбайт, 160 x 160 точек (http://savepic.org/1206681.htm)
Сейчас немного теории. Прямоугольный треугольник: Прямоугольный треугольник - это треугольник с углом 90° (прямым углом). Катет - одна из двух сторон прямоугольного треугольника, образующая прямой угол. Гипотенуза - сторона прямоугольного треугольника, противоположная прямому углу. Синус и Косинус: Из школьного курса геометрии вам должно быть известно два определения синуса: 1) синус острого угла это отношение катета, лежащего напротив этого угла к гипотеузе. 2) синус это ордината (y-координата, если кто забыл) точки, лежащей на единичной окружности. Косинус так же имеет два общеизвестных определения: 1) косинус острого угла это отношение катета, выходящего из этого угла (прилежащего катета), к гипотенузе. 2) косинус это абсцисса точки, лежащей на единичной окружности. Единичная окружность - это окружность с радиусом 1.
Так как косинус (cos(angle)) по определению - (x2-x1)/dis, стаёт очевидно, что x2-x1 мы можем найти умножив значение косинуса на dis: cos(angle)*dis, а y2-y1 с помощью синуса: sin(angle)*dis. Однако, в декартовой системе координат абцисса направлена вверх, а не вниз, как в Game Maker. Потому, следует отразить координату y, отнять её от нуля или просто изменить её знак: -sin(angle)*dis. (http://savepic.org/1205657.jpg) ссылка на изображение, размер: 24.5 кбайт, 160 x 160 точек (http://savepic.org/1205657.htm)
Но, что если угол angle не острый и не удаётся построить прямоугольный треугольник как нужно? Смотрим второе определение: (http://savepic.org/1211801.jpg) ссылка на изображение, размер: 29.4 кбайт, 160 x 160 точек (http://savepic.org/1211801.htm) т.е. в любом случае cos и sin будут работать как надо.
Итак, формулы верны. Что же такое lengthdir_x и lengthdir_y? [gml]lengthdir_x(len, angle) = cos(angle)*dis; lengthdir_y(len, angle) = -sin(angle)*dis;[/gml]
Подведём итог: [gml]x2 = x1 + lengthdir_x(dis, angle); y2 = y1 + lengthdir_y(dis, angle);[/gml]
I.3.6. Что за переменная image_single, которой нет в справке? Ответ: Эту переменную оставили для совместимости с играми, разрабатываемыми в старых версиях Game Maker. Она изменяет кадр и автоматически устанавливает скорость анимации на 0. К примеру, вместо [gml]image_single = 3;[/gml] Можно написать: [gml]image_index = 3; image_speed = 0;[/gml] Не смотря на её удобность в некоторых случаях - рекомендуется использовать image_index и image_speed. I.3.7. Что это за функции, которые начинаются с приставки action_ и которые не описаны в справке? Ответ: Это встроенные функции в Game Maker, точно повторяющие действия стандартных *.lib библиотек. Они не имеют описания в справочном руководстве и для них не показывается подсказка в редакторе кода. Их рекомендуется использовать только новичкам, которые только-только перешли на код. В этом документе можно увидеть полный список этих функций: http://www.blackratstudios.com/games/DD_to_GML_7/Drag%20and%20Drop%20Icons%20and%20their%20GML%20Equals_Ver%207.html I.3.8 Как работает оператор mod? Ответ: Оператор mod - это деление по модулю. Операция деление по модулю это нахождение остатка от деления одного числа на другое, т.е. той части числа, которая не поделилась нацело. К примеру, если поделить число 90 на 11 - получим 8.(18). Остаток же от деления будет 2 - число 90 можно записать как 11*8 + 2: 90 / 11 = 8.18181818... 90 div 11 = 8 90 mod 11 = 2 90 = (90 div 11) * 11 + (90 mod 11) I.3.9. Зачем нужен оператор var? Ответ: Когда вы создаёте объект - вы автоматически создаёте 50 локальных переменных и один массив: id object_index persistent solid depth mask_index visible
xstart ystart xprevious yprevious x y
hspeed vspeed speed direction friction gravity gravity_direction
sprite_index sprite_width sprite_height sprite_xoffset sprite_yoffset
image_index image_xscale image_yscale image_angle image_blend image_alpha
image_number image_speed image_single
bbox_left bbox_right bbox_bottom bbox_top
path_endaction path_index path_orientation path_position path_positionprevious path_scale path_speed
timeline_index timeline_loop timeline_position timeline_running timeline_speed
alarm Заданные локальные переменные в этом объекте остаются с ним до удаления или до конца игры. Если вы объявляете какие-то переменные в скрипте, а потом вызываете этот скрипт в объекте - все новые переменные остануться с этим экземпляром, захламляя собой память. Оператор var предназначен для объявления временных переменных, которые будут удалены по завершению выполнения этого скрипта. Эти переменные не являются локальными для данного экземпляра объекта, а общие для всех. К примеру, такой код не выдаст ошибки: [gml]var i; // Объявляем временную переменную i = 100; with o_test // Обращаемся к другому объекту a += i; // Используем временную переменную в этом объекте[/gml] Создавать временные переменные можно не только в скриптах, но и в действиях объектов, коде создания комнаты, триггерах и т.п. I.3.10. Когда следует использовать switch, а когда if? Ответ: Оператор switch следует использовать в том случае, когда количество вариантов значения одной переменной превышает 2-3 раза. Конечно, многое зависит от ситуации, иногда даже четыре проверки удобно записать оператором if. Пример использовать оператора switch: [gml]switch varible { case value0: action1(); break; case value1: action2(); break; case value2: action3(); break; case value3: action4(); break; default: action5(); }[/gml]
Оператор if: [gml]if varible == value0 then action1() else if varible == value1 then action2() else if varible == value2 then action3() else if varible == value3 then action4() else action5();[/gml] II.1.13. Как выполнить действие, только если объект находится в определённом радиусе? Ответ: Для того, чтобы проверить, находится ли объект в определённом радиусе - можно использовать функцию point_distance. Проверяя, на каком расстоянии находится объект - мы получим определённый радиус. Пример: [gml]if point_distance(x, y, some_object.x, some_object.y) < 200 // 200, в данном случае, радиус { // Выполняем действия }[/gml] II.1.14. Как выполнить действие, только если герой собрал все монеты/ресурсы и т.п.? Ответ: Для этого нужно проверить кол-во объектов в комнате. Пример: [gml]if instance_number(o_star) == 0 { // Выполняем нужные действия }[/gml] II.2.8. Как сделать плавный поворот турели? Ответ: Для этого нужно добавить два скрипта. Первый, angle_difference - вычисляет разницу между двумя направлениями: [gml]/* ** usage: ** diff = angle_difference(angle1,angle2); ** ** given: ** angle1 first direction in degrees, real ** angle2 second direction in degrees, real ** ** returns: ** difference of the given angles in degrees, -180 to 180 ** ** GMLscripts.com */ { return ((((argument0 - argument1) mod 360) + 540) mod 360) - 180; }[/gml] Второй, set_angle (здесь название может быть любым) - вычисляет новое направление: [gml]/* Скрипт плавно изменяет направление башни до требуемого Возвращает полученное направление argument0 - текущее направление argument1 - требуемое направление argument2 - скорость изменения направления Автор скрипта DreamRunner 09.09.2006 */
argument0 = argument0 mod 360; // Ограничиваем направление - от -360 до 360 (не включительно). if argument0 <0 argument0 += 360; // Если направление меньше 360 - преобразовываем значение в положительное if abs(angle_difference(argument0,argument1)) < argument2 // Если разница между направлениями меньше скорости поворота, то... return argument1; // Возвращаем требуемое направление return argument0 + (sign(sin(degtorad(argument1-argument0))) * argument2); /* sign(sin(degtorad(argument1-argument0))) - от 0 до 180 получаем положительно значение, от 180 до 360 - отрицательное. т.е. определяем, в какую сторону нужно повернуть объект. Если разница между направлениями меньше 180 - значит по часовой стрелке, больше - против часовой. */[/gml] Пример использования, step event: [gml]image_angle = set_angle(image_angle, point_direction(x, y, mouse_x, mouse_y), 3);[/gml] II.2.9. Как сделать движущиеся платформы в платформере? Ответ: На самом деле, в этом нет ничего сложного, нужно только хорошенько подумать. Если вы используете встроенные механизмы движения, вроде vspeed и gravity - позиция игрока измениться после step event и до end step event. Значит, платформа, как и игрок сдвинется после step'а игрока. Итак, в step event игрока мы проверяем, нет ли платформы под игроком. Если под игроком есть подвижная платформа - мы записываем её id в переменную, чтобы двигать игрока за ней. В end step игрока мы сдвигаем игрока относительно платформы, на которой он стоит. Далее мы проверяем, если игрок всё же столкнулся с платформой (к примеру, когда горизонтальная платформа наехала на игрока) - мы возвращаем платформу на предыдущую позицию и меняем её направление движения - буквально "выталкиваем" из игрока. В коде это выглядит примерно так: create event игрока: [gml]platform = noone; // Изначально игрок не стоит на подвижной платформе[/gml] step event игрока: [gml]//... platform = instance_place(x, y + 1, o_moving_platform); // Определяем id платформы под игроком, если под игроком нет платформы - функция возвратит значение noone, -4. id всегда начинается с 100001, что значит - можно использовать проверку "if platform", что аналогично "if platform >= 0.5". Если для вас эта проверка в новинку, можете писать "if platform != noone"[/gml] end step event игрока: [gml]//... if platform // Если игрок стоит на платформе, то... { x += platform.hspeed; // Двигаем игрока относительно платформы y += platform.vspeed; }
platform = instance_place(x, y, o_moving_platform); if platform // Если на игрока наехала платформа, то... { with platform { x = xprevious; // Возвращаем платформу на предыдущую позицию y = yprevious; hspeed *= -1; // Инвертируем скорость, если платформа двигалась влево - она будет двигаться вправо и т.п. vspeed *= -1; } }[/gml] P.S: если у вас возникают проблемы со столкновениями, залипания игрока в платформах и т.п. - советую вам отказаться от использования vspeed и hspeed, так как встроенный механизм движения автоматически останавливает объект при столкновении c solid объектом. II.2.10. Как сделать движение по неровной поверхности в платформере? Ответ: Здесь тоже нет ничего сложного. Проблема в том, что иногда игроку может препятствовать всего один пиксель, и чтобы на него взобраться - приходится прыгать. Потому, нужно создать некоторую имитацию ног человека - за один шаг игрок может взобраться на несколько пикселей, без прыжка. Итак, сначала задаётся максимальная высота, на которую может взобраться игрок - обычно 4-8 пикселей. Во время движения в цикле проверяется сначала позиция прямо возле игрока, потом на один пиксель выше, на два пикселя выше, и так до максимальной высоты, на которую может взобраться игрок за один шаг. Эта картинка наглядно демонстрирует метод: http://savepic.org/1160418.png В коде это будет выглядеть примерно так: step event: [gml]var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. { if place_free(x - spd, y - i) // Если данная позиция свободна, то... { x -= spd; // Двигаем игрока y -= i; break; // Завершаем цикл } } }
//...[/gml] Где vdis_max - максимальная высота, на которую может взобраться игрок за один шаг, spd - скорость передвижения игрока. В случае, если нужно реализовать ещё и быстрый спуск по ступенькам вниз - код будет выглядеть примерно так: [gml]var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. if place_free(x - spd, y - i) // Если данная позиция свободна { x -= spd; // Двигаем игрока y -= i; if place_free(x, y + 1) // Если игрок не стоит на платформе, if !place_free(x, y + vdis_max2 + 1) // Но она под ним есть! for (i = 0; i < vdis_max2 + 1; i += 1) // Проверяем все позиции немного ниже его { if !place_free(x, y + i) // Если в данная позиция занята твёрдым объектом { y += i - 1; // Двигаем игрока вплотную к этому объекту break; // Завершаем цикл } } break; // Завершаем цикл } }[/gml] Собственно, эти циклы - самописные аналоги функций move_outside_solid и move_contact_solid. При желании их можно заменить встроенными функциями, или даже использовать instance_place.
II.2.11. Как сделать, чтобы игрок запрыгивал на платформы снизу? Ответ: Идея проста: выполнять событие столкновения с платформой только если игрок находится выше платформы. Переменная bbox_bottom - нижняя граница прямоугольника, ограничивающего спрайт объекта. bbox_top, соответственно, верхняя. Можно было бы просто сравнить bbox_bottom игрока и bbox_top платформы - но часто бывает так, что событие столкновения вызывается уже тогда, когда игрок непосредственно пересекается с платформой, и проверка может не сработать. Потому, поверку в событии столкновения игрока с платформой можно записать так: [gml]if bbox_bottom-vspeed <= other.bbox_top // Если в предыдущей позиции игрок был выше платформы, а теперь столкнулся с ней, то... { // Выполняем события столкновения... (можно вернуть игрока на предыдущую позицию, и с помощью move_contact_solid сдвинуть его вплотную к платформе) }[/gml] Так же обратите внимание, что объекты, которые движутся с помощью стандартных механизмов движения GM - автоматически останавливаются при контакте с solid объектами. II.2.12. Как сделать, чтобы игрок скользил по неровным стенам в tds игре? Ответ: Используется тот же принцип, что и с движением по неровной поверхности в платформере, только реализуется немного иначе. Если позиция перед игроком занята - пытаемся изменить направление игрока так, чтобы позиция была свободна - на 10 градусов влево/вправо, на 20 градусов влево/вправо и т.д. Пример реализации: [gml]var spd, dir, angle, angle_step, lx, ly, i; spd = 8; // Скорость движения игрока dir = -1; angle = 90; // Максимальный поворот игрока angle_step = 5; // Величина, на которую увеличивается направление в шаге цикла
if keyboard_check(ord('W')) dir = 90; // В зависимости от того, какую клавишу нажал пользователь - определяем направление игрока if keyboard_check(ord('A')) dir = 180; if keyboard_check(ord('S')) dir = 270; if keyboard_check(ord('D')) dir = 0;
if dir != -1 // Если игрока нужно подвинуть, то... { for (i = 0; i < angle; i += angle_step) // Цикл отклонения. В начале - проверяем позицию прямо перед игроком, затем +-angle_step, +-angle_step*2 и т.д. { lx = lengthdir_x(spd, dir + i); // Вычисляем смещение игрока ly = lengthdir_y(spd, dir + i); if place_free(x + lx, y + ly) // Если эта позиция свободна, то... { x += lx; // Двигаем игрока y += ly; break; // Завершаем цикл } lx = lengthdir_x(spd, dir - i); // Проверяем позицию левее; действия и проверки аналогичны ly = lengthdir_y(spd, dir - i); if place_free(x + lx, y + ly) { x += lx; y += ly; break; } } }[/gml] Для ускорения работы алгоритма можно увеличить значение angle_step и/или уменьшить значение angle. Для увеличения точности нужно уменьшать значение angle_step. II.2.13. Как прикрепить башню танка к самому танку? Ответ: Во-первых, позицию башни танка нужно изменять исключительно после изменения позиции танка, чтобы она не отставала. Прикрепить башню можно двумя способами, либо написать примерно такой код в step event башни: [gml]x = o_panzer.x; // Изменяем позицию башни y = o_panzer.y;[/gml] Либо в draw event сразу рисовать спрайт башни в нужной позиции: [gml]draw_sprite_ext(sprite_index, image_index, o_panzer.x, o_panzer.y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);[/gml] II.2.14. Как сделать, чтобы интерфейс не отставал от вида при движении? Ответ: Позицию элементов интерфейса нужно менять после изменения позиции объекта, за которым следит вид - в end step event либо в draw event. II.2.15. Как определить позицию столкновения? Как определить, в какую сторону ударил снаряд? Ответ: Определить позицию столкновения часто бывает довольно сложно, если снаряд и противник имеют сложную форму. Вычислить позицию столкновения можно двумя способами: относительно пули, и относительно объекта, с котором столкнулась пуля. Если пуля круглая или всё время повёрнута в сторону полёта - проще всего. Для начала нам нужно определить расстояние от центра спрайта до точки столкновения при повороте 0 градусов (для круглой пули поворот не учитывается). Если пуля использует bbox для проверки столкновений - ограничивающий прямоугольник, формула может выглядеть так: [gml]len = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index)[/gml] Событие столкновения часто вызывается уже тогда, когда пуля непосредственно над объектом. Потому, перед поиском точки столкновения нужно выполнить такой код: [gml]x = xprevious; // Возвращаем пулю на предыдущую позицию y = yprevious; move_contact_solid(direction, speed); // Пододвигаем её вплотную к объекту (объект должен быть твёрдым)[/gml] Итак, если направление пули - direction, код будет выглядеть так: [gml]var len, xx, yy; x = xprevious; y = yprevious; move_contact_solid(direction, speed);
len = sprite_get_bbox_right(sprite_index) - sprite_get_xoffset(sprite_index); xx = x + lengthdir_x(len, direction); yy = y + lengthdir_y(len, direction);[/gml] Где xx, yy - полученная точка столкновения. Если пуля неровная, но объект, с которым она столкнулась повёрнут в ней, либо он круглый - выполняем те же действия, только для объекта-преграды. В случае, когда таким способом точку столкновения обнаржуить не удаётся - вам придётся придумывать собственные формулы, для вашего конкретного случая. II.2.16. Как сделать, чтобы герой в игре жанра "лабиринт" мог двигать ящики? Ответ: Реализация возможности двигать ящики зависит от того, как реализовано управление игроком. Если он двигается за счёт speed и direction, можно поставить такой код в событие столкновения камня с игроком: [gml]if place_free(x + lengthdir_x(other.speed, other.direction), y + lengthdir_y(other.speed, other.direction)) // Если камень можно сдвинуть { x += lengthdir_x(other.speed, other.direction); // Двигаем камень по направлению движения игрока y += lengthdir_y(other.speed, other.direction); } else // Если камень нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию { x = xprevious; y = yprevious; speed = 0; } }[/gml]
Если игрок двигается за счёт vspeed и hspeed, можно использовать такой код: [gml]if place_free(x + other.hspeed, y + other.vspeed) // Если камень можно сдвинуть { x += other.hspeed; // Двигаем камень по направлению движения игрока y += other.vspeed; } else // Если камень нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию { x = xprevious; y = yprevious; vspeed = 0; hspeed = 0; } }[/gml]
В случае, если игрок двигается непосредственно через x и y - можно использовать такой код: [gml]var len, dir, lx, ly; with other { len = point_distance(xprevious, yprevious, x, y); dir = point_direction(xprevious, yprevious, x, y); } lx = lengthdir_x(len, dir); ly = lengthdir_y(len, dir);
if place_free(x + lx, y + ly) // Если камень можно сдвинуть { x += lx; // Двигаем камень по направлению движения игрока y += ly; } else // Если камень нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию { x = xprevious; y = yprevious; } }[/gml] II.2.17. Как сделать, чтобы пуля вылетала из дула? Ответ: Нужно использовать lengthdir_x и lengthdir_y. Предположим, у нас есть такой спрайт: (http://savepic.org/1202587.jpg) ссылка на изображение, размер: 19.2 кбайт, 160 x 160 точек (http://savepic.org/1202587.htm) Красный крест - центр спрайта. Пуля должна создаваться на конце дула: (http://savepic.org/1188251.jpg) ссылка на изображение, размер: 21.6 кбайт, 160 x 160 точек (http://savepic.org/1188251.htm) Для того, чтобы она создавалась в нужном месте нужно: 1) Записать координаты центра спрайта и позиции, в которой нужно создать объект; 2) Вычислить расстояние между этими двумя координатами; 3) Вычислить направление между этими двумя координатами. Тепрь, пулю можно создавать в этой позиции: [gml]xx = x + lengthdir_x(len, direction + dir); yy = y + lengthdir_y(len, direction + dir);[/gml] Где len - расстоние между двумя точками, direction - текущее направление объекта, dir - направление от центра спрайта к точке на конце дула. Расстояние и направление можно вычислить с помощью функций point_distance и point_direction. II.2.18. Как реализовать мгновенные пули? Ответ: Для реализации мгновенных пуль нужно либо написать свой алгоритм, аналогичный collision_line, либо использовать move_contact_solid. К примеру, при стрельбе вы могли бы использовать подобный алгоритм: [gml]var i, temp_x, temp_y; // Объявляем временные переменные for(i = 0; i < shoot_distance; i += 4) { temp_x = x + lengthdir_x(i, direction); // Вычисляем новую позицию temp_y = y + lengthdir_y(i, direction); obj = collision_circle(temp_x, temp_y, 2, all, 0, 0); if obj != noone // Если в этой позиции находится какой-то объект { if obj.object_index = o_enemy // Если это враг, то... { with obj hp -= 10; // Уменьшаем его кол-во жизней } if obj != id // Если это не тот объект, кто стреляет, то... { break; // Завершаем цикл } } }[/gml] Где shoot_distance - максимальная дистанция, которую может достигнуть пуля, direction - направление полёта пули и o_enemy - объект врага. Заметьте, что hp не изначально определённая переменная, и она использована здесь для примера. Для оптимизации скрипта - можно увеличить кол-во пикселей, на которое смещается позиция проверки каждый шаг (4 по умолчанию), или заменить проверку collision_circle чем-то вроде collision_point. Обратите внимание, что проверка производиться для всех объектов, но, если, к примеру, в одной позиции будет одновременно находится объект врага и объект, скажем, решётки на полу - может возникнуть баг, так как пуля может не проверить столкновение с врагом. В таком случае - для всех объектов, с которыми происходит действие пули - можно создать родитель (parent), и заменить all в коде на его имя. Другой вариант - делать несколько проверок для каждого объекта. Стоит учесть, что это далеко не единственный способ реализации мгновенной стрельбы. II.3.7. Можно ли для хелсбара использовать спрайт, а не цвет? Ответ: Конечно! [gml]draw_sprite(s_healthbar, 0, view_xview + 8, view_yview + 8) //Рисуем фон draw_sprite_part(s_healthbar, 1, 0, 0, sprite_get_width(s_healthbar) * (Health / Health_max), sprite_get_height(s_healthbar), view_xview + 8, view_yview + 8) //Рисуем жизни на фоне[/gml] s_healthbar - спрайт хелсбара, первый кадр должен быть фоном хелсбара, а второй кадр - картинка полностью заполненного жизнями хелбара. Health - текущее кол-во жизней, Health_max - максимальное кол-во жизней. view_xview + 8, view_yview + 8 - позиция хелсбара
II.3.8. Как сделать, чтобы при наведении на объект высвечивалась информация о нём? Ответ: В draw event объекта, при наведении на который должна высвечиваться информация следует добавить такой код: [gml]if position_meeting(mouse_x, mouse_y, id) // Если в позиции мышки находится данный экземпляр объекта, то... { // Рисуем нужную информацию. }[/gml] Так же не стоит забывать, что если добавить какой-то код в событие draw - GM перестанет автоматически рисовать спрайт объекта, так что его отрисовку нужно добавить вручную (с помощью функции draw_sprite, к примеру). II.3.9. Как повернуть сурфейс относительно его центра? Ответ: Нужно использовать 3D-преобразования, которые отлично работают и в 2D. Пример: [gml]d3d_transform_add_translation(-surface_get_width(surface)/2, -surface_get_height(surface)/2, 0); // Устанавливаем сурфейс в центр d3d_transform_add_rotation_z(image_angle); // Поворачиваем его на величину image_angle d3d_transform_add_translation(x, y, 0); // Сдвигаем в нужную позицию, там, где будет рисоваться сурфейс draw_surface(surface, 0, 0); // Рисуем сурфейс d3d_transform_set_identity(); // Отключаем все преобразования, установленные пользователем[/gml]
II.3.10. Как полностью перекрасить спрайт в другой цвет? Ответ: Для того, чтобы перекрасить спрайт в чёрный цвет - можете использовать image_blend, тот же параметр color в функциях для отображения спрайтов. Кстати, это довольно полезная функция, к примеру - с её помощью можно легко создать тень, пример: [gml]draw_sprite_ext(sprite_index, 0, x + 2, y + 2, 1, 1, 0, c_black, 0.3); // Рисуем тень с непрозрачностью 0.3 draw_sprite(sprite_index, 0, x, y); // Рисуем сам спрайт[/gml] Чтобы полность перекрасить спрайт в цвет, отличный от чёрного - используйте функцию для создания тумана в 3D играх. Пример: [gml]d3d_set_fog(true, c_white, 0, 0); draw_sprite(sprite_index, 0, x, y); d3d_set_fog(false, c_white, 0, 0);[/gml] Ну, а если вы хотите создать полноценный эффект "Fade" - используйте dll для работы с пиксельными шейдерами в GM, где это реализуется очень легко: http://gmc.yoyogames.com/index.php?showtopic=492876 II.3.11. Как убрать курсор с помощью кода? Как изменить курсор? Как сделать свою картинку курсора? Ответ: Изменить стандартное изображение можно с помощью функции window_set_cursor(curs), в которой можно использовать следующие константы: [gml]cr_default cr_none cr_arrow cr_cross cr_beam cr_size_nesw cr_size_ns cr_size_nwse cr_size_we cr_uparrow cr_hourglass cr_drag cr_nodrop cr_hsplit cr_vsplit cr_multidrag cr_sqlwait cr_no cr_appstart cr_help cr_handpoint cr_size_all[/gml] Чтобы убрать курсор - следует выбрать константу cr_none. Чтобы показывалась картинка игрового курсора, можно использовать переменную cursor_sprite. Обратите внимание, если скорость комнаты меньше 60 - ваш собственный курсор будет немного "тормозить", потому что частота обновления экрана значительно больше 30. II.4.13. Как сделать респавн монстров через определённое время за границами комнаты в зависимости от счета игрока? Ответ: Чтобы сделать респавн монстров через определённое время можно использовать алармы. Для начала нужно в create event объекта, который будет создавать монстров написать такой код: [gml]alarm[0] = room_speed; // Монстры появятся через 1 секунду[/gml] В событии alarm 0 пишем такой код: [gml]var xx, yy; repeat score*0.5 + 10 { switch irandom(3) { case 0: xx = -32; yy = random(room_height); break; case 1: xx = room_width + 32; yy = random(room_height); break; case 2: xx = random(room_width); yy = -32; break; case 3: xx = random(room_width); yy = room_height + 32; break; } instance_create(xx, yy, o_enemy); } alarm[0] = 5 * room_speed; // Следующая волна монстров будет через пять секунд[/gml] II.4.14. Как сделать разброс пуль? Ответ: Всё очень просто, следует только использовать random_range для некоторой случайной неточности. Например, код создание пули в игроке можно составить таким образом: [gml]var bull; bull = instance_create(x, y, o_bullet); // Создаём пулю bull.direction = direction + random_range(-20, 20); // Максимальное отклонение - 20 градусов[/gml] II.4.15. Вопрос 1: Как проверить, чётное ли число? Вопрос 2: Как проверить, кратно ли одно число другому? Ответ: Если проверка value mod 2 возвращает 0 - число чётное, в другом случае - число нечётное. Пример: [gml]if value mod 2 == 0 { show_message('Число чётное.'); } else { show_message('Число нечётное.'); }[/gml] Для проверки кратности используется та же проверка, только вместо 2 - делитель. II.4.16. Как сделать бесконечную комнату? Движущуюся вниз/вверх. Ответ: Обычно эффект бесконечности достигается посредством движением фона и объектов - движется фон, а игроку кажется, что движутся объекты. Предположим, что фон двигается со скоростью -5 - каждый шаг двигается на 5 пикселей вверх. Тогда недвижимый объект на экране падает со скорость 5 пикселей, так как относительно фона каждый шаг он сдвигается на 5 пикселей вниз. Объект, который движется вверх со скоростью 5 пикселей - завис в воздухе, так как относительно фона он не сдвигается. Таким образом, создавая за нижней границей комнаты объекты и устанавливая им отрицательную вертикальную скорость - получим бесконечный поток объектов. Не стоит забывать, что все объекты нужно удалять, если они пересекли верхнюю границу комнаты. II.4.17. Как сделать, чтобы при переходе в другую комнату в текущей сохранялись все изменения? Ответ: Нужно установить persistent в настройках комнаты, вкладка settings. Так же для этого можно использовать функцию room_set_persistent и переменную room_persistent. II.4.18. Как загрузить спрайт/звук/фон из папки, как загрузить анимацию, как проверить существование файла? Ответ: Для загрузки спрайтов используются следующие функции: sprite_add (загружает новый спрайт в игру), sprite_replace (заменяет существующий спрайт), sprite_add_sprite (добавляет спрайт в формате gmspr) и sprite_replace_sprite (заменяет существующий спрайт спрайтом в формате gmspr). Аналогичные функции для загрузки фонов: background_add, background_replace, background_add_background, background_replace_background. И функции для загрузки звуков: sound_add (добавляет музыку/звук), sound_replace (заменяет музыку/звук). Чтобы сохранить анимацию в png формате - спрайт нужно сохранить как стрип: Edit Sprite -> File -> Save as PNG File (Game Maker автоматически объединит все кадры). Чтобы загрузить полученную картинку в игру - в аргументе imgnumb, функции для загрузки спрайта нужно указать кол-во кадров анимации. В редакторе изображений GM загружать стрип следует выбрав пункт "Create from Strip" в меню "File". Советую проверять на существование каждый внешний файл. Для этого используется функция file_exists. Так же обязательно убедитесь, что вы не загружаете один и тот же ресурс более одного раза, и так же примите во внимание, что загруженные ресурсы не сохраняются при вызове функции game_save. II.4.19. Как узнать путь к папке windows, appdata и т.д.? Ответ: Для этого следует использовать Переменные среды (http://ru.wikipedia.org/wiki/Переменные_среды) / Environment variables (http://en.wikipedia.org/wiki/Environment_variable). Пример: [gml]AppDataDir = environment_get_variable('AppData');[/gml] II.4.20. Вопрос 1: Как сделать, чтобы при столкновении отнимались не сразу все три жизни, а только одна? Вопрос 2: Как сделать, чтобы событие столкновения происходило через определённые промежутки времени? Ответ: Чтобы жизни отнимались не сразу все три, а только через определённые промежутки времени - достаточно установить таймер, который идёт во время столкновения и сбрасывается на 0, если столкновения нет. К примеру, можно написать такой код в step event противника:: [gml]var obj; obj = instance_place(x, y, o_player); if obj != noone // Если противник столкнулся с игроком { if alarm[0] == -1 // Если таймер не запущен { with obj hp -= 1; // Уменьшаем кол-во жизней игрока alarm[0] = 15; // Через 1/2 секунды противник сможет атаковать ещё раз. } } else { alarm[0] = -1; // Если столкновения нет - сбрасываем таймер }[/gml] alarm 0 противника: [gml]// Противник может атаковать[/gml]
Ещё один вариант - после атаки делать игрока на время бессмертным. Тогда код примет примерно такой вид: step event противника: [gml]var obj; obj = instance_place(x, y, o_player); if obj != noone { if obj.alarm[0] == -1 { with obj { hp -= 1; alarm[0] = 15; // Через 1/2 секунды игрок перестанет быть бессмертным. } } }[/gml] alarm 0 event игрока: [gml]// Игрока можно атаковать[/gml]
II.4.21. Как определить, в какой ячейке произвольной сетки расположена конкретная позиция? Ответ: Предположим, что сетка начинается с координат start_x, start_y. Ширина и высота сетки в ячейках - grid_width и grid_height соответственно. Ширина и высота ячейки в пикселях - cell_width, cell_height. Данная позиция - xx, yy. Итак, получаем такой код: [gml]if xx >= start_x and yy >= start_y and xx <= start_x + grid_width*cell_width and yy <= start_y + grid_height*cell_height { cell_x = (xx - start_x) div cell_width; cell_y = (yy - start_y) div cell_height; } else { cell_x = -1; cell_y = -1; }[/gml] К примеру, если сетка начинается в координатах 0,0 и она никак не ограничена, в том числе номера её ячеек могут принимать отрицательные значения, то поиск ячейки, на которой расположена позиция xx,yy будет выглядеть так: [gml]cell_x = xx div cell_width; cell_y = yy div cell_height;[/gml] II.4.22. Как сделать у противников разные жизни? Я пишу для одного противника health = 0, а умирают все. Ответ: health - глобальная переменная, обычно используемая для кол-ва жизней игрока. Чтобы у каждого противника были свои жизни - следует использовать локальные переменные. У каждого противника в create event нужно объявить локальную переменную hp: [gml]hp = 100; // Изначальное кол-во жизней - 100[/gml] При столкновении противника с пулей, к примеру, можно написать примерно такой код: [gml]hp -= 15; // Уменьшаем hp противника with other instance_destroy(); // Удаляем пулю if hp <= 0 // Если жизни противника меньше или равны нулю, то... { instance_destroy(); // Удаляем противника // Создаём кровь и т.д. }[/gml] Иногда hp противника уменьшается не только в событиях столкновения, но и как результат различных бонусов и т.д. Чтобы не писать код уничтожения противника во всех местах, где hp противника уменьшается - можно поставить такой код в step противника: [gml]if hp <= 0 // Если жизни противника меньше или равны нулю, то... { instance_destroy(); // Удаляем противника // Создаём кровь и т.д. }[/gml] II.4.23. Как сначала проиграть анимацию до конца, а затем запустить наоборот? Ответ: В step event объекта можно поставить приблизительно такой код: [gml]if round(image_index + image_speed) >= image_number // Если анимация дошла до конца, то... image_speed = - 1/room_speed; // Устанавливаем отрицательную скорость анимации if image_index < 0 // Если анимация в обратную сторону закончилась, то... instance_destroy(); // Удаляем объект[/gml] II.5.5. Что работает быстрее, <> или != ? Ответ: На практике разница очень мала. Тем не менее, я бы всё равно советовал вам использовать !=. II.5.6. Почему не стоит выносить действия в действиях step/draw в скрипты? Ответ: Механизм вызова скриптов в GM невероятно медленный. Допустим, у нас есть два куска кода: [gml]a = b;[/gml] И [gml]script0();[/gml] script0 такого содержания: [gml]a = b;[/gml] Первый код, повторенный 100 раз выполнялся 0.044 миллисекунды, второй (скрипт) - 0.341 миллисекунды. Первый код, повторенный 1000000 раз выполнялся 5401 миллисекунду, второй (скрипт) - 9864 миллисекунды. Очевидно, что вызов скрипта занимает довольно много времени. На деле при большом количестве использования скриптов в постоянно повторяющихся событиях, как step и draw - fps значительно проседает. Следующие вопросы были дополнены: I.1.1. Что такое Game Maker? Ответ: Game Maker — один из самых известных конструкторов игр. Это не движок. Первую версию GM Разработал Марк Овермарс в 1999 году, однако, начиная с версии 7.0 разработкой GM занимается команда YoYo Games. Официальный сайт конструктора на данный момент - yoyogames.com (http://www.yoyogames.com). Скачать Game Maker для Windows и Mac можно здесь: http://www.yoyogames.com/gamemaker/try II.1.1. Как ограничить значение переменной? Ответ: Первый способ: [gml]variable += x; if variable > variable_max // Если переменная больше указанного значения, то... variable = variable_max; // Устанавливаем переменной максимальное значение variable -= x; if variable < variable_min variable = variable_min;[/gml] Второй способ: [gml]variable = min(variable_min + x, variable_max); variable = max(variable_min - x, variable_min);[/gml] Третий способ: [gml]variable = median(variable_min, variable, variable_max); // Находим среднее из значений[/gml]
II.1.2. Мне нужно написать текст с указанием значения переменной, как? Ответ: Пропишите отдельному объекту в событие draw, такой код: [gml]draw_text (x, y, ' Текст до переменной ' + string(переменная) + ' Текст после');[/gml] Не забудьте, что переменная может быть названа только на английском языке, без пробелов и начинаться она должна с буквы. Так же, если переменная всегда хранит текстовое значение - её не обязательно заносить в string(). II.2.6. Почему быстрые пули могут пролетать через стенку? Ответ: Для начала, нужно понять, почему это происходит. Дело в том, что за один шаг пуля мгновенно перемещается на некоторое расстояние, хотя столкновение проверяется только в новой позиции - при большой скорости пуля может запросто "перескачить" стенку. Как вариант, можно использовать такой код в step пули: [gml]var i; for (i = sprite_width; i <= speed; i += sprite_width) { if place_meeting(x + lengthdir_x(i,direction), y + lengthdir_y(i,direction), o_wall) // Если в этой позиции есть стена, то... { x += lengthdir_x(i, direction); // Двигаемся к позиции столкновения y += lengthdir_y(i, direction); event_perform(ev_collision, o_wall); // Вызываем событие столкновения со стеной } }[/gml] II.3.5. Как сделать, чтобы когда герой был ниже дерева - он был над ним, а когда выше - за ним? Какую нужно использовать формулу, чтобы вычислить глубину объекта в изометрии или в играх с видом как в классических jrpg? Ответ: Для игр с видом как в классических jrpg обычно используется формула depth = -y; при условии, что центр спрайта находится в точке столкновения объекта с землёй, а не в (0,0). Эту код нужно поставить в create event статических объектов, и step event динамических. Чем ниже объект, тем меньше его глубина, тем выше он рисуется. Для изометрии можно использовать формулу depth = -(y - sprite_yoffset + (sprite_height + H) / 2), где H - высота объекта над уровнем земли. Если у одного и того же спрайта высота точек спрайта над уровнем земли разная - нужно использовать буфер глубины, то есть - 3D технологии. И, были добавлены следующие примеры: Платформеры:- motion in platformer.gmk (10.6) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3033) - базовый пример двжения в платформере
- rough surface.gmk (13.5 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3036) - пример движения по неровной поверхности
- stairs.gmk (12.2 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3035) - пример лесниц. Автор: Лер
Другое:- momemtary bullets.gmk (11.6 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3034) - пример мгновенных пуль, собственных жизней у противников и хелсбаров
- healthbar and gradual turn.gmk (14.4 кб) (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=3032) - пример спрайтового хелбара и плавного поворота
Название: Re: FAQ для начинающих
Отправлено: Romixal от Январь 10, 2011, 03:38:28
Отлично ;) , прадва лучше для разделов сделать спойлеры, а то слишком громозко.
Название: Re: FAQ для начинающих
Отправлено: Vendet от Январь 10, 2011, 03:41:17
Просто суперская подборка на самые популярные вопросы, новичкам в первую очередь стоит читать эту тему! sm:) Так ка из этих вопросов можно узнать ответы на простые вопросы, или те которые уже повторялись / обсуждались много раз! DeatHSoul молодец, такую огромную работу проделал sm_respekt Ну и так же всем благодарности, кто ему помогал ;)
Название: Re: FAQ для начинающих
Отправлено: Romixal от Январь 10, 2011, 03:43:15
Плюсанул sm_respekt
Название: Re: FAQ для начинающих
Отправлено: Vendet от Январь 10, 2011, 03:46:19
Отлично ;) , прадва лучше для разделов сделать спойлеры, а то слишком громозко.
Тогда вообще читать не будут новички, просто так хоть и громоздко, зато сразу видно вопрос. Дело ваше) sm_epik
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Январь 10, 2011, 04:12:34
Спасибо sm_milo Сейчас попробовал писать вопросы в именах спойлера - намного лучше. Но, нужно увеличить размер текста, маловат как-то. Для теста: I - ТЕОРИЯ 1) СтартОтвет: Game Maker — один из самых известных конструкторов игр. Это не движок. Первую версию GM Разработал Марк Овермарс в 1999 году, однако, начиная с версии 7.0 разработкой GM занимается команда YoYo Games. Официальный сайт конструктора на данный момент - yoyogames.com (http://www.yoyogames.com). Скачать Game Maker для Windows и Mac можно здесь: http://www.yoyogames.com/gamemaker/try Ответ: Game Maker Language (GML) — это интерпретируемый язык программирования, встроенный в Game Maker. Он предлагает значительно большую функциональность, чем встроенные действия lib библиотек GM. Ответ: На данный момент, последняя версия GM - 8.0 Ответ: На данный момент существует версия Game Maker для Windows и Mac (http://www.yoyogames.com/gamemaker/try). У YoYo Games так же имеется конвертер для портирования GM игр на PSP и iOS (iPhone, iPod, iPad). В планах у YoYo Games так же добавить поддержку Android и Windows 7 Mobile. Ответ:Game Maker предоставляется в двух версиях, Lite Edition (облегченная редакция) и Pro Edition (профессиональная редакция). Lite Edition подходит для тех, кто только делает первые шаги в разработке игр. Она совершенно бесплатна, но имеет ограниченную функциональность. Также при запуске игр показывается логотип, а при использовании программы будет постоянно выходить напоминание о возможности обновления. Если Вы собираетесь пользоваться Game Maker регулярно, Вам настойчиво рекомендуется обновить программу до Pro Edition. В Pro Edition значительно расширена функциональность и не показываются логотипы и сообщения. Конкретно в Pro Edition доступны следующие возможности: - Не показывается логотип Game Maker при запуске игр.
- Не показываются всплывающие сообщения о возможности обновления.
- Возможность отрисовывать повернутые, окрашенные и прозрачные спрайты.
- Дополнительные опции в редакторах спрайтов и изображений.
- Дополнительные действия, такие как проигрывание CD музыки, рисование повернутого текста и окрашенных форм.
- Использование звуковых эффектов и позиционирования источников звука.
- Использование загрузочных экранов с фильмами, изображениями, веб страницами, текстом и т. д.
- Система частиц для эффектов взрыва, салюта, пламени, снега, дождя и других.
- Дополнительные продвинутые функции рисования, например, для отрисовки окрашенного текста и текстурированных полигонов.
- Возможность создание 3D игр, при использовании функций для 3D графики.
- Возможность создания многопользовательских проектов для игры через интернет или локальную сеть.
- Возможность задавать свои собственные эффекты перехода между комнат.
- Вы можете использовать функции для создания, загрузки и изменения ресурсов (спрайтов, фонов и т.д.) "на лету", прямо во время игры.
- Доступны функции для работы с различными структурами данных.
- Функции для планирования движения.
- Возможность вложения файлов в исполняемые файлы игр, которые можно использовать во время запуска игр.
- Функциональные возможности можно улучшать пакетами расширений. Их может сделать любой человек и распространять, как правило, совершенно бесплатно.
- Три таких пакета расширения уже включены в дистрибутив, они добавляют новые эффекты перехода между комнатами, диалоги windows и функции для принтера.
- Вы можете определять свои собственные события триггера.
- Вы можете импортировать и экспортировать ресурсы, что поможет Вам легко совмещать ваши проекты.
Обновление с версии Lite Edition до Pro Edition стоит 20 Евро или US $25. Этот взнос делается один раз и будет действительным, как минимум, для всех версий Game Maker 8.x. Ответ: Да. Достаточно посмотреть коснтруктор игр Noobster (http://game-maker.ru/infusions/pro_download_panel/download.php?did=927), HTML редактор HyperPage (http://www.yoyogames.com/games/71096-hyperpage), браузер GMB (http://www.yoyogames.com/games/122183), музыкальный проигрыватель visual music (http://www.game-maker.ru/infusions/pro_download_panel/download.php?did=351) и торрент-клиент GMTorrent (http://gmc.yoyogames.com/index.php?showtopic=482966). Ответ: Безусловно. Взгляните на гоночные симуляторы SWERVE (http://www.yoyogames.com/games/113439-swerve) и Park Racer Game (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1038), gta-подобные игры Total Anarchy (http://gmc.yoyogames.com/index.php?showtopic=467300) и Crimelife 3 (http://gmc.yoyogames.com/index.php?showtopic=393243), онлайн шутер Metroid online (http://game-maker.ru/infusions/pro_download_panel/download.php?did=850), оффлайн шутер Ice Arena 3d (http://www.yoyogames.com/games/20640-ice-arena-3d), клон портала - Power Gates (http://www.yoyogames.com/games/20333-power-gates), авиасимулятор Aces High Over verlor Island (http://www.yoyogames.com/games/105-aces-high-over-verlor-island) и вестерн Guns and Spurs (http://www.yoyogames.com/games/126583-guns-and-spurs)! Ответ: Да. Можете сыграть в Arcane Adventures (http://gmc.yoyogames.com/index.php?showtopic=462962), Almora Online (http://gmc.yoyogames.com/index.php?showtopic=312634) и Gang Garrison 2 (http://www.yoyogames.com/games/149093-gang-garrison-2). Ответ: Вы можете скачать его здесь: http://gmakers.ru/index.php?action=tpmod;dl=get220 Или прочитать онлайн здесь: http://gmakers.ru/gamemaker_help/
P.S: Если ещё убрать картинку кнопки - выйдет именно то, о чём я говорил в чате ) Но, может её и не стоит убирать - нужно глянуть и так и так, выбрать что лучше. P.P.S: Я таки занёс разделы в спойлеры, так действительно легче ориентироваться в faq. P.P.P.S: Почему-то второе сообщение темы обрезается до 56391 символа... Может разное ограничение для первого сообщения темы, и для ответов? :errm:
Название: Re: FAQ для начинающих
Отправлено: NinjaCat от Январь 10, 2011, 06:05:38
Когда в первый раз тему прочитал и сохранил фак, не стал ничего писать тут, думал нельзя. А теперь вот выражаю большую благодарность. Мне, как человеку, до которого код не доходит даже при самом подробном изучении очень полезно иметь такую справку. Снова все сохранил. И sm_respekt поставил!
Название: Re: FAQ для начинающих
Отправлено: Vendet от Январь 10, 2011, 13:45:38
Кнопки лучше, особенно если в них написан текст. Можно было бы сделать чтобы текст был больше или лучше читабилен в кнопке спойлера, но вот только я не помню куда проинсталировалась установка мода, в какие файлы. А вот цвет кнопки можно сменить) PS: Текст у спойлера вроде большой
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Январь 13, 2011, 00:14:22
Занёс вопросы под спойлеры и исправил одну опечатку. Но, мне кажется, нужно что-то убрать: Либо надпись "(кликните для показа/скрытия)", либо "Спойлер:". Предполагаю, если убрать первое - faq станет выглядеть значительно лучше. Категории раздела "Теория" выглядят замечательно, а вот в остальных, с моим расширением - текст "(кликните для показа/скрытия)" переносится на вторую строку. P.S: чтобы не убивать кучу времени на занесение вопросов в спойлеры - я написал код на GML, который проделывает всю работу за меня. Кому интересно: dll39_buffer_create(); dll39_buffer_clear(0); dll39_buffer_clear(1);
var file, size; file = dll39_file_open('H:\faq.txt', 0); size = dll39_file_size(file); dll39_file_read(file, size, 0); dll39_file_close(file);
var str_q, str_name, str_spoiler, char, pos, i, bvl, svl;
while dll39_get_pos(true, 0) < size { str_q = ''; str_name = ''; str_spoiler = ''; do { char = dll39_read_byte(0); str_q += chr(char); } until char = 10 or dll39_get_pos(true, 0) >= size bvl = string_pos('[b]I', str_q) = 1 if bvl = 0 svl = string_pos('[spoiler][b]I', str_q) = 1 else svl = 0 if bvl or svl { // Читаем следующую строку - сроку спойлера do { char = dll39_read_byte(0); str_spoiler += chr(char); } until char = 10 or dll39_get_pos(true, 0) >= size if string_pos('spoiler', str_spoiler) = 0 { dll39_write_chars(str_q, 1); dll39_write_chars(str_spoiler, 1); continue; } if svl = 1 str_q = string_copy(str_q, 10, string_length(str_q) - 2); // Генерируем имя вопроса после спойлера str_name = string_replace_all(str_q, '[b]', ''); str_name = string_replace_all(str_name, '[/b]', ''); repeat 2 str_name = string_delete(str_name, 1, string_pos('.', str_name)); pos = string_pos('.', str_name); str_name = string_delete(str_name, pos, 1); str_name = string_insert(')', str_name, pos); str_name = string_copy(str_name, 1, string_length(str_name) - 2); if svl = 0 dll39_write_chars('[spoiler=' + str_name + ']' + str_q + string_copy(str_spoiler, 10, string_length(str_spoiler)), 1); else dll39_write_chars('[spoiler][spoiler=' + str_name + ']' + str_q + string_copy(str_spoiler, 10, string_length(str_spoiler)), 1); } else { dll39_write_chars(str_q, 1); } }
if file_exists('H:\faq2.txt') file_delete('H:\faq2.txt');
file = dll39_file_open('H:\faq2.txt', 1); dll39_file_write(file, 1); dll39_file_close(file);
game_end(); P.P.S: Vendet, второе сообщение почему-то постоянно обрезается до 56к. В чём причина?
Название: Re: FAQ для начинающих
Отправлено: Vendet от Январь 13, 2011, 10:02:42
Над спойлером поработаю если найду где он. P.P.S: Vendet, второе сообщение почему-то постоянно обрезается до 56к. В чём причина?
Хотел бы я знать. Секреты SMF я еще не все знаю. Возможно Лимит Базы Данных, ведь сообщения хранятся в ней. Добавлено: Февраль 09, 2011, 21:48:33 Ого, отлично, видимо тема хорошая что аж прочитана 1510 раз ;)
Название: Re: FAQ для начинающих
Отправлено: VeGaS от Февраль 10, 2011, 05:16:42
Ого, отлично, видимо тема хорошая что аж прочитана 1510 раз ;)
sm_hzx sm_hzx sm_hzx
Название: Re: FAQ для начинающих
Отправлено: De_Joker от Февраль 20, 2011, 23:57:20
Нашёл ошибку. Лишняя скобка и не хватает запятой. Выделил красным. II.6.2. Как сделать, чтобы зомби двигался за игроком или союзным персонажем обходя препятствия? Ответ: Для начала нужно проверить, есть ли в комнате хотя бы один союзный юнит. Для этого всем союзным юнитам и игроку в том числе устанавливаем родителем объект o_friend (parent). После этого, находим ближайшего из юнитов и, если он находится в радиусе видимости, двигаемся к нему. Код:
if instance_exists(o_friend) // Если существует хотя бы один экземпляр объекта o_friend (или дочерного объекта), то... { var obj, dis; obj = instance_nearest(x, y, o_friend)); // Определяем ближайшего юнита dis = point_distance(x, y, obj.x, obj.y); // Определяем расстояние к нему if dis < 300 and dis > 16 // Если он в пределах видимости { mp_potential_step(obj.x, obj.y, spd, 0); // Двигаемся к нему со скоростью spd, обходя все твёрдые объекты } }
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Февраль 21, 2011, 02:56:00
Отлично, спасибо sm_milo
Название: Re: FAQ для начинающих
Отправлено: Fantom от Март 28, 2011, 20:47:49
"Просканировал" все пункты, обнаружил крупные недопечатки (видимо, связанные с обработкой текста) в пунктах II.1.7, II.4.13, и мелкие в II.4.23, II.4.20, II.4.14, II.3.10, II.3.9, II.3.6, II.2.9, II.1.1.
Название: Re: FAQ для начинающих
Отправлено: DeatHSoul от Апрель 01, 2011, 02:24:27
Ок, спасибо, я разберусь в чём причина на днях. sm_epik
Так, вроде бы всё поправил. Код теперь отображается нормально.
Название: Re: FAQ для начинающих
Отправлено: Demvi007 от Апрель 11, 2011, 17:55:52
У меня почемуто по ссылке "momemtary bullets.gmk (11.6 кб)" предлагает сохранить фаил в формаие htm...Так у всех или я что то не так делаю?...
Название: Re: FAQ для начинающих
Отправлено: MegaDimon от Апрель 11, 2011, 18:45:53
если у тебя опера то это баг,я на опере я просто переменовую.
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Апрель 26, 2011, 00:10:38
Привет всем! ^_^ Сегодня состоялось очередное обновление FAQ. Был добавлен только один новый вопрос, добавлено два, которые ранее были в составе третьего, и, что главное, исправлено двадцать три вопроса. Это обновление и так небольшое, а с этого дня обновления будут содержать в себе всего 2-3 новых вопроса. Статьи, которые я обещал написать, я до сих пор не начал писать, и вряд ли они появятся в скором времени. Но появятся обязательно, я не вхожу в число людей, которые не могут держать свое слово. С каждым обновлением будет поставляться подробная информация обо всех изменениях и нововведениях в FAQ, и это обновление - не исключение. Далее вы можете видеть подробный список всех исправленных / дополненных / переписанных вопросов: Обновлён. I.1.3. Какая последняя версия Game Maker? Ответ: На данный момент, последняя версия GM - 8.1. Впрочем, постоянно выходят обновления, исправляющие баги текущей версии и добавляющие новые возможности. Обновлён. I.1.4. На каких платформах работают GM-игры? Ответ: На данный момент существует версия Game Maker для Windows и Mac (http://www.yoyogames.com/gamemaker/try). У YoYo Games так же имеется конвертер для портирования GM игр на PSP, iOS (iPhone, iPad), Android и HTML5. Так же, в планах у YoYo Games выпустить продукт под названием "GameMaker Studio", некую особую версию GameMaker, включающую возможность портирования игр на различные платформы. Обновлён и дополнен. I.1.5. Что такое Pro и Lite версии Game Maker? Какая стоимость Game Maker? Ответ: Начиная с GameMaker версии 8.1, обычная Pro версия стала называться Standart (а Lite сохранила свое название). До первого июня 2011 года GameMaker Standart можно купить за $25, однако после этого стоимость GameMaker повыситься до $39.99. Покупка GameMaker 8.x будет действительна для всех версий 8.х Информация из русифицированного справочного руководства к Game Maker 8.0 (http://gmakers.ru/gamemaker_help/): Game Maker предоставляется в двух версиях, Lite Edition (облегченная редакция) и Pro Edition (профессиональная редакция). Lite Edition подходит для тех, кто только делает первые шаги в разработке игр. Она совершенно бесплатна, но имеет ограниченную функциональность. Также при запуске игр показывается логотип, а при использовании программы будет постоянно выходить напоминание о возможности обновления. Если Вы собираетесь пользоваться Game Maker регулярно, Вам настойчиво рекомендуется обновить программу до Pro Edition. В Pro Edition значительно расширена функциональность и не показываются логотипы и сообщения. Конкретно в Pro Edition доступны следующие возможности: - Не показывается логотип Game Maker при запуске игр.
- Не показываются всплывающие сообщения о возможности обновления.
- Возможность отрисовывать повернутые, окрашенные и прозрачные спрайты.
- Дополнительные опции в редакторах спрайтов и изображений.
- Дополнительные действия, такие как проигрывание CD музыки, рисование повернутого текста и окрашенных форм.
- Использование звуковых эффектов и позиционирования источников звука.
- Использование загрузочных экранов с фильмами, изображениями, веб страницами, текстом и т. д.
- Система частиц для эффектов взрыва, салюта, пламени, снега, дождя и других.
- Дополнительные продвинутые функции рисования, например, для отрисовки окрашенного текста и текстурированных полигонов.
- Возможность создание 3D игр, при использовании функций для 3D графики.
- Возможность создания многопользовательских проектов для игры через интернет или локальную сеть.
- Возможность задавать свои собственные эффекты перехода между комнат.
- Вы можете использовать функции для создания, загрузки и изменения ресурсов (спрайтов, фонов и т.д.) "на лету", прямо во время игры.
- Доступны функции для работы с различными структурами данных.
- Функции для планирования движения.
- Возможность вложения файлов в исполняемые файлы игр, которые можно использовать во время запуска игр.
- Функциональные возможности можно улучшать пакетами расширений. Их может сделать любой человек и распространять, как правило, совершенно бесплатно.
- Три таких пакета расширения уже включены в дистрибутив, они добавляют новые эффекты перехода между комнатами, диалоги windows и функции для принтера.
- Вы можете определять свои собственные события триггера.
- Вы можете импортировать и экспортировать ресурсы, что поможет Вам легко совмещать ваши проекты.
Обновление с версии Lite Edition до Pro Edition стоит 20 Евро или US $25. Этот взнос делается один раз и будет действительным, как минимум, для всех версий Game Maker 8.x. Информация из официального справочного руководства к Game Maker 8.1.69:
GameMaker comes in two editions, the Lite Edition and Standard Edition. The Lite Edition is meant for those that take their first steps on the path of developing games. It can be used for free but is limited in its functionality. Also it shows a popup logo when running games and will regularly remind you of upgrading the program. When you are using GameMaker regularly you are strongly recommended to upgrade from the Lite Edition. Standard Edition contains considerably more functionality and does not display any logos or popup messages. More precisely, Standard Edition has the following additional functionality: - No GameMaker logo is shown when running a game.
- No GameMaker TV logo in the corner of a game.
- No GameMaker advert screen on exit.
- No regular popups remind you of upgrading.
- You can use color blended sprites, which can be used for many special effects and easy shadows.
- There are additional options in the sprite and image editors.
- There are additional actions for e.g. CD music, rotated text, and colorized shapes.
- You can use special sound effects and positional sound.
- You can create splash screens with movies, images, webpages, texts, etc.
- There is a particle system to create explosions, fireworks, flames, rain, and other effects.
- A number of advanced drawing functions are available, for example colorized text and textured polygons.
- It is possible to create 3D games using functions for 3D graphics.
- It is possible to create multiplayer games that can be played over a network.
- You can define your own room transitions.
- You can use functions to create, load, and modify resources (sprites, backgrounds, etc.) while the game is running.
- There is a collection of functions to create and use data structures.
- There are functions for motion planning.
- You get the possibility to include additional files in the game executables that can be used when the game is run.
- Standard Edition can be easily extended using extension package. These can be made by everybody and will in general be provided free of
- charge.
- Three such extension packages are included adding many room transitions, windows dialogs, and printing facilities.
- You can define your own trigger events.
- You can export and import resources, which makes it easier to collaborate on games.
Upgrading from Lite Edition costs only $39.99 (subject to change). This is a one-time fee that will be valid for all versions 8.x of GameMaker. When you are running the Lite Edition, you can upgrade by going to the Help menu, and selecting Upgrade from Lite Edition. If you purchased GameMaker before (and hence, have an license key), you can go to the Help menu, and pick Enter License Key. Once you have entered a valid, your copy of GameMaker will be upgraded. You must be connected to the internet for the upgrade to work. While GameMaker itself does not require an internet connection, it will require occasional access to maintain the license. If you can not connect your computer to the internet, you can download the license check file from YoYo Games website, and point the auto update system to it. if you fail to provide a valid file, or an internet connection when requested, your copy of GameMaker will be downgraded to Lite until such time as you do. Слегка исправлен. I.2.1. У меня появились / я скачал файлы с расширением *.gb1 - *.gb9. Что это? Ответ: Это бэкап-файлы (http://ru.wikipedia.org/wiki/Резервное_копирование) игр, сделанных на GM. Каждый раз когда вы сохраняетесь - бэкап файлы обновляются. В случае, если сохранили игру с критической ошибкой - вы можете удалить текущий исходник и работать с бэкап файлом. Для этого просто откройте его с помощью GM (ПКМ -> Открыть с помощью -> Game Maker 8). Выбрав пункт Preferences в меню File - вы увидите окно настроек GM, где во вкладке General вы можете либо вовсе отключить создание бэкапов, убрав флажок с "Keep backup copies of files", либо изменить их количество, изменив значение "Maximum number of backups". Дополнен. I.2.2. Текст в редакторе кода стал меньше / больше. Как восстановить нормальный размер? Ответ: Используйте функциональные клавиши F7 и F8 (только для Game Maker 8). Дополнен. I.2.3. Меню-помощи в редакторе кода перестало появляться. Что делать? Ответ: Нажмите F11 (только для Game Maker 8). Слегка исправлен и дополнен. I.2.7. Как использовать функции пакета расширения? Ответ: Перед тем как добавить пакет расширения в ваш проект - вам нужно установить его в Game Maker. Выберете из меню Resources пункт Select Extension Packages (Shift+Ctrl+E). Перед вами появится окно, в котором вы можете добавить какой-то пакет расширения в вашу игру или просмотреть информацию о нём / прочитать справочное руководство. Жмите кнопку "Install". В открывшемся окне вы можете удалить из Game Maker выбранный пакет расширения, нажав кнопку "Uninstall" и установить новый, нажав кнопку "Install" и выбрав *.gex файл. После установки пакетов расширений вы можете добавить какие-то из них себе в проект. Для этого вернитесь в первое окно (нажмите "OK"), выберите имя пакета в списке справа, и нажмите на появившуюся кнопку между списками. Убрать пакет расширения из вашего проекта вы можете аналогичным образом. Функции пакетов расширений в данном проекте можно посмотреть, выбрав из меню Scripts пункт Show Extension functions. Подробнее здесь: http://gmakers.ru/gamemaker_help/source/files/215_00_extensions.php Переписан. I.3.1: Что такое шаг, что такое скорость комнаты? Ответ: В Game Maker за секунду проходит определённое количество шагов. Это количество определяет переменная room_speed (её можно задать в свойствах комнаты: settings -> Speed). Событие step event называется событием шага именно потому, что оно выполняется каждый шаг. К примеру, если в событии step event объекта вы напишете код "score += 1", и установите скорость комнаты на 30 шагов, то за секунду переменная score увеличится на 30. Таким же образом, если вы напишите "image_speed = 1", то за секунду у спрайта сменится 30 кадров, потому что переменная image_speed хранит в себе значение, на которое изменяется кадр спрайта каждый шаг. То же относится и ко времени. Если вы напишете "alarm[0] = 1", то событие таймера произойдёт через 1/30 секунды (для общего случая - 1/room_speed). Переписан. II.1.1. Как ограничить значение переменной? Ответ: Для начала, следует учесть, что вы можете получить небольшой, но всё же выигрыш в производительности, проверяя значение переменной исключительно фактически после её изменения. То есть, если жизни игрока уменьшаются при столкновении с монстром и с огнём - немного производительней будет поставить две проверки в эти события, чем писать одну в step event, которая будет выполнятся каждый шаг. Однако, не стоит злоупотреблять этим в ущерб сопровождаемости кода. К примеру, если вам понадобится как-то изменить событие смерти игрока - вам придётся менять его в двух событиях (в лучшем случае), а не в одном (в случае со step event). Чтобы этого не происходило, лучше выносите повторяющиеся куски кода в скрипты или user events. Последние можно выполнить с помощью команды event_user(номер_события). Итак, при увеличении или уменьшении вы можете использовать такие простые проверки: variable += x; if variable > variable_max // Если переменная больше указанного значения, то... variable = variable_max; // Устанавливаем переменной максимальное значение variable -= x; if variable < variable_min variable = variable_min; Слегка понизив читабельность можно добится большей компактности кода, используя функции min и max: variable = min(variable + x, variable_max); // Если variable_min + x больше variable_max - выбираем меньшее, то есть, variable_max. variable = max(variable - x, variable_min); Часто в различных примерах вы можете встретить такую запись: variable = max(variable_min, min(variable, variable_max)); Однако, есть способ лучше, который я и предпочитаю использовать: variable = median(variable_min, variable, variable_max); // Находим среднее из значений, если variable < variable_min - средним становится variable_min и аналогично для variable_max. Например, если вы хотите ограничить передвижение игрока некоторыми рамками, скажем, сделать, чтобы он не выходил за границы комнаты - вы можете написать так: x = median(0, x, room_width - sprite_width); y = median(0, y, room_height - sprite_height); Переписан. II.1.4. Как запросить имя игрока, и в последствии использовать его в сообщениях и диалогах? Ответ: Запросить имя можно таким образом: global.Hero_name = get_string('Как вас зовут?', 'DeatHSoul'); После этого введённое имя игроком будет хранится в глобальной переменной Hero_name, которая будет сохранять свое значение во всех комнатах, и вы можете использовать её, чтобы получить имя игрока. Например, так: show_message('Привет ' + global.Hero_name + '!'); Дополнен. II.1.6. Как повернуть комнату? Ответ: Используйте view_angle[0..7], и убедитесь, что у вас включен указанный вид. Если вы хотите, чтобы вид поворачивался вместе с игроком - учтите, что его нужно поворачивать в противоположную сторону. Вместо: view_angle[0] = direction; пишите: view_angle[0] = -direction; Исправлен. II.1.10. Как сделать простую паузу одной кнопкой? Ответ: Один из самых простых алгоритмов состоит в использовании функции keyboard_wait (код нужно вставить в событие нажатия соответствующей клавиши): /// Отрисовка сообщения о паузе игры draw_set_color(c_black); draw_set_alpha(0.3); draw_rectangle(0, 0, view_wview, view_hview, 0); // Отрисовка фона. Если у вас не используются виды - замените view_wview и view_hview на room_width и room_height соответственно. draw_set_alpha(1); draw_set_halign(fa_center); draw_set_valign(fa_middle); draw_text(view_xview + view_wview/2, view_yview + view_hview/2, 'PAUSE'); // Отрисовка текста. Если у вас не рисует русский текст - посмотрите вопрос II.4.6.
// Обновляем экран screen_refresh(); // Эта функция в действительности отображает на экране всё то, что мы нарисовали ранее
// Останавливаем игру до нажатия какой-либо клавиши keyboard_wait(); Если вы хотите, чтобы игра продолжалась только при нажатии какой-то конкретной клавиши, к примеру, клавиши P (или, скажем, клике мыши) - замените последнюю строку скрипта (keyboard_wait()) на: io_clear(); // Очищаем состояние клавиатуры
while true // Запускаем вечный цикл { if keyboard_check_pressed(ord('P')) break; // Если игрок нажал Р - выходим из цикла keyboard_wait(); // Ожидаем нажатия какой-нибудь клавиши }
io_clear(); // Снова очищаем состояние клавиатуры, чтобы пауза не влючилась сразу же после выключения Переписан. II.2.4. Как сделать разгон для машины, как сделать чтобы игрок постепенно разгонялся и тормозил? Ответ: На самом деле, на разгон и торможение машины влияет масса показателей. Для общего случая - нужно задать скорость разгона, силу торможения, силу трения и максимальную скорость движения (это касается любого абстрактного игрока, как машини так и реального героя). Простая схема механизма разгона / торможения для машины будет выглядеть примерно так: if keyboard_check(vk_up) { скорость += скорость_разгона; // Увеличиваем скорость машины. } else if keyboard_check(vk_down) { скорость -= сила_торможения; // Уменьшаем её скорость. } else { скорость -= сила_трения; }
скорость = median(0, скорость, максимальная_скорость); // Ограничиваем скорость, чтобы она не могла быть отрицательной и не превышала максимальный порог. Управление игроком в плафтормере будет выглядеть несколько иначе, хотя и сохраняет основную схему: // В платформере скорость может принимать отрицательное значение - движение влево (соответственно положительное - движение вправо). if keyboard_check(vk_left) spd = median(-speed_max, spd - 0.5 , speed_max); else if keyboard_check(vk_right) spd = median(-speed_max, spd + 0.5 , speed_max); else spd = max(abs(spd) - 0.2, 0) * sign(spd); // Короткая запись довольно большого куска кода. Если вы не можете понять его значение - вы можете увидеть расшифровку чуть ниже.
if place_free(x + spd, y) // Если ничто не преграждает путь игроку { x += spd; // Двигаем игрока } else { var dir; if spd > 0 // Самый простой код, позволяющий определить направление движения. dir = 0; else dir = 180; move_contact_solid(dir, speed_max); // Пододвигаем игрока вплотную к стене. spd = 0; // Обнуляем скорость. } speed_max в этом коде - максимальная скорость игрока по горизонтали. spd - текущая скорость игрока. Эта строка: spd = max(abs(spd) - 0.2, 0) * sign(spd); Скрывает в себе весь этот код: if spd > 0 { spd -= 0.2; if spd < 0 spd = 0; } else { spd += 0.2; if spd > 0 spd = 0; } То есть, она уменьшает скорость передвижения героя, сохраняя направление (знак числа). Исправлена картинка. II.2.10. Как сделать движение по неровной поверхности в платформере? Ответ: Здесь тоже нет ничего сложного. Проблема в том, что иногда игроку может препятствовать всего один пиксель, и чтобы на него взобраться - приходится прыгать. Потому, нужно создать некоторую имитацию "ног человека" - за один шаг игрок может взобраться на несколько пикселей, без прыжка. Итак, сначала задаётся максимальная высота, на которую может взобраться игрок - обычно 4-8 пикселей, во время движения в цикле проверяется сначала позиция прямо возле игрока, потом на один пиксель выше, на два пикселя выше, и так до максимальной высоты, на которую может взобраться игрок за один шаг. Эта картинка наглядно демонстрирует метод: http://savepic.net/1109905.jpg В коде это будет выглядеть примерно так: step event: var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. { if place_free(x - spd, y - i) // Если данная позиция свободна, то... { x -= spd; // Двигаем игрока y -= i; break; // Завершаем цикл } } }
//... Где vdis_max - максимальная высота, на которую может взобраться игрок за один шаг, spd - скорость передвижения игрока. В случае, если нужно реализовать ещё и быстрый спуск по ступенькам вниз - код будет выглядеть примерно так: var i; if keyboard_check(vk_left) // Если игрок нажал стрелку влево { for (i = 0; i < vdis_max; i += 1) // В цикле проверяем все позиции: с высотой как у игрока, на 1 пиксель выше, на 2 и т.д. if place_free(x - spd, y - i) // Если данная позиция свободна { x -= spd; // Двигаем игрока y -= i; if place_free(x, y + 1) // Если игрок не стоит на платформе, if !place_free(x, y + vdis_max2 + 1) // Но она под ним есть! for (i = 0; i < vdis_max2 + 1; i += 1) // Проверяем все позиции немного ниже его { if !place_free(x, y + i) // Если в данная позиция занята твёрдым объектом { y += i - 1; // Двигаем игрока вплотную к этому объекту break; // Завершаем цикл } } break; // Завершаем цикл } } Собственно, эти циклы - самописные аналоги функций move_outside_solid и move_contact_solid. При желании их можно заменить встроенными функциями. Слегка исправлен. II.2.16. Как сделать, чтобы герой в игре жанра "лабиринт" (в игре с видом сверху) мог толкать ящики? Ответ: Реализация возможности двигать ящики зависит от того, как реализовано управление игроком. Если он двигается за счёт speed и direction, можно поставить такой код в событие столкновения ящика с игроком: if place_free(x + lengthdir_x(other.speed, other.direction), y + lengthdir_y(other.speed, other.direction)) // Если ящик можно сдвинуть (позиция свободна) { x += lengthdir_x(other.speed, other.direction); // Двигаем ящик по направлению движения игрока y += lengthdir_y(other.speed, other.direction); } else // Если ящик нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию, чтобы он не застрял в ящике { x = xprevious; y = yprevious; speed = 0; } } Если игрок двигается за счёт vspeed и hspeed, можно использовать такой код (практически аналогичный предыдущему): if place_free(x + other.hspeed, y + other.vspeed) { x += other.hspeed; y += other.vspeed; } else { with other { x = xprevious; y = yprevious; vspeed = 0; hspeed = 0; } } В случае, если игрок двигается непосредственно через x и y - можно использовать такой код: var dx, dy; // Объявляем временные переменные dx = other.x - other.xprevious; // Вычисляем dy = other.y - other.yprevious;
if place_free(x + dx, y + dy) // Если ящик можно сдвинуть { x += dx; // Двигаем ящик по направлению движения игрока y += dy; } else // Если ящик нельзя сдвинуть { with other // Возвращаем игрока на предыдущую позицию { x = xprevious; y = yprevious; } } Можно усовершенствовать код, используя функцию move_contact_solid, для того, чтобы придвинуть игрока к ящику. Ещё можно вычислять скорость игрока и сдвигать ящик на вдвое меньшее расстояние, чтобы создать эффект тяжести. Переписан (дополнен). II.4.4. Как определить наивысший объект под мышкой? Ответ: Скрипт опеределения наивысшего объекта в конкретной позиции выглядит так: /*************************************************** Скрипт определяет наивысший экземпляр объекта в указанной позиции. Возвращает id экземпляра объекта, если он существует, в противном случае - noone. argument0 - x; argument1 - y; argument2 - объект; ***************************************************/ var high_object; high_object = noone; with argument2 // Обращаемся ко всем экземплярам объекта { if position_meeting(argument0, argument1, id) // Если объект находится в нужной позиции, то... { if other.high_object = noone // Если мы ещё не выбрали ни один объект, то... { other.high_object = id; // Запоминаем текущий объект. } else { if depth < other.high_object.depth // Если текущий объект выше чем выбранный, то... { other.high_object = id; // Запоминаем объект. } } } }
return high_object; // Возвращаем id найденного объекта. В этом скрипте идёт обращение ко всем экземплярам искомого объекта. Вначале каждый из них проверяется на столкновение с указанной позицией, то есть, проверяется, находится ли он в ней. Если да, тогда его глубина сравнивается с глубиной записанного объекта (тут и далее подразумевается экземпляр объекта). Если его глубина меньше - этот объект заменяет ранее записанный. Конечно, если ни один объект ещё не был записан - глубина не проверяется, а объект сразу записавается. Скачать пример. (http://forum.hellroom.ru/index.php?action=dlattach;topic=2035.0;attach=2032) Переписан. II.4.6. Как мне нарисовать русский текст? Почему я его не вижу? Ответ: В Game Maker по умолчанию встроен шрифт Arial 12, с ограниченным набором символов: начиная от 32 до 127. Русский алфавит в этот диапазон не входит, поэтому, чтобы рисовать русский текст, вам понадобится добавить свой шрифт, в котором нужно выставить максимальный диапазон символов, для поддержки кириллицы. Итак, выберите пункт "Create Font" из меню "Resources", или просто нажмите соответствующую кнопку на панели инструментов. Затем дайте имя своему шрифту в игре (я лично предпочитаю что-то вроде font_menu_button или font_arial10b), выберите сам шрифт, установите нужный размер и нажмите на кнопку "All" (Все), которая устанавливает максимальный диапазон символов. Наконец, вам нужно установить для использования этот шрифт в игре, для этого перед рисованием текста вызовите функцию draw_set_font: draw_set_font(имя_вашего_шрифта_в_игре); draw_text(...); Если вы всё равно не увидили русские буквы - значит выбранный вами шрифт не поддерживает кириллицу. Переписан. II.4.8:Вопрос 1: Как запросить у игрока код, к примеру, для открытия двери? Вопрос 2: Как сделать чит-коды? Ответ: Обе задачи решаются очень просто, с помощью функции get_string. Запросить код можно следующим образом: var text; text = get_string('Введите код для открытия двери:', '****'); // Запрашиваем у игрока код. if text = '1234' // Сравниваем его с правильным кодом. { // Действия, которые выполняются, если игрок ввёл правильный код. } else { show_message('Код неверен.'); // Выводим сообщение об ошибке. } Чит-коды можно организовать следующим образом: var text; text = get_string('Введите чит-код:', ''); // Запрашиваем у игрока чит-код. switch (text) // Сравнивем введённый игроком текст со всеми чит-кодами. Не забудьте break в конце каждой проверки! { case 'lives': lives = 100; break; case 'gold': score += 1000000; break; default: show_message('Такого чит-кода не существует!'); } Дополнен. II.4.10. Как определить время компьютера? Как отобразить текущее время на экране? Ответ: Все функции можно посмотреть в справке: GML -> Игровой процесс -> Синхронизация (http://gmakers.ru/gamemaker_help/source/files/403_07_timing.php): current_time* Количество миллисекунд, которые прошли с тех пор, как система была запущена. current_year* Текущий год. current_month* Текущий месяц. current_day* Текущий день. current_weekday* Текущий день недели (1=воскресенье, ..., 7=суббота). current_hour* Текущий час. current_minute* Текущая минута. current_second* Текущая секунда. Отобразить дату и время компьютера можно следующим образом: draw_text(x, y, string(current_hour) + ':' + string(current_minute) + ':' + string(current_second) + ' / ' + string(current_day) + '.' + string(current_month) + '.' + string(current_year)); Слегка исправлен. II.5.2. Что быстрее выполняется, функции lengthdir_x(len, dir) и lengthdir_y(len, dir), или cos(degtorad(dir))*len и -sin(degtorad(dir))*len? Ответ: Как и в случае с point_distance, lengthdir_x и lengthdir_y будет работать быстрее. Слегка исправлен. II.5.3. Что выполняется быстрее, стандартные проверки GM в объекте (на подобии add event -> Keyboard -> <Left>), или собственные проверки в step event (вроде keyboard_check)? Ответ: Стандартные события GM выполняются немного быстрее проверок в шаге. Вероятно, из-за того, что интерпретация кода, каким-бы простым он ни был - занимает довольно много времени. То есть, использование стандартных GM событий покажет большую производительность, чем многочисленные собственные проверки в step event. Однако, разница в скорости выполнения не столь велика, чтобы злоупотреблять этим. P.S: я лично, например, чаще всего вручную пишу большинство проверок в step event объекта. Слегка исправлен. II.5.4. Если одно из выражений в условии ложно, будет ли проверяться остальная часть условия? Ответ: В отличии от большинства языков программирования, в GML проверяется всё условие, вне зависимости, является ли одно из выражений ложным. То есть, условие написанное так: if is_picture_grayscale(temp) { if is_picture_fractal(temp) { // ... } } Будет выполнятся быстрее условия, записанного так: if is_picture_grayscale(temp) and is_pisture_fractal(temp) { // ... } (названия скриптов взяты наобум) Слегка дополнен. II.5.5. Почему не стоит выносить действия в событиях step/draw в скрипты? Ответ: Механизм вызова скриптов в GM невероятно медленный. Допустим, у нас есть два куска кода: a = b; И script0(); script0 такого содержания: a = b; Первый код, повторенный 100 раз выполнялся 0.044 миллисекунды, второй (скрипт) - 0.341 миллисекунды (то есть, примерно в семь раз дольше!). Первый код, повторенный 1000000 раз выполнялся 5401 миллисекунду, второй (скрипт) - 9864 миллисекунды. Очевидно, что вызов скрипта занимает довольно много времени. На деле, при большом количестве использования скриптов в постоянно повторяющихся событиях (как step и draw) - fps значительно падает. Был удалён следующий вопрос, из-за ошибочного предположения в разной скорости выполнения операторов <> и !=: II.5.5. Что работает быстрее, <> или != ? Ответ: На практике разницы практически нет. Тем не менее, я бы всё равно советовал вам использовать !=. И новые вопросы: II.01.15. Я устанавливаю image_speed на единицу, но кадр спрайта меняется мгновенно, а не один раз в секунду! Почему? Ответ: Присвоив переменной image_speed единицу, вы устанавливает смену кадра спрайта каждый шаг. То есть, если у вас скорость комнаты - 30 шагов, то за секунду у спрайта сменится 30 кадров. Если вам нужно, чтобы за секунду менялся один кадр, пишите: image_speed = 1/room_speed; Тогда каждую секунду кадр будет изменяться на 1/30 (если у вас скорость комнаты - 30 шагов), и за секунду кадр всего изменится на 30/30, то есть, на 1. II.01.16. Я устанавливаю таймер на единицу, но действие таймера происходит мгновенно, а не через одну секунду! Почему? Ответ: Таймеры измеряется в шагах, и установив таймеру время в единицу - он выполнится через один шаг, то есть, через 1/room_speed секунды. Для того, чтобы таймер выполнился через одну секунду, нужно писать так: image_speed = alarm[0] = room_speed;; Таким образом, событие таймера выполнится через room_speed шагов, а room_speed шагов состовляют одну сенкунду. II.4.24. Как вычислить разницу между направлениями? Ответ: Пожалуй, стоит разобраться с этим на примере, шаг за шагом разрабатывая искомый скрипт. 1. Предположим, у нас есть три направления: (http://savepic.org/1181608.jpg) ссылка на изображение, размер: 34.0 кбайт, 192 x 192 точек (http://savepic.org/1181608.htm) Очевидно, что для вычисления разницы между синим и красным направлениями нужно от синего отнять красное: (135° - 45°) = 90°. Как может показаться вначале, разница между красным и синим направлениями равна разнице между синим и красным. Однако, в нашем случае, разница может принимать отрицательно значение. Поэтому, разница между красным и синим направлениями равна -90°, а не 90°. На самом деле, вы получаете значение, которое нужно добавить ко второму направлению, чтобы получить первое. Добавляя 90 градусов к 45° получается 135°, ровно как и вычитая 90 градусов из 135° получается 45°. 2. Однако с зелёным и красным направлениями такая простая операция не даст желаемого результата. Скрипт должен возвращать "ближайшую разницу", не 270 градусов (которые можно получить, вычитая 45 градусов из 315°), а 90°: (http://savepic.org/1239979.jpg) ссылка на изображение, размер: 31.3 кбайт, 192 x 192 точек (http://savepic.org/1239979.htm) Требуется вычислить угол a° - он обозначен оранжевым цветом на картинке. Очевидно, что его можно получить, вычитая из 360 345° (зелёное направление), и прибавив к нему 45° (красное направление): dir = dir1 + (360 - dir2); // 45 + (360 - 315) = 90 Где dir - угол a°, dir1 - меньший угол (45° на картинке) и dir2 - больший угол (315 градусов на картинке). Итак, если разность направлений меньше 180 - можно просто отнять от одного направления другое, как в случае с синим и красным направлениями. Если же разность больше или равна 180 - нужно вычислять направление посредством вышеприведённой формулы, или вот так: dir = 360 - (dir2 - dir1); Этот код аналогичен предыдущему, в нём лишь переставлены значения, хотя логика сохранена. 3. Итого, скрипт вычисления разницы между двумя направлениями можно записать так: var diff; diff = argument1 - argument0; // Вычисляем разность между направлениями if abs(diff) > 180 // Если разность по модулю больше 180 return 360 - diff; // Возвращаем разность "через ноль" else return diff; // Возвращаем обычную разность Мы уже вплотную приблизились к решению задачи. Однако, этот скрипт полностью рабочий только когда argument1 больше argument0. К примеру, если argument1 = 15°, а argument0 = 215°, получим соответственно 360° - (15° - 215°) = 560 градусов. Потому, нужно изменить скрипт так, чтобы этой ошибки не возникало: // argument0 - первое направление // argument1 - второе направление var diff; diff = argument1 - argument0; if abs(diff) > 180 return (360 - abs(diff)) * -sign(diff); // Сначала находим разность между направлениями "через ноль", а потом устанавливаем нужный знак else return diff; Этот скрипт полностью рабочий и готов к использованию. Он возвращает значение, на которое больше / меньше направление argument1 чем направление argument0. Если argument1 = 135, а argument0 = 45, то получим 90. Если же argument1 = 315, а argument0 = 45, получим -90, так как 315 на 90 градусов меньше чем 45, считая "через ноль" (извините за каламбур, но это так): (http://savepic.org/1216428.jpg) ссылка на изображение, размер: 38.1 кбайт, 192 x 192 точек (http://savepic.org/1216428.htm) 4. Есть однако ещё одна проблема. Иногда направления бывают отрицательные, и часто превышают 360. Поэтому, желательно обработать входящие данные должным образом, чтобы не возникало непредвиденных ошибок: dir = dir mod 360; Эта строка вычисляет остаток от деления указанного направления на 360. То есть, если направление 370, то остаток от деления на 360 будет 10, если направление -740, то получим -20 и т.п. Таким образом, направление будет всегда меньше 360. После этого отрицательное направление нужно преобразовать в положительное. Сделать это, очевидно, можно так: if dir < 0 dir += 360; 5. К слову, все три вышенаписаные строки можно записать всего одной: dir = (dir mod 360 + 360) mod 360; Поясню этот код. Вначале направление приводится к виду от -360 до 360 (не включительно), с помощью оператора mod: "dir mod 360". Далее, если направление отрицательное - она преобразовывается в положительное, после прибавления к нему 360 градусов. К примеру: "-20 + 360" это тоже самое что "360 - 20", то есть, 340 - получаем нормальное положительное направление. Далее вычисляется остаток деления направление на 360, если направление было отрицательным - ничего не изменится, так как 340 mod 360 = 340, а если положительным - оно вернётся к изначальному: (20 + 360) mod 360 = 380 mod 360 = 20. Если вас эта сокращённая запись чем-то смущает, либо вы не можете с нею разобраться, либо же вам просто лень морочить себе голову, то используйте обычный код: dir = dir mod 360; if dir < 0 dir += 360; 6. В результате всех манипуляций с направлениями, скрипт вычисления разницы между двумя направлениями приобрёл следующий вид: /*************************************************** Скрипт возвращает разницу между двумя направлениями. argument0 - первое направление; argument1 - второе направление направление; ***************************************************/ var diff; diff = (argument1 - argument0) mod 360; if diff < 0 diff += 360; if abs(diff) > 180 return (360 - abs(diff)) * -sign(diff); else return diff; 7. На этом можно было бы закончить, однако есть способ записать весь этот скрипт в одну строку, только для самых "крутых" программистов. Я хочу вам рассказать про этот способ. Идея, на самом деле, довольно простая, только очень запутанная. Для начала нужно вычислить разницу двух направлений, просто вычитая одно из другого. Далее, нужно добавит 180 к полученному направлению. Если разность была меньше 180 - она так и останется меньше 360, а если больше - мы получим направление большее 360. После этого находим остаток от деления на 360, и снова отнимаем 180. Когда это написано сухими словами - понять это довольно сложно, так что снова попробуем разобраться на примере: (http://savepic.org/1212333.jpg) ссылка на изображение, размер: 35.6 кбайт, 192 x 192 точек (http://savepic.org/1212333.htm) Итак, мы "поворачиваем" наше направление (225 на рисунке) на 180 градусов, после чего вычисляем, на сколько полученное направление больше нуля (mod 360), в результате чего, получаем 45 градусов (серая стрелка на рисунке, a°). После этого вычитаем из полученного направления 180 градусов, вроде бы как "возвращая" направление назад, получая тоже, что и -(360 - dir) или dir - 360. На рисунке: (http://savepic.org/1203117.jpg) ссылка на изображение, размер: 28.2 кбайт, 192 x 192 точек (http://savepic.org/1203117.htm) Если dir (разность направлений) меньше 180 - в результате всех операций получаем тоже направление, так как (dir + 180) mod 360 - 180 = dir (при условии, что dir меньше 180). Итого, получаем вот такую страшную строку: return (((argument1 - argument0) mod 360 + 360) mod 360 + 180) mod 360 - 180; "((argument1 - argument0) mod 360 + 360) mod 360" - приводим разность направлений к виду 0 - 360, чтобы избежать ошибок. "(... + 180) mod 360 - 180" - если направление меньше 180, то ничего не меняется, если больше - получаем отрицательную разность (то, что я описывал выше). Можно заметить, что в этой строке есть пара повторяющихся действий, которые можно было бы объединить в одно: "((... + 360) mod 360 + 180) mod 360" тоже что и "(... + 540) mod 360" Итого, получаем такой скрипт: return ((((argument1 - argument0) mod 360) + 540) mod 360) - 180; и выглядит он именно так, как на сайте www.gmlscripts.com: /* ** usage: ** diff = angle_difference(angle1,angle2); ** ** given: ** angle1 first direction in degrees, real ** angle2 second direction in degrees, real ** ** returns: ** difference of the given angles in degrees, -180 to 180 ** ** GMLscripts.com */ { return ((((argument0 - argument1) mod 360) + 540) mod 360) - 180; } Вы можете использовать уже готовый скрипт в одну строку - а можете использовать более простой скрипт для понимания, составленный нами выше. Ах да, совсем забыл! Был полностью переписан раздел искусственного интеллекта, и, мало того, он ещё находится в разработке. Потому, среди готовых вопросов вы можете видеть странные надписи "Зарезервировано", они означают, что новый вопрос скоро будет добавлен на это место. Или не скоро, When It's Done, в общем. По правде говоря, и те вопросы, которые я переписал следовало бы полностью переписать ещё два-три раза как минимум. Не говоря уж о тех, которые я оставил в покое. Но, как известно, лучшее - враг хорошего, верно? Я не буду зацикливаться на доведении FAQ до идеала, а займусь добавлением вопросов. Обязательно будет переписан вопрос про lengthdir'ы, как я и обещал, но чуть позже. Не избегут такой участи и два вопроса, ему предшествующие. Так же планирую слегка переформировать FAQ, потому что подраздел "Другое" содержит в себе слишком большое кол-во вопросов, которые можно было бы как-то разделить на несколько категорий. Впрочем, никому не интересны эти скучные детали, кроме меня, так что просто ждите улучшений в ближайшем будущем! ^_^ Ещё я готовлю кое-что интересное, но увидите вы это не скоро, потому что с каждым днём свободного времени у меня становится всё меньше. Скорее всего, релиз будет летом. До новых встреч. С уважением, DeatHSoul.
Название: Re: F.A.Q. для начинающих
Отправлено: Vendet от Апрель 26, 2011, 10:45:18
Молодец DeatHSoul! sm_respekt
Название: Re: F.A.Q. для начинающих
Отправлено: Shadowpoper от Май 26, 2011, 12:50:51
Добавьте пожалуйста информацию по добавлению очков. К примеру, если убил монстра, то 10 очков.
Название: Re: F.A.Q. для начинающих
Отправлено: lucheus от Май 27, 2011, 07:47:57
Еще несколько моих примеров:
Пример использования "Сепоратора Движения" http://letitbit.net/download/20363.273c7daf436b94cab5988e7d46f7/(m.primer)_meat_exp.gmk.html Пример нахождения цвета на мышке http://letitbit.net/download/36152.3e11b89c8729a606002f963b75f2/(m.primer)_Color.gmk.html Пример градиэнтного треугольника и с изменение вершин http://letitbit.net/download/04446.08072b6ac071cbf7fad38414c4a3/(m.primer)_Treugol.nik.gmk.html
Название: Re: F.A.Q. для начинающих
Отправлено: Alcatraz от Май 27, 2011, 09:25:46
кошмар! летитбит! :facepalm_2: лейте файлы на http://sendspace.com , http://rghost.ru , или прикрепляй к сообщению, так надёжней.
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Июнь 20, 2011, 17:06:07
Я решил отменить обновления FAQ. Оно не будет обновляться ещё очень долгое время, кроме, возможно, нескольких вопросов, которые просто необходимо переписать. Если у кого-то есть сильное желание заниматься FAQ - в принципе, я могу передать его в ваши руки, сможете сделать всё так, как вам хочется, даже абсолютно по-другому. Я планировал массивную переработку faq, так что когда и если она будет готова - она выйдет как отдельный продукт (как минимум месяца через четыре-пять).
Название: Re: F.A.Q. для начинающих
Отправлено: Hummer от Июль 04, 2011, 09:36:57
II.01.16. Я устанавливаю таймер на единицу, но действие таймера происходит мгновенно, а не через одну секунду! Почему? Ответ: Таймеры измеряется в шагах, и установив таймеру время в единицу - он выполнится через один шаг, то есть, через 1/room_speed секунды. Для того, чтобы таймер выполнился через одну секунду, нужно писать так: Код: image_speed = alarm[0] = room_speed;; Таким образом, событие таймера выполнится через room_speed шагов, а room_speed шагов состовляют одну сенкунду. Как код понять? ::)
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Июль 06, 2011, 19:03:51
Ахаха =D Извиняюсь, поправил.
Название: Re: F.A.Q. для начинающих
Отправлено: afutui от Июль 08, 2011, 12:06:32
Уважаемые..............люди. Я Новичок в GMе, прошел один туториал.Подскажите пожалуйста как поставить на Game Maker движок GMOgre, вот движок скачал, а как поставить не знаю.
Название: Re: F.A.Q. для начинающих
Отправлено: afutui от Июль 08, 2011, 13:37:47
примеры же есть http://forum.hellroom.ru/index.php?topic=640.0 необходимо в свой проект перетащить скрипты и длл в папку проекта.. также создать папки под текстур, модели и т.п..
новичку надо гм изучить, а не сразу после первого туториала на движок переходить, зачем лезть вперед паровоза?
спс за обьяснения.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Июль 12, 2011, 17:06:11
Предлагаю вывести весь список вопросов в первое сообщение под спойлер простым текстом дабы облегчить поиск нужного вопроса. А то не все браузеры поддерживают поиск по заголовкам спойлеров (открыв все главы и начав простой поиск по тексту ( Control+F)). Выглядеть будет примерно так: ...Помните, даже незначительные изменения могут упростить использование FAQ. I - Теория. 1) Старт I.1.1. Что такое Game Maker? I.1.2. Что такое GML? I.1.3. Какая последняя версия Game Maker? ... Хоть у каждой главы есть своя тема, все равно некоторые вопросы могут затеряться, например, II.4.3. Хелсбар не показывает больше 100 жизней, хотя health у меня равно 200! Как мне установить максимальное значение health? - скорее относится к главе Рисование. И для поиска приходится открывать все главы и "вручную" перечитывать все заголовки спойлеров.
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 13, 2011, 00:26:17
Спасибо за проделанный труд! Ещё одно предложение - было бы совсем здорово, если бы все эти вопросы в chm загнать - гораздо легче (+поиск и т.п.)
Название: Re: F.A.Q. для начинающих
Отправлено: Vendet от Июль 13, 2011, 01:32:51
Спасибо за проделанный труд! Ещё одно предложение - было бы совсем здорово, если бы все эти вопросы в chm загнать - гораздо легче (+поиск и т.п.)
А почему бы не отблагодарить автора, сделав самому такую версию в формате .chm и выложить в этой теме) Просто раз речь пошла, было бы отлично, но у автора и так много других дел.
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 14, 2011, 23:02:33
Сделал. Однако пока без поиска. И так двое суток на это убил. Как будет время, сделаю поиск. Просьба сообщать о багах, очепятках и т.п.
Название: Re: F.A.Q. для начинающих
Отправлено: Vendet от Июль 16, 2011, 19:33:58
Сделал. Однако пока без поиска. И так двое суток на это убил. Как будет время, сделаю поиск. Просьба сообщать о багах, очепятках и т.п.
sm_respekt Сделано и оформлено отлично, не хватает лишь поиска. Плюсую sm_good
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 17, 2011, 14:08:12
Теперь банановыыыый sm:25
Добавлен поиск, добавлен раздел про ошибки, переработан раздел с терминологией.
Качайте, пользуйтесь, оценивайте. Пожелания, предложения принимаются. Если что-то нужно включить туда - пишите.
Название: Re: F.A.Q. для начинающих
Отправлено: Vendet от Июль 17, 2011, 16:59:25
Отлично sm_good Добавил архив на сайт http://game-maker.ru/infusions/pro_download_panel/download.php?did=1631 PS: На сайте сделал обновление, кнопочку "Мне нравится" (возможно потом будут другие), увидеть можно в разделах файлы, вверху названия.
Название: Re: F.A.Q. для начинающих
Отправлено: PelmeshkO от Июль 17, 2011, 17:06:35
Теперь банановыыыый sm:25 Добавлен поиск, добавлен раздел про ошибки, переработан раздел с терминологией. Качайте, пользуйтесь, оценивайте. Пожелания, предложения принимаются. Если что-то нужно включить туда - пишите.
Опечатка в F.A.Q'е FAQ может и должно постоянно пополняться...
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 17, 2011, 17:57:14
Опечатка в F.A.Q'е FAQ может и должно постоянно пополняться... А в первом сообщении написано: FAQ может и должно постоянно пополняться, так что пишите вопросы, которые на ваш взгляд должны находиться в FAQ. В следующей раз будет так, как вы сейчас написали. Хотя логика подчеркивания трёх слов вполне понятна. Может и останется :)
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Июль 23, 2011, 15:56:00
Вау! :_shocked_: Спасибо огромное, парни! Честно признаться, и сам планировал сделать новую версию FAQ в формате .chm, но остановил разработку из-за критической нехватки времени. Ещё раз спасибо, я очень благодарен. sm_milo
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 23, 2011, 16:52:35
Если у вас есть какие-то наработки, можете мне их давать, я буду пополнять.
P.S. Да и ссылку в первый пост можно вставить :whistling:
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Июль 24, 2011, 15:03:20
Ссылку в первый пост добавил. Есть кое-какие мысли по реорганизации всего FAQ, но эта улучшенная версия выйдет зимой-весной, как отдельный продукт.
Название: Re: F.A.Q. для начинающих
Отправлено: MegaDimon от Июль 30, 2011, 21:23:05
нашёл небольшую недороботку:
Добавлено: Июль 30, 2011, 21:25:00 там ищё в разделе другое много таково
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Июль 30, 2011, 21:29:07
Два однотипных вопроса... не помещаются в спойлер.
Название: Re: F.A.Q. для начинающих
Отправлено: TPM от Август 16, 2011, 17:41:23
При запуске программы появляется окно Just-In-Time Debugging из-за которого зависает программа. Для чего это окно вообще нужно? Ибо избавится от него невозможно.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Август 16, 2011, 17:56:31
Название: Re: F.A.Q. для начинающих
Отправлено: aleckei от Сентябрь 03, 2011, 14:29:28
спасибо за F.A.Q. я многое уже понял на форумен, но тут много что было интересного, так что таким как я это понадобится...
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Сентябрь 03, 2011, 15:52:32
Спасибо за комментарий sm_milo
Название: Re: F.A.Q. для начинающих
Отправлено: aleckei от Сентябрь 30, 2011, 22:24:27
Спасибо за комментарий sm_milo
да не за что)))
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Октябрь 04, 2011, 20:53:49
Обновил (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1701) версию до 0.2.2. Пополнен список ошибок.
Название: Re: F.A.Q. для начинающих
Отправлено: stdcout от Октябрь 23, 2011, 14:34:04
А можно про lengthdir-ы поподробнее? А то я уже третий день фактически "занимаюсь сексом" с ГМ, но не могуникак сделать так чтоб пуля вылетала из дула!
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Октябрь 23, 2011, 16:22:59
На здоровье (автоматика) (http://forum.hellroom.ru/index.php?topic=2416.0)
Lengthdir - проекция вектора на соответствующую ось 2д координатной сетки. Показывает, грубо говоря, ширину / высоту прямоугольника, в который вписывается указанный вектор.
Название: Re: F.A.Q. для начинающих
Отправлено: denis от Декабрь 20, 2011, 15:10:37
спасибо за урок sm_good оч помогло sm_respekt
Название: Re: F.A.Q. для начинающих
Отправлено: Tourist от Январь 07, 2012, 14:37:46
А можно в FAQ добавить вопрос: Как сделать двойной прыжок?
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Январь 08, 2012, 08:09:33
в оффлан-версии появится в следующем билде.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Февраль 25, 2012, 13:25:59
Народ, у меня такой вопрос. Когда я поворачиваю объект, то качество графики ухудшается, как это исправить?!
Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы.
Название: Re: F.A.Q. для начинающих
Отправлено: Hamster099 от Март 09, 2012, 23:27:46
так как округление воспроизводится и не в меньшую сторону и не в большую, т.е. если, скажем, image_index равно 1.4, то после округления мы получим 1, а если оно равно 1.5 - получим 2. Это важно учитывать, так как мы увидим второй кадр на экране, когда округлённое значение image_index фактически будет равно 1 (нумерация начинается с 0, так что второй кадр - 1). А потому, следует написать так: if round(image_index) = 1 then instance_create(x, y, o_explosion); Мы получим точно такой результат же :errm: Может следует написать if floor(image_index) = 1 ?
Название: Re: F.A.Q. для начинающих
Отправлено: DeatHSoul от Март 11, 2012, 19:41:54
Спасибо за бдительность! Однако написано всё верно. В справке ошибка в этом предложении: (Значение может иметь дробную часть. В этом случае, оно всегда будет округлено в меньшую сторону, чтобы получить кадр, который рисуется.) На самом деле, значение округляется к ближайшему. Потому в проверке и следует использовать round, а не floor. Ответ можно было бы уточнить и переписать, однако я не вижу в этом смысла: мелкие / отдельные исправления не исправят общей картины. Страдает всё: и формулировка ответов, и их детальность, и способ изложения, и классификация вопросов. FAQ нуждается в глубокой переработке, однако вместо того чтобы просто переписать всё, я решил переосмыслить задумку. Что же, сами всё увидите. P.S. Не ждите, что обновление будет в скором времени, однако когда-нибудь faq таки обновится (может даже к концу лета), и предстанет перед вами как часть чего-то большего, чем просто список вопросов-ответов. Вероятно, обновлённой версией будет пользоваться уже новое поколение GM-игроделов, а все читатели нынешней версии к тому времени узнают больше, чем я напишу. Хотя, faq ведь актуально для каждого игродела, верно?
Название: Re: F.A.Q. для начинающих
Отправлено: MusNik от Апрель 28, 2012, 23:50:06
Очепятка _gg_: Другое: momemtary bullets.gmk (11.6 кб) - пример мгновенных пуль, собственных жизней у противников и хелсбаров. healthbar and gradual turn.gmk (14.4 кб) - пример спрайтового хелбара и плавного поворота. depth example.gmk (25.2 кб) - пример определения наивысшего объекта в области мышки. tds move.gmk (9.83 кб) - пример движение по диагонали с той же скоростью, что и обычно.
Название: Re: F.A.Q. для начинающих
Отправлено: coder94 от Июль 20, 2012, 14:48:52
А если что-то не понятно и не получается вопросы здесь можно задавать? Или создавать на форуме тему, но тогда если создать, скажут читай FAQ.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Июль 20, 2012, 14:55:49
Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы.
Создавай новую тему с пометкой, что Faq читал, не получается, мол, объясните подробнее для новичка.
Название: Re: F.A.Q. для начинающих
Отправлено: Exerion от Август 11, 2012, 19:44:50
Вопрос: Как отключить появление Just-in-time Debugger при старте Game Maker?
Ответ: Меню File -> Preferences, вкладка General, снять галочку Show news on startup.
Проблема возникала у меня и ещё у некоторых людей, решилась таким простым методом.
Название: Re: F.A.Q. для начинающих
Отправлено: M@ster от Август 15, 2012, 19:14:26
Тема супер!Для новичков вообще круто!! sm_respekt sm_respekt sm_respekt sm_respekt
Название: Re: F.A.Q. для начинающих
Отправлено: AleksM от Ноябрь 03, 2012, 22:51:32
Классный FAQ, заметил ошибку, там, где примеры: stairs.gmk (12.2 кб) - пример лестниц. Автор: Лер.
Название: Re: F.A.Q. для начинающих
Отправлено: vlad2525253 от Январь 08, 2013, 17:58:56
ваше sm_respekt sm_good супер
Название: Re: F.A.Q. для начинающих
Отправлено: nectarine от Февраль 14, 2013, 22:29:35
Привет, форумчане! sm_hi3 Не нашел, где этим можно поделиться, поэтому оставлю здесь :) Недавно столкнулся с проблемой, установил GameMaker Studio, а он наотрез отказывался отрисовывать кириллицу, даже для заведомо кириллических шрифтов, выдавая пустоту на экране. Решение: 1. Создать шрифт и открыть его свойства. 2. Нажать внизу окна "+" 3. В окне Font Range нажать "All" Если появились русские буквы - готово :) Если же полезла абракадабра (??????????????? и т.д.) 4. Стереть в окошке всю абракадабру до перевернутого знака вопроса (?) 5. Заменить этой строкой: АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя 6. Сохранить все изменения и выдохнуть, теперь точно будет работать :) P.S. Пишу этот пост, ибо ни здесь, ни в комьюнити yoyogames ответа не нашел.
Название: Re: F.A.Q. для начинающих
Отправлено: Briginas от Февраль 14, 2013, 22:38:20
nectarine, http://forum.hellroom.ru/index.php?topic=12355.msg145659#msg145659
Название: Re: F.A.Q. для начинающих
Отправлено: Степан от Август 31, 2013, 16:23:01
Что значит "зарезервировано"?
Название: Re: F.A.Q. для начинающих
Отправлено: Psycho от Август 31, 2013, 16:32:14
Что значит "зарезервировано"?
Новый толково-словообразовательный словарь русского языка. Автор Т. Ф. Ефремова. Оставить, сохранить в качестве резерва.
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Август 31, 2013, 16:35:15
Что значит "зарезервировано"? зарезервировано - значит, туда хотели что-то вставить, но не сделали этого.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Сентябрь 02, 2013, 11:40:13
Еще раз для непонятливых: Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы.
(http://forum.hellroom.ru/index.php?topic=17355.0)
Название: Re: F.A.Q. для начинающих
Отправлено: Discord Dash от Сентябрь 03, 2013, 05:08:52
Это на 20 % крче моих знаний. sm_respekt автору.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Сентябрь 03, 2013, 15:14:23
Еще раз для непонятливых: :getlost: Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы.
(http://forum.hellroom.ru/index.php?topic=17364.0)
Название: Re: F.A.Q. для начинающих
Отправлено: SVESH от Февраль 28, 2014, 17:25:06
rough surface.gmk (13.5 кб) - пример движения по неровной поверхности. когда персонаж подходит к стене или подлетает в прыжке, то он придвегается к стене не в плотную. Остаётся зазор в несколько пикселей. Надо бы исправить пример
Название: Re: F.A.Q. для начинающих
Отправлено: hitrok от Февраль 28, 2014, 17:50:11
Пример вообще не сахар, для своего проекта, сначала переписывал, мучился, после сам написал, с нуля - получилось шикарно [как Картмен говорит] ! Но для новичков то, что надо. :sideways:
Название: Re: F.A.Q. для начинающих
Отправлено: SVESH от Февраль 28, 2014, 20:41:06
Пример вообще не сахар, для своего проекта, сначала переписывал, мучился, после сам написал, с нуля - получилось шикарно [как Картмен говорит] !
а свой вариант кода движения по неровностям показать можете?
Название: Re: F.A.Q. для начинающих
Отправлено: Maspel от Апрель 05, 2014, 15:54:22
при запуске на html5 var obj; obj = instance_nearest(x, y, родительский_объект);
mp_potential_step(obj.x, obj.y, скорость_движения, checkall)
и т.д. не работает. Все стоят на местах. А при обычном запуске работает.
Название: Re: F.A.Q. для начинающих
Отправлено: Fantom от Апрель 05, 2014, 20:43:43
Еще раз для непонятливых: :getlost: [x6] Здесь не задают вопросы и не просят помощи касательно Game Maker или GML! Здесь обсуждают FAQ и добавляют грамотно написанные вопросы/ответы.
(http://forum.hellroom.ru/index.php?topic=18901.0)
Название: Re: F.A.Q. для начинающих
Отправлено: Goo от Апрель 27, 2014, 12:02:55
Тема классная, но если бы было побольше спойлеров в разделе движение и столкновение, было бы еще круче!!! а в целом класс!!!
Название: Re: F.A.Q. для начинающих
Отправлено: Shpanyk от Июль 18, 2014, 17:18:07
А вот интересно мне, как сделать чтобы обьект отскакивал от площадки как в игре дудлДжамп? тоесть пока он не упадёт сверху не отскочит
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 18, 2014, 17:50:03
А вот интересно мне, как сделать чтобы обьект отскакивал от площадки как в игре дудлДжамп? тоесть пока он не упадёт сверху не отскочит
Двумя сообщениями выше прочитайте
Название: Re: F.A.Q. для начинающих
Отправлено: Record от Декабрь 11, 2014, 16:28:43
II.2.17. Как сделать, чтобы пуля вылетала из дула? До меня не дошло...причём как будто я в первый раз сел за комп и не знаю что делать...расписали блин...прошу объяснится и расписать по подробнее, представьте что объясняете пню...вдолбите в пень как этой информацией воспользоваться, спасибо.
Название: Re: F.A.Q. для начинающих
Отправлено: redmassacre от Апрель 05, 2015, 11:36:45
Дополните пожалуйста этот пункт
II.5.4. Если одно из выражений в условии ложно, будет ли проверяться остальная часть условия? Ответ: В отличии от большинства языков программирования, в GML проверяется всё условие, вне зависимости, является ли одно из выражений ложным. То есть, условие написанное
Это починили в GMS Version 1.2.1262
http://bugs.yoyogames.com/view.php?id=0008738
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Апрель 05, 2015, 13:09:12
Это FAQ написано для GM8 и нужно достаточно много переписывать, чтобы всё было на актуальном уровне по отношению к GMS. Вряд ли стоит надеяться на это в ближайшее время. О большинстве нововведений GMS и о нюансах работы (в том числе, касательно оптимизации) есть множество статей/тем/сообщений на этом форуме.
По 2.5.4 внесено дополнение в ответ.
Название: Re: F.A.Q. для начинающих
Отправлено: Stron от Июль 25, 2015, 05:34:27
Моё мнение, как новичка, который читает F.A.Q. сделать в каждом спойлере, в котором ответ на вопрос, пример для вставке в игру.
Вообще когда начал изучать GM, то заметил такую разницу. По видеороликам легко изучать, там показывается какой код куда должен помещаться. И я ставлю на паузу что бы перенести код в свою игру.
В вашем F.A.Q. просто дается минимальный код. Я не знаю куда его вставлять и как прикрутить к готовой минимальной игре. Или как по минимуму увидеть работу данного кода.
Поэтому мое предложение , что бы новички поменьше спрашивали и побольше сами все изучали, с первого вопроса в этой ветке давать готовый вариант и куда его нужно вставлять. Лучше что бы путаницы не было с начала темы предложить создать базовый набор спрайтом, объектов. комнат, и т.д. то есть базовый вариант игры. И на ней все показывать в виде добавлений кода. То есть ученический проект игры. И в этом ученический проект предлагалось бы вставлять код, который описывается в каждом вопросе.
Название: Re: F.A.Q. для начинающих
Отправлено: TheTemperenNuke от Июль 25, 2015, 06:36:18
Моё мнение, как новичка, который читает F.A.Q. сделать в каждом спойлере, в котором ответ на вопрос, пример для вставке в игру. :facepalm: Ради одной строчки делать пример?! Есть новички, которые понимаю всё, а не пишут: "А как сделать это? А как сделать то? А сделайте за меня игру".
Название: Re: F.A.Q. для начинающих
Отправлено: Dmi7ry от Июль 25, 2015, 07:11:34
Моё мнение, как новичка, который читает F.A.Q. сделать в каждом спойлере, в котором ответ на вопрос, пример для вставке в игру. Цель FAQ - дать ответы на вопросы, а не обучение с нуля. Для обучения существует огромное количество уроков - как в виде видеоуроков, так и в виде статей.
Название: Re: F.A.Q. для начинающих
Отправлено: skypo от Июнь 05, 2016, 15:05:51
Плиз, поправьте FAQ. В "II.3.4. Как изменить глубину объекта в draw event?" говорится, что нельзя, но я точно помню что не так давно появились какие-то команды, чтобы из одного объекта можно было отрисовывать спрайты на разных глубинах.
Название: Re: F.A.Q. для начинающих
Отправлено: Тёлыч от Октябрь 20, 2017, 22:36:05
Божечки, тут кажется очень давно никого не было.. Спасибо большое за FAQ, очень помогло в продвижении, по сути это - миниучебник. Добавить немного самого базового, типа передвижения или стрельбы (хотя это может и есть, я не видел) и будет полноценный учебник для новичка. Многое, конечно, я не понял, но то, что понял - очень интересно.
Название: Re: F.A.Q. для начинающих
Отправлено: Lelekanet от Декабрь 02, 2020, 14:24:34
Большое спасибо за труд. Возник вопрос по пункту "II.4.4. Как определить наивысший объект под мышкой?" Во время запуска скрипта выбивает ошибку... О реализовать данную функцию пытаюсь уже давно и все без толку. И еще, под мышкой у меня не экземпляры одного объекта, а разные объекты. Буду очень признателен за помощь.
Название: Re: F.A.Q. для начинающих
Отправлено: Duncorp от Июль 08, 2021, 14:13:36
Всем привет. Можно ли добавить еще больше примеров?
Хотелось бы видеть пример или сам код 1. Как вывести текст 2. Как в комнате показать 10 спрайтов одновременно в рандомных местах,но без перекрытий
Название: Re: F.A.Q. для начинающих
Отправлено: AndrewVideoGames от Июль 08, 2021, 15:04:09
Всем привет. Можно ли добавить еще больше примеров?
Хотелось бы видеть пример или сам код 1. Как вывести текст 2. Как в комнате показать 10 спрайтов одновременно в рандомных местах,но без перекрытий
1 – это банальный вопрос, ответ на который можно найти в справке. Гуглите draw_* функции 2 – спрайты не создаются, создаются объекты, а спрайты рисуются. Самым простым решением будет задать все возможные точки, в которых могут располагаться квадраты, в начале уровня выбирать из них случайные 10 точек и на них сравнить (или отрисовывать) квадраты. Вот ссылки, которые могут пригодится при изучении GameMaker(GML): 1) Обязательно прочитать: - Русская справка по Game maker (http://game-maker.ru/infusions/pro_download_panel/download.php?did=1024); - Школа GML (http://forum.hellroom.ru/index.php?board=65.0); 2) Почитать уроки: - Статьи/Уроки (http://forum.hellroom.ru/index.php?board=30.0); - Туториалы (http://game-maker.ru/infusions/pro_download_panel/download.php?catid=10); 3) Посмотреть различные примеры: - Примеры на форуме (http://forum.hellroom.ru/index.php?board=22.0); - Примеры на сайте (http://game-maker.ru/viewpage.php?page_id=54); 4) Обратите внимание на эти правила и советы: - 10 советов пользователям GM для избежания часто встречающихся ошибок (http://forum.hellroom.ru/index.php?topic=4275.0); - Простые правила оптимизации кода / игры в целом (http://forum.hellroom.ru/index.php?topic=7896.0); - Оптимизация игр в GameMaker: Studio (http://forum.hellroom.ru/index.php?topic=18542) 5) Если возникла ошибка - попробуйте найти решение здесь: - Ошибки, их причины и исправление (http://forum.hellroom.ru/index.php?topic=2940.0); - [GMS] Ошибки раннера и компилятора (описание и причины) (http://forum.hellroom.ru/index.php?topic=13765.0); 6) Если возник вопрос или хочется узнать как что то сделать, то скорее всего, на форуме это уже обсуждалось: - F.A.Q. для начинающих (http://forum.hellroom.ru/index.php?topic=2035.0); - Поиск на форуме (http://forum.hellroom.ru/index.php?action=search); - Поиск на сайте (http://game-maker.ru/infusions/pro_download_panel/search.php); - Как пользоваться поиском (http://forum.hellroom.ru/index.php?topic=20718.0) 7) Основные источники это наш форум (http://forum.hellroom.ru/) и сайт (http://game-maker.ru/).
+ Заглядывать сюда: Маркетплейс YoYo Games с полезными ассетами (http://marketplace.yoyogames.com)
|