CUmmObject 4 - Drive_n_GL - управление игровой моделью.

1) Краткое описание. Изменения с прошлых версий.
2) Новые функции (управление).
3) Применение OpenGL.
4) Пример решения - Drive_n_GL.

1) Краткое описание. Изменения с прошлых версий.

С предыдущих версий реализация CUmmObject претерпела следующие изменения :

1) Программая реализация класса теперь разбита на следующие файлы :
- cumm_file.h - определения класса, используемые константы и стуктуры.
- cumm_file.cpp - основные функции - загрузка, анимирование, математика .
- cumm_draw.cpp - отрисовка объекта с помощью USMMain141.dll.
- cumm_opengl.cpp - функции инициализации и отрисовки с помощью OpenGL .
- cumm_grarray.cpp - функции иниациализации графических массивов при работе с USMMain141.dll или данных OpenGL.

2) Изменен заголовок функции LoadObject - теперь в нее передаются (и затем хранятся внутри объекта) параметры о формате цвета и дополнительной длине строки плоскости вывода.

3) Добавлен ряд новых функций (см. ниже).

2) Новые функции (управление).
Новые функции представляют возможность устанавливать дополнительные повороты для сочленений скелета и получать информацию о состоянии сочленения (adb-функции), а также устанавливать "коэффициент масштабирования" - относительную скорость анимаций (ITS-функции).

Отрывки непосредственно из определения класса в файле usm_file.h:

	//-----------------------------------------------------------------------------------
	// adb - функции

	//получить номер joint с указанным именем (-1, если такого нет)
	int adbCatchBone (char* name) ;

	//поставить пределы добавок
	BOOL adbSetMinMax (int ijoint, BOOL amm, float ammmin, float ammmax,
		BOOL mmm, float mmmmin, float mmmmax) ;

	//изменить/получить значение угла
	BOOL adbSetAngle (int ijoint, float val, int type) ;
	float adbGetAngle (int ijoint) ;

	//изменить/получить значение удлиннения
	BOOL adbSetMul (int ijoint, float val, int type) ;
	float adbGetMul (int ijoint) ;

	//получить матрицу поворота и текущее положение кости
	BOOL adbGetJointData (int ijoint, MATRIX* m, POINT3d& p) ;

	//-----------------------------------------------------------------------------------
	// ITS - функции

	//установить границы коэффициента масштабирования
	void   SetITSMinMax (BOOL bset, float tmin, float tmax) ;

	//изменить коэффициент масштабирования
	void   SetITS (float its, int type) ;

	//получить значение коэффициента масштабирования
	float  GetITS () {return itimescale;} ;


	//-----------------------------------------------------------------------------------
	// OpenGL
	
	//отрисовать через OpenGL
	void glDraw (int cx, int cy) ;

	//инициализация / деинициализация объекта для OpenGL
	BOOL InitForOpenGL () ;
	void DeInitForOpenGL () ;
Все неясности разбираются ниже, в примере.

3) Применение OpenGL.
Для реализации OpenGL - отрисовки был добавлен ряд функций в класс, указанный выше и функция инициализации графики в файл usm_grarray.cpp - InitGlobalOpenGL (hwnd).

Эти добавки были сделаны для демонстрации альтернативных методов отрисовки CUmmObject и не претендуют на на полную правильность работы с OpenGL. Если у Вас есть замечания по поводу исполнения этих функций, я буду рад их прослушать и прилюдно озвучить (посыпав голову пеплом, ежели нужно :).

4) Пример решения - Drive_n_GL.

Рассмотрим применение CUmmObject в программе Drive_n_GL (см. рисунок) :

1) Модели машины и персонажа представлены двумя различными .mod файлами.
2) Модели независимо выполняют анимации.
3) Модель стрелка "сидит в машине" - т.е. она своим началом координат "привязана" к сочленению машины, выделенному зеленым кругом.
4) Колеса машины (желтые круги), весь корпус и стрелок поворачиваются и накреняются при управлении поворотом от пользователя.
5) Колеса машины (фиолетовые круги) "аммортизируют" подпрыгивая в ухабах дороги.
6) При продолжительном удержании стрелки "вверх", машина ускоряет ход.



Итак, в первую очередь заводим переменные для моделей и определяем используемые callback-функции:
CUMDrawData drawdata ;        //данные проецирования
CUmmObject *c_niva = NULL ;   //машина
CUmmObject *c_opfor = NULL ;  //человечек
int opfor_j ;                 //это -
int car_j [6] ;               //    индексы сочлелений скелета
BOOL move = FALSE ;           //флаги
BOOL stop = FALSE ;
BOOL shot = FALSE ;

