Программирование игр для Windows. Советы профессионала

       

Программа Астероиды с использованием матриц


Я уже устал от разговоров — давайте что-нибудь напишем. К примеру, перепишем нашу программу из Листинга 4.8. Вы должны ее помнить. Мы ее переделаем и используем в ней матрицы. Листинг 4.11 показывает эту программу. Она называется «Супер Астероиды».

Листинг 4.11. Супер Астероиды (FIELD.C).

// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ///////////////////////////////////////////

#include <stdio.h>

#include <graph.h>

#include <math.h>

//ОПРЕДЕЛЕНИЯ ///////////////////////////////////////////////

#define NUM__ASTEROIDS 10

#define ERASE 0

#define DRAW 1

#defineX_COMP 0

#define Y_COMP 1

#define N_COMP 2



// СТРУКТУРЫ ДАННЫХ ////////////////////////////////////

// новая структура, описывающая вершину

typedef struct vertex_typ

{

float p[3]; // единичная точка в двумерном пространстве

//и фактор нормализации

} vertex, *vertex_ptr;

// общая структура матрицы

typedef struct matrix_typ

{

float elem[3] [3]; // массив для хранения элементов

// матрицы

} matrix, *matrix_ptr;

// определение структуры "объект",.

typedef struct object_typ

{    

int num_vertices;     // количество вершин в объекте

int color;            // цвет объекта

float xo,yo;          // позиция объекта

float x_velocity;     // скорости пермещения по осям Х float y_velocity;

// и Y matrix scale;         // матрица масштабирования

matrix rotation;      // матрицы поворота и перемещения

vertex vertices[16];  // 16 вершин

} object, *object_ptr;

// ГЛОБАЛЬНЫЕ.ПЕРЕМЕННЫЕ /////////////////////////////////

object asteroids [NUM_ASTEROIDS] ;

// ФУНКЦИИ ////////////////////////////////////////////

void Delay(int t)

{

// функция выполняет некоторую задержку

float x = 1;

while(t—>0)

x=cos(x) ;

} // конец функции

///////////////////////////////////////////////////////

void Make_Identity(matrix_ptr i)

