на Главную Вход Регистрация Забыли пароль ?

skype: megainformatic, телеграм: megainformatic, онлайн-чат (megainformatic live chat), форма обратной связи

Онлайн Школа Компьютерных Наук Андрея Синицина

Онлайн Школа Компьютерных Наук Андрея Синицина - автор

Добро пожаловать в нашу школу ! Давайте вместе откроем путь к новым перспективам !!!

Fle game engine - реализация коллизий на примере проекта Многоликий: dress




О реализации столкновений на движке fle game engine я уже рассказывал в статье Проверка столкновений

В упомянутой статье предполагалось, что у вас перед глазами открыт исходный код проекта и Вы можете
его посмотреть.

Сейчас мы рассмотрим более общий пример реализации коллизий. И в качестве примера
будет рассказано о том, как реализуются коллизии в игре Многоликий: dress.


проверка столкновений между врагами и персонажем в игре Многоликий: 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 карта сайта




Посетили страницу: 183