//после анимации остановки машины
void StopCar (void)
{
	if (!move)
		c_niva -> Stop () ;
	else
		c_niva -> SetAnimation (AT_SKELETON, "move", AF_ENDFRAME, 0, StartCar) ;		
	stop = FALSE ;
}

//после анимации старта машины
void StartCar (void)
{
	if (move)
		c_niva -> SetAnimation (AT_SKELETON, "move", AF_CYCLED, 0, NULL) ;
	else
		c_niva -> SetAnimation (AT_SKELETON, "stop", AF_ENDFRAME, 0, StopCar) ;
}

//после анимации выстрела человечка
void ManShot (void)
{
	if (shot)
		c_opfor -> SetAnimation (AT_SKELETON, "shot", AF_ENDFRAME, 0, ManShot) ;
	else
		c_opfor -> SetAnimation (AT_SKELETON, "idle", AF_CYCLED, 0, NULL) ;
}
//----------------------------------------------------------

Далее, установив параметры графики одной из функций файла usm_grarray, вызываем следущую функцию загрузки объектов :

void InitObject ()
{
	//загрузить джип
	c_niva = new CUmmObject () ;	
	c_niva -> LoadObject ((bpajero) ? "pj.mod" : "tlc.mod", LOAD_ALL, cumm_bit1516, global_pitch) ;
	c_niva -> SetDrawData (drawdata) ;
	c_niva -> SetBaseState () ;
	c_niva -> SetITSMinMax (TRUE, 0.5f, 4.0f) ;

	//получить номера нужных сочленений
	car_j [0] = c_niva -> adbCatchBone ("lf_joint") ;
	car_j [1] = c_niva -> adbCatchBone ("lb_joint") ;
	car_j [2] = c_niva -> adbCatchBone ("rf_joint") ;
	car_j [3] = c_niva -> adbCatchBone ("rb_joint") ;
	car_j [4] = c_niva -> adbCatchBone ("prodol_j") ;
	car_j [5] = c_niva -> adbCatchBone ("man_place") ;

	//установить пределы изменений
	c_niva -> adbSetMinMax (car_j [0], TRUE, -1.0f, 1.0f, FALSE, 0, 0) ;
	c_niva -> adbSetMinMax (car_j [2], TRUE, -1.0f, 1.0f, FALSE, 0, 0) ;
	c_niva -> adbSetMinMax (car_j [4], TRUE, -0.06f, 0.06f, FALSE, 0, 0) ;

	//то же для человечка
	c_opfor = new CUmmObject () ;
	c_opfor -> LoadObject ("opfor.mod", LOAD_ALL, cumm_bit1516, global_pitch) ;
	c_opfor -> SetDrawData (drawdata) ;
	c_opfor -> SetAnimation (AT_SKELETON, "idle", AF_CYCLED, 0, NULL) ;

	opfor_j = c_opfor -> adbCatchBone ("main") ;
	c_opfor -> adbSetMinMax (opfor_j, TRUE, -1.0f, 1.0f, FALSE, 0, 0) ;

	//ежли OpenGL - проинициализировать
	if (opengl_enabled)
	{
		c_opfor -> InitForOpenGL () ;
		c_niva -> InitForOpenGL () ;
	}
}

Управление состоянием объектов в цикле обработки сообщений окна определяется так :

	case WM_KEYDOWN :
		switch (LOWORD (wParam))
		{		
		case VK_UP : //увеличить скорость
			if (!move)
			{
				move = TRUE ;
				c_niva -> SetAnimation (AT_SKELETON, "start", AF_ENDFRAME, 0, StartCar) ;
			}
			else
			{
				c_niva -> SetITS (0.2f, ADB_COMPAREIT) ;
			}
			break ;
		case VK_DOWN : //затормозить
			if (move)
			{
				c_niva -> SetITS (-2.0f, ADB_COMPAREIT) ;
				
				if (c_niva -> GetITS () <= 1.0f)
				{
					c_niva -> SetITS (1.0f, ADB_ABSOLUTE) ;

					move = FALSE ;
					stop = TRUE ;
					c_niva -> SetAnimation (AT_SKELETON, "stop", AF_ENDFRAME, 0, StopCar) ;
				}
				
			}
			break ;

		case VK_LEFT : //поворот влево
			c_niva -> adbSetAngle (car_j [0], 0.05f, ADB_COMPAREIT) ;
			c_niva -> adbSetAngle (car_j [2], 0.05f, ADB_COMPAREIT) ;
			c_niva -> adbSetAngle (car_j [4], 0.003f, ADB_COMPAREIT) ;
			c_opfor -> adbSetAngle (opfor_j, -0.05f, ADB_COMPAREIT) ;
			break ;
		case VK_RIGHT : //поворот вправо
			c_niva -> adbSetAngle (car_j [0], -0.05f, ADB_COMPAREIT) ;
			c_niva -> adbSetAngle (car_j [2], -0.05f, ADB_COMPAREIT) ;
			c_niva -> adbSetAngle (car_j [4], -0.003f, ADB_COMPAREIT) ;
			c_opfor -> adbSetAngle (opfor_j, 0.05f, ADB_COMPAREIT) ;
			break ;		
		case VK_CONTROL : //стрелять
			shot = TRUE ;
			c_opfor -> SetAnimation (AT_SKELETON, "shot", AF_ENDFRAME, 0, ManShot) ;
			break ;
		case VK_ESCAPE : SendMessage (hwnd, WM_CLOSE, 0, 0) ; break ;
		}
		return 0 ;