{

// функция формирует единичную матрицу

i->elem[0][0] = i->elem[l][1] = i->elem[2][2] = 1;

i->elem[0][1] = i->elem[l][0] = i->elem[l][2] = 0;

i->elem[2][0] = i->elem[01[2] = i->eiem[2][1] = 0;




} // конец функции ///////////////////////////////////////////////////////

void Clear_Matrix(matrix_ptr m) {

// функция формирует нулевую матрицу

m->е1еm[0][0] = m->elem[l][1] = m->е1еm[2][2] = 0;

m->elem[0][1] = m->elem[l] [0] = m->е1еm[1] [2] = 0;

m->elem[2][0] = m->elem[0] [2] = m->elem[2][1] = 0;

} // конец

функции

///////////////////////////////////////////////////////

void Mat_Mul (vertex_ptr v, matrix_ptr m)

{

 // функция выполняет умножение матрицы 1х3 на матрицу 3х3

// элемента. Для скорости каждое действие определяется "вручную",

// без использования циклов. Результат операции - матрица 1х3

float x new, у

new;

x_new=v->p[0]*m->elem[0][0] + v->p[1]*m->elem[1][0] + m->elem[2][0];

y_new=v->p[0]*m->elem[0][1] + v->p[1]*m->elem[1][1] + m->elem[2][1];

// N_COMP - всегда единица

v->p[X_COMP] = x_new;

v->p[Y_COMP] = y_new;

} // конец

функции

///////////////////////////////////////////////////////

void Scale_Object_Mat(object_ptr obj)

{

// функция выполняет масштабирование объекта путем умножения на

// матрицу масштабирования

int index;

for (index=0; index<obj->num_vertices; index++)

{

Mat_Mul ((vertex_ptr) &obj->vertices [index],

(matrix_ptr)&obj->scale) ;

} // конец цикла for

} // конец функции

///////////////////////////////////////////////////////

Rotate_Object_Mat(object_ptr obj)

{

// функция выполняет.поворот объекта путем умножения на

// матрицу поворота

int index;

for (index=0; index<obj->num_yertices; index++)

{

Mat_Mul((vertex_ptr)&obj->vertices[index],(matrix_ptr)&obj->rotation) ;

} // конец цикла for

} // конец функции ///////////////////////////////////////////////////////

void Create_Field(void)

{      

int index;

float angle,c,s;

// эта функция создает поле астероидов

for (index=0; index<NUM_ASTEROIDS; index++)

{

asteroids[index].num vertices = 6;

asteroids [index] .color        = 1 + rand() % 14; //астероиды



// всегда

видимы

asteroids[index].xo           = 41 + rand() % 599;

asteroids[index].yo           = 41 + rand() % 439;

asteroids [index].,x_velocity   = -10 +rand() % 20;

asteroids[index].y_velocity   = -10 + rand() % 20;

// очистить

матрицу

Make_Identity((matrix_ptr)&asteroids[index].rotation) ;

// инициализировать матрицу вращений

angle = (float) (- 50 + (float) (rand ()\ % 100)) / 100;

c=cos(angle);

s=sin(angle);

asteroids[index].rotation.elem[0][0] = с;

asteroids[index].rotation.elem[0][1] = -s;

asteroids[index].rotation.elem[l][0] = s;

asteroids[index].rotation.elem[l][1] = с;

// формируем матрицу масштабирования

// очистить матрицу и установить значения коэффициентов

Make_Identity((matrix ptr)&asteroids[index].scale);

asteroids[index].scale.elem[0][0] = (float) (rand() % 30) / 10;

asteroids[index].scale.elem[1][1] = asteroids[index].scale.elem[0][0];

asteroids[index].vertices[0].p[X_COMP] = 4.0;

asteroids[index].vertices[0].p[Y_COMP] = 3.5;

asteroids[index].vertices[0].p[N_COMP] = l;

asteroids[index].vertices[1].p[X_COMP] = 8.5;

asteroids[index].vertices[l].p[Y_COMP) = -3.0;

asteroids[index].vertices[1].p[N_COMP] = l;

asteroids[index].vertices[2].p[X_COMP] = 6;

asteroids[index].vertices[2].p[Y_COMP] = -5;

asteroids[index].vertices[2].p[N_COMP] = l;

asteroids[index].vertices[3].p[X_COMP] = 2;

asteroids[index].vertices[3].p[Y_COMP] = -3;

asteroids[index].vertices[3].p[N_COMP] = l;

asteroids[index].vertices[4].p[X_COMP] = -4;

asteroids[index].vertices[4].p[Y_COMP] = -6;

asteroids[index].vertices[4].p[N_COMP] = 1;

asteroids[index].vertices[5].p[X_COMP] = -3.5;

asteroids[index].vertices[5].p[Y_COMP] = 5.5;

asteroids[index],vertices[5].p[N_COMP] = 1;

// теперь масштабировать астероиды

Scale_Object_Mat((object_ptr)&asteroids[index]);

} // конец цикла for

} // конец функции

///////////////////////////////////////////////////////

void Draw Asteroids (int erase)

{

int index,vertex;

float xo,yo;

// эта функция в зависимости от переданного флага рисует или стирает



// астероиды

for (index=0; index<NUM_ASTEROIDS; index++)

{

// нарисовать астероид

if (erase==ERASE)

_setcolor(0);

else

_setcolor(asteroids[index].color);

// получаем позицию объекта

xo = asteroids[index].xo;

yo = asteroids [index].yo;

// перемещаемся в позицию первой вершины астероида

_moveto((int)(xo+asteroids[index]-vertices[О].p[X_COMP]), (int)(yo+asteroids[indexl.vertices[0].p[Y_COMP])) ;

for (vertex=l; vertex<asteroids[index].num_vertices; vertex++)

{

_lineto((int)(xo+asteroids[index].vertices[vertex].p[X_COMP]), (int)(yo+asteroids[index].vertices[vertex].p[Y_COMP])) ;

} // конец цикла по вершинам

_lineto((int)(xo+asteroids[index].vertices[0],p[X_COMP]), (int)(yo+asteroids[index].vertices[0].p[Y_COMP]));

} // замкнуть контур объекта

} // конец функции

///////////////////////////////////////////////////////

void Translate_Asteroids(void)

{

// функция перемещает астероиды

int index;

for (index=0; index<NUM_ASTEROIDS; index++)

{

// перемещать текущий астероид

asteroids[index].xo += asteroids[index].x velocity;

asteroids[index].yo += asteroids[index].y_velocity;

// проверка на выход за границы экрана

if (asteroids[index].xo > 600 || asteroids[index].xo < 40)

{

asteroids[index].x_velocity = -asteroids[index].x_velocity;

asteroids[index].xo += asteroids[index].x_velocity;

      }        

if (asteroids[index].yo > 440 1) asteroids[index].yo < 40)

{

asteroids[index].y_velocity = -asteroids[index].y_velocity;

asteroids[index].yo += asteroids[index].у_velocity;

)

} // конец цикла for

} // конец функции

////////////////////////////////////////////////////////

void Rotate__Asteroids()

{

int index;

for (index=0; index<NUM_ASTEROIDS; index++)

{

// вращать

текущий астероид

Rotate_Object_Mat((object_ptr)&asteroids[index]);

} // конец цикла for

} // конец функции                       

///////////////////////////////////////////////////////

void main(void)

{

// перевести компьютер в графический режим



_setvideomode(_VRES16COLOR); // 640х480, 16 цветов

// инициализация

Create_Field();

while(!kbhit())

{

// стереть

поле

Draw_Asteroids(ERASE) ;

// преобразовать

поле

Rotate_Asteroids();

Translate_Asteroids() ;

// нарисовать

поле

Draw_Asteroids(DRAW);

// немного подождем...

Delay(500);

)

// перевести компьютер в текстовый режим

_setvideomode(_DEFAULTMODE);

} // конец функции

Вам потребуется время, чтобы изучить эту программу. Уделите внимание способу, которым астероиды масштабируются и поворачиваются. Если вы сравните время исполнения программ из Листингов 4.8 и 4.11, то не найдете никакой разницы. Если же вы потратите время и поместите все повороты, масштабирование и перемещение в одну матрицу, то программа из Листинга 4,11 будет работать значительно быстрее.

Итак, умножение матриц особенно эффективно, когда вы производите множественные трансформации объекта с помощью единой, заранее подготовленной матрицы, включающей в себя все операции преобразования над этим объектом.


Содержание раздела