skype: megainformatic, телеграм: megainformatic, онлайн-чат (megainformatic live chat), форма обратной связи
Онлайн Школа Компьютерных Наук Андрея Синицина
Добро пожаловать в нашу школу ! Давайте вместе откроем путь к новым перспективам !!!
Fle game engine - реализация коллизий на примере проекта Многоликий: dress
О реализации столкновений на движке fle game engine я уже рассказывал в статье Проверка столкновений В упомянутой статье предполагалось, что у вас перед глазами открыт исходный код проекта и Вы можете его посмотреть. Сейчас мы рассмотрим более общий пример реализации коллизий. И в качестве примера будет рассказано о том, как реализуются коллизии в игре Многоликий: dress. В чем суть задачи: по экрану слева-направо движутся враги и вам нужно фиксировать столкновение между ними и персонажем. В данном случае этот персонаж - девушка по имени Ри. Если столкновение зафиксировано, то в ответ надо предпринимать какие-либо действия, например снижать полоску индикатора на некоторое значение, так называемый урон fDamage наносимый данным врагом. Чтобы лучше понимать суть - посмотрите как выглядит игровой процесс (на видео еще не показано как работают столкновения, показано лишь перемещение врагов и персонажа). На первый взгляд может показаться, что работа с коллизиями (столкновениями), особенно для новичков, представляет что-то непонятное и даже сложное. Например во многих движках для настройки коллизий не нужно выполнять какой-то сложный набор действий, однако детали того, как работают коллизии могут быть скрыты от вас. И уж если вдруг вам потребуется изменить поведение коллизий самым нетривиальным образом, то с большой вероятностью в движках, где вы никак не можете повлиять на код реализации коллизий и их использование нестандатно, Вам придется искать какой-то другой путь. В движке fle game engine, который написан на c++ directx 9 и имеет полный открытый исходный код все это не представляет сложности. За тем лишь исключением, что использование коллизий в вашем проекте поначалу может показаться более громоздким, нежели в других движках. Но этот недостаток с лихвой покрывается тем, что Вы можете не только применять коллизии каким-то нестандартным образом, но можете и изменить сам исходный код - добавив какие-то новые возможности. Тем самым нетривиальное использование не имеет никаких ограничений, а в настоящих игровых проектах, где чаще всего и нужно как можно больше чего-то нестандартного, все это найдет применение. Итак, Реализация столкновений включает следующие шаги: 1) Определить размеры collision box - прямоугольной области у игрового объекта, при попадании в которую будет фиксироваться столкновение; 2) Подключить необходимые для работы с коллизиями модули в коде; 3) Добавить код осуществляющий загрузку параметров коллизий у игровых объектов и освобождение загруженных ресурсов при завершении работы игры; 4) В нужном месте кода вызывать метод осуществляющий проверку столкновения между персонажем и врагами; 5) В соответствии с фиксацией столкновения выпонять какие-либо игровые действия, например изменять полоску индикатора и если она достигла определенных значений, например 0 - вызывать экран Game over. Также выполнять какие-то еще необходимые действия. Рассмотрим каждый из шагов более подробно. 1) Определить размеры collision box - прямоугольной области у игрового объекта, при попадании в которую будет фиксироваться столкновение; для этого в папке ресурсов проекта - в моем случае это папка Media4 для удобства я создал внутри отдельную папку Media4\prop_desc так что внутри неё создаем 2 файла с таким содержимым Media4\prop_desc\collision_rects_desc6.txt hero_walk; 0.0525f; -0.1800f; 0.2025f; -0.3800f; 0.785f; enemy_walk; 0.035f; -0.0733f; 0.2075f; -0.15f; 0.6f; hero_walk - задаем 4 значения для левого верхнего - left, top, правого нижнего углов right, bottom collision box у персонажа, а последний параметр означает масштаб нашего collision box. 0.785f означает, что он сжат. Если было бы 1.0f - имеет тот же масштаб, что и спрайт. А если будет > 1.0f - значит растянут относительно спрайта (такое тоже может быть для каких-либо целей). Но обычно масштаб < 1.0f поскольку чаще всего мы не хотим чтобы вся область спрайта являлась одновременно и областью для фиксации столкновений. Обычно эту область делают значительно меньше - т. к. чтобы столкновение произошло объекты должны визуально коснуться друг друга - чего нельзя будет достичь при масштабе 1.0f т. к. вокруг спрайта будет обязательно пустое пространство и поэтому столкновение будет фиксироваться еще задолго до того, как объекты соприкоснутся - и это может вызвать недоумение игрока, хотя все зависит от особенностей конкретного проекта. Это может использоваться и намеренно. аналогично задаем для врага - enemy_walk параметры имеют отрицательное значение по y означая, что от верхней границы объекта нужно отступить вниз указанное количество единиц размера (не пикселей ! т. к. используются относительные значения не зависящие от разрешения экрана) Media4\prop_desc\game_object_class_properies6.txt // // описание свойств героя // begin =; Name = hero_walk; Collided = true; end =; // // описание свойств врага // begin =; Name = enemy_walk; Collided = true; end =; Здесь все еще проще. Просто задаем возможность наличия коллизии. Могут быть случаи когда проверку столкновения делать нужно, но фиксировать коллизию - нет. Поэтому значение Collided = true можно у объекта задать и как Collided = false Чего не позволят сделать вам движки, где функционал коллизий применяется "из коробки", то есть Вы не знаете внутренние подробности их устройства. Обратите внимание, что оба файла имеют номерной индекс 6 Media4\prop_desc\collision_rects_desc6.txt Media4\prop_desc\game_object_class_properies6.txt это означает, что данная коллизия в моем проекте уже 6 по счету. А индексы даются чтобы отделить код и логику от коллизий которые уже используются в проекте, но для других целей. То есть в моем проекте получается используется 6 разных коллизий, и коллизия с врагами и персонажем - уже 6 по счету. 2) Подключить необходимые для работы с коллизиями модули в коде; Происходит это так - нужно взять 4 файла для работы с кодом коллизий - в моем проекте эти файлы находятся в папке start\game_common\ за основу я беру файлы других коллизий, которые у меня уже были в проекте например файлы collision5.h collision5.cpp game_object_properties5.h game_object_properties5.cpp я делаю копию этих 4 файлов и переименовываю в collision6.h collision6.cpp game_object_properties6.h game_object_properties6.cpp чтобы не было конфликта имен переменных используемых внутри других файлов коллизий я все именования имеющие индекс 5 в коде заменяю на 6 пример collision6.h typedef struct GAMEOBJECTCOLLISIONRECT5 { CString* Name; //game object name D3DXVECTOR2 LeftTop; D3DXVECTOR2 RightBottom; float BaseScale; } GameObjectCollisionRect5, *LPGAMEOBJECTCOLLISIONRECT5; нужно превратить в typedef struct GAMEOBJECTCOLLISIONRECT6 { CString* Name; //game object name D3DXVECTOR2 LeftTop; D3DXVECTOR2 RightBottom; float BaseScale; } GameObjectCollisionRect6, *LPGAMEOBJECTCOLLISIONRECT6; и все остальные элементы в коде во всех этих 4 файлах. Далее нужно подключить эти 4 файла в ваш проект. Сначала добавив их в окне Solution explorer, а затем и указав в коде ссылки на их подключение. В своем проекте я подключаю их в файле gdess.cpp такими строками кода в самом начале файла - #include "game_object_properties6.h" #include "collision6.h" Собственно говоря с этого момента использование коллизий в проекте подключено. Остается добавить код, который будет работать с вашими коллизиями - загрузит и освободит (когда нужно) файлы с параметрами коллизий, выполнит проверку факта столкновения (коллизии) между игровыми объектами и наконец код который в зависимости от коллизий будет выполнять какие-то действия в игре - изменение количества очков, энергии и что угодно еще - все что задумано в игре. Таким образом следующий шаг - 3) Добавить код осуществляющий загрузку параметров коллизий у игровых объектов и освобождение загруженных ресурсов при завершении работы игры; Для этого в своем проекте в модуле gdess.cpp я добавил такой код - в методе void CGdess::Load() { делаю вызов //загрузка свойств объектов необходимых для проверки столкновений LoadGameObjProperties6(GameObjectClassProperties6); а в методе void CGdess::Before_Free() { FreeGameObjProperties6(); //освобождаем ресурсы выделенные для объектов проверки //столкновений Если эти 2 важных элемента забыть - то код работы с коллизиями будет давать ошибку !!! Если все хорошо и параметры загружены (и будут освобождены когда нужно), можно двигаться дальше - 4) В нужном месте кода вызывать метод осуществляющий проверку столкновения между персонажем и врагами; для этого в модуле gdess.cpp я написал такой метод void CGdess::RiContactEnemy() { m_bRiContactWithEnemyDetected = false; //это будет у нас флаг фиксации момента столкновения //между персонажем и врагом LPGAMEOBJECTPROPERTIES6 heroProp = GetGameObjInstProperty6(hero_prop6); //получаем свойства объекта //столкновений у персонажа игрока LPGAMEOBJECTPROPERTIES6 enemyProp = GetGameObjInstProperty6(enemy_prop6); //и врага //проходим по циклу из всех врагов, которые есть в сцене for ( int iEnemy = 0; iEnemy < m_i_enemy_creatures_num; iEnemy++ ) { //если с данным врагом столкновение еще не зафиксировано - if ( m_arr_EnemyCreatures[iEnemy].isCollided ) { //делаем вызов функции проверки столкновения m_arr_EnemyCreatures[iEnemy].bContactDetected = CollisionDetected6( heroProp->CollisionRectIndex, //индекс области столкновения (collision box) у игрока enemyProp->CollisionRectIndex, //тоже у врага &D3DXVECTOR2( m_v2_Scene_Pos.x, //координаты игрока на экране m_v2_Scene_Pos.y + 0.25f), //в координаты может вноситься поправка чтобы достичь //определенного эффекта - столкновения фиксировались бы вплотную или на некотором //расстоянии &D3DXVECTOR2( m_arr_EnemyCreatures[iEnemy].Pos.x - 0.05f, //координаты врага m_arr_EnemyCreatures[iEnemy].Pos.y), 1.0f, //масштаб игрока и врага 1.0f); if ( m_arr_EnemyCreatures[iEnemy].bContactDetected ) //если коллизия с врагом зафиксирована Damage_To_Player_By_Enemy_Creature(iEnemy); //вызываем метод который выполняет нанесение //урона игроку - в моем примере снижается индикатор прогресса в левом верхнем углу экрана //метод нужен отдельный т. к. в моем примере разные враги могут наносить немного разный //урон //ну и наконец, если как минимум одно или более столкновений зафиксировано //выставляем флаг столкновений в true m_bRiContactWithEnemyDetected |= m_arr_EnemyCreatures[iEnemy].bContactDetected; //еще может быть вариант когда нужно подсчитывать количество произошедших столкновений //но в данном примере я это не использую } } g_i_Test_Var_3 = (int)m_bRiContactWithEnemyDetected; //это вывод значения в отладочную переменную //на экран - чтобы убедиться - фиксация столкновений работает (1 - признак что столкновение было, 0 - нет) //собственно здесь можно (при желании) как раз поставить счетчик столкновений т. е. такой - if ( m_bRiContactWithEnemyDetected ) { m_b_Collisions_6_Count++; //предварительно объявив переменную в модуле gdess.h } //но здесь это показано лишь для демонстрации. В проекте dress я это не использовал. } Сам метод RiContactEnemy() в моем случае вызывается тут - void CGdess::Move_Enemy_Creatures() { //... RiContactEnemy(); то есть в методе осуществляющем перемещения врагов по экрану. Враги переместились на шаг - и далее проверяется не столкнулся ли игрок с одним из врагов. Вот так это и работает. И наконец финальный штрих 5) В соответствии с фиксацией столкновения выпонять какие-либо игровые действия, например изменять полоску индикатора и если она достигла определенных значений, например 0 - вызывать экран Game over. Также выполнять какие-то еще необходимые действия. Просто покажу код метода Damage_To_Player_By_Enemy_Creature, который уже упоминался выше. void CGdess::Damage_To_Player_By_Enemy_Creature(int iEnemy) { //если индекс врага больше чем доступный - ничего не делаем if ( iEnemy < 0 || iEnemy > (m_i_enemy_creatures_num-1) ) return; //если враг не является видимым - ничего не делаем if ( !m_arr_EnemyCreatures[iEnemy].Visible ) return; //снижаем полоску индикатора на значение урона наносимого данным врагом m_f_Aim_Indicator_Percent = m_f_Aim_Indicator_Percent - m_arr_EnemyCreatures[iEnemy].fDamage * g_fElapsedTime * 0.15f; } Вот собственно и все. Как видите реализация столкновений не такое уж сложное действие, как может показаться на первый взгляд.
оцените статью:
0
0
megainformatic 2006 - 2024 карта сайта