Ну и наконец, расчет положения и вывод на экран :

void DrawAll ()
{
	static MATRIX rot_matrix, matrix, matrix2 ;
	//определить время
	int the_time = GetTickCount () ;
	int delta = the_time - time ;
	time = the_time ;

	//------------------------------------------------------------
	if (move)
	{
		//колеса дергаются вверх и вниз
		c_niva -> adbSetMul (car_j [0], (rand () % 10) * (0.02f), ADB_ABSOLUTE) ;
		c_niva -> adbSetMul (car_j [1], (rand () % 10) * (0.02f), ADB_ABSOLUTE) ;
		c_niva -> adbSetMul (car_j [2], (rand () % 10) * (0.02f), ADB_ABSOLUTE) ;
		c_niva -> adbSetMul (car_j [3], (rand () % 10) * (0.02f), ADB_ABSOLUTE) ;
	}

	//------------------------------------------------------------
	if (move || stop) //общий поворот сцены по y оси
		mouse_b -= c_niva-> GetITS () * 0.0005f * delta * c_niva -> adbGetAngle (car_j [0]) ;

	//установить матрицы машины
	SetMRotateG (&rot_matrix, mouse_g) ;	
	SetMRotateB (&matrix, mouse_b) ;
	rot_matrix = *MulMatrix (&rot_matrix, &matrix) ;

	c_niva -> IdentityMatrix () ;
	c_niva -> SetMatrix (&rot_matrix, TRUE) ;
	c_niva -> Tick (delta, FALSE) ;
	c_niva -> UseMatrixSettings () ;
	
	//установить матрицы человечка
	c_opfor -> IdentityMatrix () ;

	//повернуть модель человечка на 90' (в файле она ориентирована не так, как надо :)
	SetMRotateB (&matrix, -1.57f) ;
	c_opfor -> SetMatrix (&matrix, TRUE) ;

	//получить данные о нужном сочленении машины и применить их к человечку
	POINT3d p ;
	if (c_niva -> adbGetJointData (car_j [5], &matrix, p))
	{
		c_opfor -> SetMatrix (&matrix, TRUE) ;

		SetMMove (&matrix, p.x, p.y, p.z) ;	
		c_opfor -> SetMatrix (&matrix, FALSE) ;
	}

	SetMRotateG (&rot_matrix, mouse_g) ;	
	SetMRotateB (&matrix, mouse_b) ;
	rot_matrix = *MulMatrix (&rot_matrix, &matrix) ;
	c_opfor -> SetMatrix (&rot_matrix, TRUE) ;

	c_opfor -> Tick (delta, FALSE) ;
	c_opfor -> UseMatrixSettings () ;
	
	//-------------------------------------------------------------
	// отрисовка
	if (opengl_enabled)
	{
		float* pf = GetR_G_Bfloat (clr_color) ;
		glClearColor (pf [0], pf [1], pf [2], 1.0f) ;

		glClear(GL_COLOR_BUFFER_BIT);
		glClear(GL_DEPTH_BUFFER_BIT);

		c_opfor -> glDraw (cxV, cyV) ;
		c_niva -> glDraw (cxV, cyV) ;
		
		glFlush();
		SwapBuffers(wglGetCurrentDC());
	}
	else
	{
		CleareBuffers () ;

		c_opfor -> dxDraw (dbuffer, zbuffer, cxV, cyV) ;
		c_niva -> dxDraw (dbuffer, zbuffer, cxV, cyV) ;

		int dsize = cxV*cyV*video_byte + cyV*global_pitch ;
		SetBitmapBits (hbmp, dsize, dbuffer) ;

		HDC hdc = GetDC (Ghwnd) ;
		BitBlt (hdc, 0, 0, cxV, cyV, memdc, 0, 0, SRCCOPY) ;
		ReleaseDC (Ghwnd, hdc) ;	
	}
}

Ну вот и все!

Hosted by uCoz