Главная Случайная страница


Полезное:

Как сделать разговор полезным и приятным Как сделать объемную звезду своими руками Как сделать то, что делать не хочется? Как сделать погремушку Как сделать так чтобы женщины сами знакомились с вами Как сделать идею коммерческой Как сделать хорошую растяжку ног? Как сделать наш разум здоровым? Как сделать, чтобы люди обманывали меньше Вопрос 4. Как сделать так, чтобы вас уважали и ценили? Как сделать лучше себе и другим людям Как сделать свидание интересным?


Категории:

АрхитектураАстрономияБиологияГеографияГеологияИнформатикаИскусствоИсторияКулинарияКультураМаркетингМатематикаМедицинаМенеджментОхрана трудаПравоПроизводствоПсихологияРелигияСоциологияСпортТехникаФизикаФилософияХимияЭкологияЭкономикаЭлектроника






Листинг 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 будет работать значительно быстрее.

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

К вашему сведению

Запомните, что все это мы делаем для того, чтобы научиться писать видеоигры, особенно трехмерные. И делаем мы это постепенно. Если я вам сразу покажу, как писать игры типа Wolfenstein 3-D или DOOM, то мы многое потеряем в тактике и философии разработки и создания игр.

Если же вы настоящий разработчик игр, то уже в данный момент должны думать,о том, как переделать те программы, которые я дал, в настоящую игру. Не беспокойтесь! Мне и в голову не приходит сказать: «В качестве упражнения перепишите программу из Листинга 4.11 в настоящую игру». Мы напишем игру вместе, но чуть позже. Лучше поговорим о том, какие изменения нам надо внести, чтобы игра получилась.

Если вы хотите узнать, как я бы переделывал Листинг 4.8 в настоящую игру, то я бы сделал следующее:

§ Оснастил программу всем необходимым для выполнения миссии. Ведь нужно иметь маневренный космический корабль, несколько ракет для уничтожения астероидов, а чтобы игра приняла «товарный» вид, нужна система подсчета очков, заставка и, конечно, возможность выхода из программы. Кроме перечисленного потребуется создать систему оповещения о столкновениях с астероидами (такая система будет рассмотрена чуть позже, в этой же главе);

§ Далее я подготовил бы свой корабль. Для этого описал бы объект, который позаимствовал, например, из игры Star Trek;

§ Написал бы подпрограмму для рисования и уничтожения корабля (типа функции DrawAsteroids из Листинга 4.11);

§ Разработал бы функции, позволяющие игроку управлять кораблем;

§ Написал бы функции, которые, в зависимости от состояния клавиатуры, вращали корабль по или против часовой стрелки. Это я сделал бы, изменяя величину angles в структуре, описывающей объект корабля;

§ Потом мне понадобился бы способ передвижения корабля. Для этого я бы изменял значения x_velocity и y_velocity в соответствующих функциях:

x_veiocity = cos(angle)*speed

y_velocity = sin(angle)*speed

§ где скорость изменялась бы при нажатии на определенные клавиши;

§ Чтобы ввести корабль в игру, я поместил бы вызов функции стирания всех графических объектов - корабля и астероидов - в одно и то же место. Затем поместил бы функцию движения, которая опрашивает клавиатуру, в середину программы (между вызовом функций стирания и рисования);

§ В самый конец цикла вставил бы функцию рисования корабля.

Вот, собственно, и все. Выглядит не очень сложно. Посмотрим, что дальше.

Основы контроля столкновений

Давайте забудем про оружие и посмотрим, что произойдет, если нас заденет астероид (я слышал, они очень твердые). Для этого нам надо создать систему контроля столкновений.

Это значит, что нам надо сделать зримым соударение космического корабля с астероидом. Правильнее всего будет поступить так:

1. Забыть о реальных границах астероида и корабля и создать виртуальную граничную область вокруг каждого объекта исключительно для тестовых целей. Не надо ее рисовать, достаточно, чтобы она присутствовала внутри программы. Рисунок 4.10 показывает, что я имею в виду.

2. Если мы увидим, что граничная область нашего судна вошла в граничную область астероида, мы можем сказать, что наш корабль уничтожен. Это довольно просто сделать: достаточно сравнить каждую вершину области с вершиной другой области. Если есть вхождение, значит произошло столкновение.

3. Теперь, когда столкновение зафиксировано, нужно произвести на экране какой-нибудь красочный эффект: 500-тонный корабль с двигателем на антивеществе врезается в астероид. Например, вспышки случайных точек. Это будет неплохо смотреться.

4. Подсчет очков прост: создайте переменную score и печатайте ее на экране каждый раз, проходя через главный цикл. Вы можете использовать функцию _outtext () из библиотеки Си.

Кроме этого, нам надо набирать очки. Значит, нужно иметь оружие. Например, корабль в игре может использовать фотонные торпеды — маленькие точки. Чтобы их получить, нам надо:

1. Назначить одну из клавиш (лучше Пробел ) для стрельбы.

2. Когда будет обнаружено нажатие на клавишу, определить несколько переменных, в которых запомнить направление движения корабля (miss_xv и miss_yv).

3. Затем запомнить в двух переменных исходную позицию ракеты, то есть координаты центра корабля (miss_x и miss_y).

4. Присвоить переменной life значение 100.

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

6. Уменьшить значение переменной life, и если она стала равна нулю, то уничтожить ракету и дать возможность игроку выстрелить следующий раз.

ИТОГ

Эта глава могла бы оказаться в сотни раз больше. У меня действительно была задача провести краткий курс двухмерной графики. Мы узнали много новых концепций и терминов. Теперь мы знаем, как производить простые преобразования объектов и точек на плоскости. Мы также узнали о матрицах (даже несколько больше, чем нужно) и как они могут быть использованы в компьютерной графике и видеоиграх для упрощения геометрических преобразований и придания им более компактной формы. В конце мы даже увидели поле астероидов на экране. Я уверен, что у вас есть много вопросов. Наверное, даже больше, чем в начале изучения этой книги. Я постараюсь ответить на них в дальнейшем. Но прошу вас помнить, что не существует простых и быстрых правил для написания игр. Это не сортировка массива. Нам, как программистам, нужен набор различных трюков для реализации наших идей, а посему продолжим работу.


Date: 2015-09-18; view: 370; Нарушение авторских прав; Помощь в написании работы --> СЮДА...



mydocx.ru - 2015-2024 year. (0.005 sec.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав - Пожаловаться на публикацию