Разработка игры "Frag the monster"

Тип работы:
Курсовая
Предмет:
Программирование


Узнать стоимость

Детальная информация о работе

Выдержка из работы

Министерство образования и науки, молодежи и спорта Украины

Севастопольский национальный технический университет

Кафедра

Информационных систем

ПОЯСНИТЕЛЬНАЯ ЗАПИСКА

к курсовому проекту

на тему: Разработка игры «Frag the monster»

по курсу «Объектно-ориентированное программирование»

UA. 2 070 973-01 81 01

Проверила

асс. Сметанина Т. И.

Разработали

Ст. группы И-33д

Вовченко В.С., Бахтишаева Т. Э., Мельников О. Ю.

Севастополь, 2011

АННОТАЦИЯ

игра программирование

В документе описывается программа, написанная в соответствии с постановкой задачи на курсовое проектирование по теме «Frag the monster» по дисциплине «Объектно-ориентированное программирование». Программа осуществляет вывод на экран случайным образом врагов, основного игрока и дополнительных объектов, а именно оружия. Входными данными является нажатие клавиш управления и движений мыши основным игроком. Программа написана с использованием основных свойств объектно-ориентированного подхода.

Назначение программы — развлечение играющих, совершенствование их координации и логического мышления. Программа может применяться в качестве игры на разных типах персональных компьютеров.

Требованием к аппаратному и программному обеспечению является наличие любого IBM-совместимого компьютера с наличием накопителя на гибких и (или) жестких магнитных дисках, видеоадаптера класса VGA и наличием достаточного количества оперативной памяти (достаточно 10Мб). На компьютере должна быть установлена операционная система Windows 2000 либо выше.

СОДЕРЖАНИЕ

ВВЕДЕНИЕ

1 ПОСТАНОВКА ЗАДАЧИ

2 ОПИСАНИЕ МЕТОДА РАЗРАБОТКИ

2.1 Анализ проекта

2.1.1 Описание объектов

2.1.2 Построение иерархии классов

2.1.3 Построение модели процесса

2.1.4 Построение диаграмм переходов состояний

2.1.5 Жизненный цикл игры

2.1.6 Жизненный цикл игрока

2.1.7 Структурная схема алгоритма программы

2.2 Объектно-ориентированное проектирование

3 ПРОГРАМНАЯ РЕАЛИЗАЦИЯ

3.1 Обоснование выбора языка программирования

3.2 Описание основных классов

3.2. 1 Описание абстрактного класса Объект

3.2.2 Описание класса Игрок

3.2.3 Описание класса Враг

3.2.4 Описание класса Оружие

4 ОПИСАНИЕ ИНТЕРФЕЙСА ПРОГРАММЫ

4.1 Условия выполнения программы

4.2 Интерфейс программы

4.3 Критерий качества программы

ЗАКЛЮЧЕНИЕ

ПЕРЕЧЕНЬ ССЫЛОК

ПРИЛОЖЕНИЕ А

ВВЕДЕНИЕ

Документ содержит описание программы, написанной в Севастопольском национальном техническом университете на факультете Автоматики и вычислительной техники на кафедре Информационных систем в соответствии с постановкой задачи на курсовое проектирование по теме

«Frag the monster» по дисциплине «Объектно-ориентированное программирование». Программа осуществляет вывод на экран случайным образом врагов, основного игрока и дополнительных объектов, а именно оружия. Входными данными является нажатие клавиш управления и движений мыши основным игроком. Программа написана с использованием основных свойств объектно-ориентированного подхода.

Как известно, объектный подход — один из современных методов реализации программных систем. Наиболее показательна эффективность применения объектного подхода для больших программных систем, со сложным характером взаимодействия значительного количества элементов.

В курсовом проекте поставлена задача закрепления навыков применения объектно-ориентированного анализа к предметной области поставленной задачи, а так же реализовать объектную модель средствами объектно-ориентированного языка программирования С++.

Систематическое применение объектно-ориентированного подхода позволяет разрабатывать достаточно хорошо структурированные, надежные в эксплуатации, просто модифицируемые программные системы. Элементы объектно-ориентированного программирования получили свое развитие, и в настоящее время ООП принадлежит к числу ведущих технологий программирования.

1 ПОСТАНОВКА ЗАДАЧИ

Целью курсового проекта является разработка игры «Frag the monster». Создаются класс «объект» и два его наследника:

— «оружие»;

— «игрок» и его наследник: класс «враг».

Случайным образом на поле боя появляются враги. Задача игрока состоит в уничтожении врагов при помощи найденного им оружия. Управление игрой осуществляется при помощи клавиатуры и мыши.

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

2 ОПИСАНИЕ МЕТОДА РАЗРАБОТКИ

2.1 Анализ проекта

Используя результаты проведения ООА, а также возможностей среды программирования Microsoft Visual Studio 2008, были разработаны классы, необходимые для функционирования игры.

На первом этапе анализа необходимо сформулировать требования к курсовой работе. Программа должна иметь возможность посредством графического интерфейса отображать объекты смоделированной системы:

· Абстрактный класс (объект)

· Класс игрок

· Класс враг

· Класс оружие

Теперь, представив требования к системе, приступим к ее моделированию. Применение в данной курсовой работе объектно-ориентированного подхода позволит наиболее эффективно использовать средства языка C++ для разработки системы.

2.1.1 Описание объектов

Объектами в данной информационной модели, изображенной на рисунке 2. 1, являются:

- объект класса Игрок;

— объект класса Враг;

Для этих объектов вызываются методы, которые позволяют управлять действиями игровых элементов.

Отношение между врагами и игроком — «много к одному», так как врагов много, а игрок один.

Рисунок 2.1 — Информационная модель

2.1.2 Построение иерархии классов

Используя результаты проведения ООА, а также возможностей среды программирования Microsoft Visual Studio 2008 были разработаны классы, необходимые для функционирования системы.

Рисунок 2.2 — Иерархия классов

2.1.3 Построение модели процесса

Рисунок. 2.3 — Жизненный цикл программы.

2.1.4 Построение диаграмм переходов состояния

Следующим этапом проектирования, будет построение диаграмм переходов состояний (ДПС) для объектов системы, которые выражают описание жизненного цикла каждого объекта.

Рисунок 2.4 — ДПС для всех объектов системы

Действия системы начинается с запуска программы. Затем управляем действиями игрока для возможности игры.

На рисунке 2.4 изображена диаграмма переходов состояний (ДПС) для объектов системы, которые выражают описание жизненного цикла каждого объекта.

2.1.5 Жизненный цикл игры

Рисунок 2.5 — Жизненный цикл игры

А1 — Начало

А2 — Поиск оружия

А3 — Поиск врага

А4 — Конец игры

2.1.6 Жизненный цикл игрока

Рисунок 2.6 — Жизненный цикл игрока

А1 — Создание объекта

А2 — Сбор оружия

А3 — Уничтожение врагов

А4 — Смерть игрока

A5 — Выход

2.1.7 Структурная схема алгоритма программы

Рисунок 2.7 — Структурная схема алгоритма программы

2.2 Объектно-ориентированное проектирование

Процесс объектно-ориентированного проектирования является возвратным проектированием и состоит в идентификации классов и объектов, определения свойств этих классов и объектов с точки зрения взаимосвязей с другими классами и создания классов и объектов.

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

На базе построенных классов была реализована программа, реализующую игру «Frag The Monster». Дальнейшее описание основных методов и классов приводится в разделе «Программная реализация».

3 ПРОГРАМНАЯ РЕАЛИЗАЦИЯ

3.1 Обоснование выбора языка программирования

При выполнении курсового проекта была возможность выбора языка программирования из языков высокого уровня, таких как Python, Object Раsса1, С++, С и др. Для написания программы был выбран язык С++.

Язык С++ считается языком системного программирования, хотя он удобен и для написания прикладных программ. Среди преимуществ языка С++ следует отметить переносимость программ на компьютеры различной архитектуры и из одной операционной системы в другую, лаконичность записи алгоритмов, логическую стройность программ, а также возможность получить программный код, сравнимый по скорости выполнения с программами, написанными на языке ассемблера. Последнее связано с тем, что хотя С++ является языком высокого уровня, имеющим полный набор конструкций структурного программирования, он также обладает набором низкоуровневых средств, обеспечивающих доступ к аппаратным средствам компьютера. С 1989 года язык С++ регламентируется стандартом Американского института национальных стандартов ANSI С.

ООП дает программистам три важных преимущества. Первое состоит в упрощении программного кода и улучшении его структуризации. Программы стали проще для чтения и понимания. Код описания классов, как правило, отделен от кода основной части программы, благодаря чему над ними можно работать по отдельности, все это в свою очередь упрощает процесс отладки и сопровождения программы. Второе преимущество заключается в том, что модернизация программ становится несравнимо более простой задачей. Чаще всего она сводится к добавлению нового класса, который наследует все свойства одного из имеющихся классов и содержит требуемые дополнительные методы. Третье преимущество состоит в том, что одни и те же классы можно много раз использовать в разных программах. Удачно созданный класс можно сохранить отдельно в библиотечном файле, и его добавление в программу, как правило, не требует внесения серьезных изменений в текст.

3.2 Описание основных классов

3.2.1 Описание абстрактного класса Объект

class Object {

protected:

float x, z; // положение объекта

public:

Object (); // конструктор объекта

virtual float getX (); // получение положения по оси Х

virtual float getZ (); // получение положения по оси Z

virtual void setX (float x); // установка положения по оси Х

virtual void setZ (float z); // установка положения по оси Z

};

3.2.2 Описание класса Игрок

class Player: public Object {

protected:

float heading; // направление движения

public:

Player (); // конструктор

~Player (); // деструктор

bool charged; // флаг активности оружия

int killed, lifes; // количество очков, жизней

void setH (float heading); // установка направления движения

float getH (); // получение направления движения

};

3.2.3 Описание класса Враг

class Enemy: public Player {

private:

float speed, x_n, z_n; // скорость движ-я, коорд-ты конечной точки

bool moveflag; // флаг признака движения

public:

CMD2Model *model; // модель игрока

Enemy (); // конструктор

~Enemy (); // деструктор

void setMove (float x, float z); // ф-я установки координат движения

void move (); // ф-я инициализации движения

void spot (); // ф-я размещения врага на поле боя

bool OnPlace (); // ф-я проверки достижения координат движения

};

3.2.4 Описание класса Оружие

class Weapon: public Object {

public:

Weapon (); // конструктор

~Weapon (); // деструктор

void spot (); // ф-я размещения врага на поле боя

float rotate; // коэффициент вращения

bool active; // флаг активности

};

4 ОПИСАНИЕ ИНТЕРФЕЙСА ПРОГРАММЫ

Написанная программа является игрой и не несет в себе научно-познавательного содержания.

4.1 Условия выполнения программы

Программа может работать под управлением операционной системы Windows 2000, а также других, более новых, версиях ОС этого семейства.

Требованием к аппаратному и программному обеспечению является наличие любого IBM-совместимого компьютера с наличием накопителя на гибких или жестких магнитных дисках и наличием достаточного количества оперативной памяти.

4.2 Интерфейс программы

Рисунок 4.1 — Интерфейс программы

Для запуска программы необходимо запустить файл FragTheMonster. exe, после чего на экране появится главное окно программы, показанное на рисунке 4.1. Программа имеет простой и доступный интерфейс. Все данные необходимые для участия в игровом процессе указаны на экране. Управление игрой осуществляется при помощи клавиш, описанных в таблице 4.1.

Задача игрока — уничтожить 5 противников. Для их уничтожения необходимо подобрать оружие — желтый куб (рисунок 4. 2).

Рисунок 4.2 — Игровой куб

После захвата оружия игроку нужно атаковать врага, пробежав сквозь него, тем самым заработав очко (фраг) (рисунок 4. 3).

Рисунок 4.3 — Получение очка игроком

Однако если атаковать врага, не подобрав оружия, можно лишиться одной из трёх жизней (рисунок 4. 4).

У игры возможны два окончания: игрок уничтожает пять врагов и выигрывает (рисунок 4. 5), либо игрок теряет все три жизни и проигрывает (рисунок 4. 6).

Рисунок 4.4 — Потеря жизни игроком

Рисунок 4.5 — Конец игры, игрок выиграл

Рисунок 4.6 — Конец игры, игрок проиграл

Таблица 4.1 — Назначение клавиш

Название клавиши

Выполняемая функция

Стрелка вправо

Движение игрока вправо

Стрелка влево

Движение игрока влево

Стрелка вверх

Движение игрока вперед

Управление мышью

Изменение угла обзора

ESC

Выход из игры

F12

Смена полноэкранного/оконного режимов

4.3 Критерий качества программы

1. Критерии качества с точки зрения выполнения критериев объектно-ориентированного подхода:

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

— в достаточной степени достигнута реализация абстрагирования, полиморфизма и наследования.

2. С точки зрения функциональности:

— программа соответствует назначению, то есть, предназначена для игры;

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

3. С точки зрения надежности:

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

4. С точки зрения пригодности к использованию:

— программа обладает интуитивно понятным и простым интерфейсом;

— программа сопровождена описанием, которое поможет пользователю понять принципы ее работы.

5. С точки зрения эффективности:

— данный программный продукт обладает высоким быстродействием и коротким временем отклика;

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

6. С точки зрения сопровождаемости:

— программа пригодна к изменениям, то есть при появлении новых требований имеется возможность модифицирования программного кода;

— программа обладает стабильностью.

7. С точки зрения переносимости:

— программа обладает хорошей адаптируемостью и независимостью от устройств (способна работать на разнообразном аппаратном обеспечении);

— продукт не требует инсталляции, то есть осуществляется запуск. exe-файла.

ЗАКЛЮЧЕНИЕ

Программа разработана в соответствии с постановкой задачи курсового проектирования по дисциплине «Объектно-ориентированное программирование». При написании были использованы методические указания по курсовому проектированию по дисциплине «Объектно-ориентированное программирование». Интерфейс программы прост и удобен в пользовании. Тестирование программы подтвердило, что программа корректно выполняет взаимодействие объектов различных классов в соответствии с вариантом.

Программа, реализующая данную объектную модель, написана в соответствии с основными принципами объектно-ориентированного программирования. В процессе написания программы были закреплены и усовершенствованы навыков работы в среде Microsoft Visual Studio 2008.

Для разработки проекта были применены метод ООА и ООП, что дает программе возможность дальнейшего развития в более сложные программы на базе существующих классов. Подход ООП дал возможность быстро и легко разработать приложение, что говорит о необходимости изучения ООА всех специалистов, каким либо образом связанных с программированием.

ПЕРЕЧЕНЬ ССЫЛОК

1. Бадд Т. Объектно-ориентированное программирование в действии. Питер. 1997.

2. Бондарев В. Н. Основы программирования. — Харьков: «Фолио»; Ростов-на-Дону: «Феникс», 1998. — 368 с.

3. Буч Г. Объектно-ориентированное проектирование с примерами применения: Пер с англ. -М.: Конкорд, 1992. -519 с.

4. Доронина Ю. В. Конспект курса лекций по дисциплине «Объектно-ориентированное программирование».

5. Паппас К., Мюррей У. «Программирование на С и С++». — Киев: «Ирина», BHV, 2000. — 318 с.

6. Рейсдорф К., Хендерсон К. «Borland C. Освой самостоятельно» — М.: «БИНОМ», 1998 — 704с.

ПРИЛОЖЕНИЕ А

Текст программы FragTheMonster. cpp

#include «stdafx. h»

#include «OOP_KURS. h»

#include «timer. h»

IDirectInput8*g_DI; // Direct Input

IDirectInputDevice8*g_KDIDev; // клавиатура

HDChDC = NULL; // приватный контекст устройства GDI

HGLRC hRC = NULL; // постоянный контекст рендеринга

HWND hWnd = NULL; // дескриптор окна

HINSTANCEhInstance; // дескриптор приложения

BYTE buffer[256]; // буфер для операций с клавиатурой

boolactive = TRUE; // флаг активности окна, в true по умолчанию

boolfullscreen = TRUE; // флаг режима окна, в полноэкранный по умолчанию

boolfsb; // флаг нажатия клавиши F12

constfloat piover180 = 0. 17 453 2925f;

GLfloatyrot;

GLfloatwalkbias = 0;

GLfloatwalkbiasangle = 0;

GLfloatlookupdown = 0. 0f;

GLfloatz = 0. 0f;// углубление в экран

GLuint base;

GLYPHMETRICSFLOAT gmf[256];

GLuinttexture[6]; // массив под текстуры

SECTORsector[4];

WZONE*wzs;

int numwz;

POINT mpos; // позиция мыши

int adjust = 5; // корректировка скорости

// прототип функции WndProc

LRESULTCALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

Player player;

Enemy *enemy[5];

int enemy_count = 1;

Weapon weapon;

float frag_timer = 0, life_timer = 0, game_over = 0, win = 0, start = 0;

void TimerInit (void)// инициализация таймера

{

memset (& timer, 0, sizeof (timer)); // очистка структуры

// проверим доступность высокоточного таймера

// если доступен, то частота таймера будет задана

if (!QueryPerformanceFrequency ((LARGE_INTEGER *) & timer. frequency))

{// нет высокоточного таймера

timer. performance_timer = FALSE; // установим флаг высокоточного таймера в ЛОЖЬ

timer. mm_timer_start= timeGetTime (); // текущее время из timeGetTime ()

timer. resolution= 1. 0f/1000. 0f;// точность равна 0. 001f

timer. frequency= 1000; // частота равна 1000

timer. mm_timer_elapsed = timer. mm_timer_start; // прошедшее время равно текущему

} else {

// высокоточный таймер доступен, используем его вместо мультимедийного таймера

// взять текущее время и сохранить его в performance_timer_start

QueryPerformanceCounter ((LARGE_INTEGER *) & timer. performance_timer_start);

timer. performance_timer = TRUE; // Установить флаг наличия таймера в TRUE

// вычислить точность таймера, используя частоту

timer. resolution= (float) (((double)1. 0f)/((double)timer. frequency));

// присвоить прошедшему времени текущее время

timer. performance_timer_elapsed = timer. performance_timer_start;

}

}

float TimerGetTime ()// взять время в миллисекундах

{

__int64 time; // time содержит 64 бита

if (timer. performance_timer)// есть высокоточный таймер?

{

QueryPerformanceCounter ((LARGE_INTEGER *) & time);//захват текущего значения высокоточного таймера

// вернем текущее время минус начальное время, умноженное на точность и 1000 (для миллисекунд)

return ((float) (time — timer. performance_timer_start) * timer. resolution)*1000. 0f;

}

else

{

return ((float) (timeGetTime () — timer. mm_timer_start) * timer. resolution)*1000. 0f;

}

}

void readstr (FILE *f, char *string)

(string[0] == 'n'));

return;

void SetupWorld ()

{

float x, y, z, u, v;

int numtriangles;

FILE *filein;

char oneline[255];

char *fnm[4];

fnm[0] = «Data/World/sector1. txt»;fnm[1] = «Data/World/sector2. txt»;fnm[2] = «Data/World/sector3. txt»;fnm[3] = «Data/World/sector4. txt»;

for (int i = 0; i < 4; i++)

{

filein = fopen (fnm[i], «rt»);

readstr (filein, oneline);

sscanf (oneline, «NUM_TR %dn», & numtriangles);

sector[i]. triangle = new TRIANGLE[numtriangles];

sector[i]. numtriangles = numtriangles;

for (int loop = 0; loop < numtriangles; loop++)

{

readstr (filein, oneline);

sscanf (oneline, «%in», & sector[i]. triangle[loop]. texture);

for (int vert = 0; vert < 3; vert++)

{

readstr (filein, oneline);

sscanf (oneline, «%f %f %f %f %f %f %f», & x, & y, & z, & u, & v);

sector[i]. triangle[loop]. vertex[vert].x = x;

sector[i]. triangle[loop]. vertex[vert].y = y;

sector[i]. triangle[loop]. vertex[vert].z = z;

sector[i]. triangle[loop]. vertex[vert].u = u;

sector[i]. triangle[loop]. vertex[vert].v = v;

}

}

fclose (filein);

}

filein = fopen («Data/World/wzones. txt», «rt»);

readstr (filein, oneline);

sscanf (oneline, «NUM_P %dn», & numtriangles);

wzs = new WZONE[numtriangles];

numwz = numtriangles;

for (int loop = 0; loop < numtriangles; loop++)

{

readstr (filein, oneline);

sscanf (oneline, «%f %f», & x, & y);

wzs[loop].x = x;

wzs[loop].y = y;

}

fclose (filein);

return;

}

bool point_in (float x, float y)

{

static const int q_patt[2][2] = { {0,1}, {3,2} };

WZONE pred_pt, cur_pt;

pred_pt.x = wzs[numwz-1]. x;

pred_pt.y = wzs[numwz-1]. y;

pred_pt.x -= x;

pred_pt.y -= y;

int pred_q = q_patt[pred_pt.y < 0][pred_pt.x < 0];

int w = 0;

for (int i = 0; i < numwz; i++)

{

cur_pt.x = wzs[i]. x;

cur_pt.y = wzs[i]. y;

cur_pt.x -= x;

cur_pt.y -= y;

int q = q_patt[cur_pt.y < 0][cur_pt.x < 0];

switch (q — pred_q)

{

case -3:

++w;

break;

case 3:

--w;

break;

case -2:

if (pred_pt.x * cur_pt.y >= pred_pt.y * cur_pt. x)

++w;

break;

case 2:

if (!(pred_pt.x * cur_pt.y >= pred_pt.y * cur_pt. x))

--w;

break;

}

pred_pt = cur_pt;

pred_q = q;

}

return w ≠ 0;

}

AUX_RGBImageRec * LoadBMP (char *Filename)

{

FILE *File=NULL;

if (!Filename)

{

return NULL;

}

File = fopen (Filename, «r»);

if (File)

{

fclose (File);

return auxDIBImageLoadA (Filename);

}

return NULL;

}

int LoadGLTextures ()

{

int Status = FALSE;

AUX_RGBImageRec *TextureImage[6];

memset (TextureImage, 0, sizeof (void *)*6);

if ((TextureImage[0] = LoadBMP («Data/floor1. bmp»)) & &

(TextureImage[1] = LoadBMP («Data/light1. bmp»)) & &

(TextureImage[2] = LoadBMP («Data/rustyblue. bmp»)) & &

(TextureImage[3] = LoadBMP («Data/weirdbrick. bmp»)) & &

(TextureImage[4] = LoadBMP («Data/crate. bmp»))&&

(TextureImage[5] = LoadBMP («Data/weapon. bmp»)))

{

Status = TRUE;

glGenTextures (6, & texture[0]);

for (int loop1 = 0; loop1 < 6; loop1++)

{

glBindTexture (GL_TEXTURE_2D, texture[loop1]);

glTexImage2D (GL_TEXTURE_2D, 0, 3, TextureImage[loop1]-> sizeX, TextureImage[loop1]-> sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage[loop1]-> data);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

}

for (int loop1 = 0; loop1 < 6; loop1++)

{

if (TextureImage[loop1])

{

if (TextureImage[loop1]-> data)

{

free (TextureImage[loop1]-> data);

}

free (TextureImage[loop1]);

}

}

}

enemy[0] = new Enemy ();

enemy[0]-> model = new CMD2Model ();

enemy[0]-> model->LoadModel («Data/Models/Ogr. md2»);

enemy[0]-> model->LoadSkin («Data/Models/Ogr. pcx»);

enemy[0]-> model->SetAnim (STAND);

enemy[0]-> model->ScaleModel (0. 03);

enemy[0]-> spot ();

weapon. spot ();

return Status;

}

GLvoid ReSizeGLScene (GLsizei width, GLsizei height)

{

if (height == 0)

{

height = 1;

}

glViewport (0, 0, width, height);

glMatrixMode (GL_PROJECTION);

glLoadIdentity ();

gluPerspective (45. 0f,(GLfloat)width/(GLfloat)height, 0. 1f, 100. 0f);

glMatrixMode (GL_MODELVIEW);

glLoadIdentity ();

}

GLvoid BuildFont (GLvoid)

DEFAULT_PITCH,(LPCWSTR)L"Arial

SelectObject (hDC, font

wglUseFontOutlines (hDC, 0,256, base, 0. 0f, 0. 2f, WGL_FONT_POLYGONS, gmf);

GLvoid glPrint (float x, float y, float z, const char *fmt, …)

{

float length = 0;

char text[256];

va_list ap;

if (fmt == NULL)

return;
va_start (ap, fmt);

vsprintf (text, fmt, ap);

va_end (ap);

for (unsigned int loop=0; loop<(strlen (text));loop++)

length += gmf[(unsigned char) text[loop]]. gmfCellIncX;

glTranslatef (x, y, z);

glBindTexture (GL_TEXTURE_2D, 0);

glPushAttrib (GL_LIST_BIT);

glListBase (base);

glCallLists (strlen (text), GL_UNSIGNED_BYTE, text);

glPopAttrib ();

}

int InitGL (GLvoid)

{

if (!LoadGLTextures ())

{

return FALSE;

}

glEnable (GL_TEXTURE_2D);

glBlendFunc (GL_SRC_ALPHA, GL_ONE);

glClearColor (0. 0f, 0. 0f, 0. 0f, 0. 0f);

glClearDepth (1. 0f);

glDepthFunc (GL_LEQUAL);

glEnable (GL_DEPTH_TEST);

glShadeModel (GL_SMOOTH);

glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

BuildFont ();

SetupWorld ();

CTimer: :GetInstance ()->Initialize ();

player. setX (0);

player. setZ (-27);

player. setH (-180);

start = 1;

return TRUE;

}

int DrawGLScene (GLvoid)

{

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();

CTimer: :GetInstance ()->Update ();

float timesec = CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0;

GLfloat x_m, y_m, z_m, u_m, v_m;

GLfloat xtrans = -player. getX ();

GLfloat ztrans = -player. getZ ();;

GLfloat ytrans = -walkbias-0. 25f;

GLfloat sceneroty = 360. 0f — yrot;

int numtriangles;

glRotatef (lookupdown, 1. 0f, 0, 0);

glRotatef (sceneroty, 0, 1. 0f, 0);

glTranslatef (xtrans, ytrans, ztrans);

for (int i = 0; i < 4; i++)

{

numtriangles = sector[i]. numtriangles;

for (int loop_m = 0; loop_m < numtriangles; loop_m++)

{

glBindTexture (GL_TEXTURE_2D, texture[sector[i]. triangle[loop_m]. texture]);

glBegin (GL_TRIANGLES);

glNormal3f (0. 0f, 0. 0f, 1. 0f);

x_m = sector[i]. triangle[loop_m]. vertex[0]. x;

y_m = sector[i]. triangle[loop_m]. vertex[0]. y;

z_m = sector[i]. triangle[loop_m]. vertex[0]. z;

u_m = sector[i]. triangle[loop_m]. vertex[0]. u;

v_m = sector[i]. triangle[loop_m]. vertex[0]. v;

glTexCoord2f (u_m, v_m); glVertex3f (x_m, y_m, z_m);

x_m = sector[i]. triangle[loop_m]. vertex[1]. x;

y_m = sector[i]. triangle[loop_m]. vertex[1]. y;

z_m = sector[i]. triangle[loop_m]. vertex[1]. z;

u_m = sector[i]. triangle[loop_m]. vertex[1]. u;

v_m = sector[i]. triangle[loop_m]. vertex[1]. v;

glTexCoord2f (u_m, v_m); glVertex3f (x_m, y_m, z_m);

x_m = sector[i]. triangle[loop_m]. vertex[2]. x;

y_m = sector[i]. triangle[loop_m]. vertex[2]. y;

z_m = sector[i]. triangle[loop_m]. vertex[2]. z;

u_m = sector[i]. triangle[loop_m]. vertex[2]. u;

v_m = sector[i]. triangle[loop_m]. vertex[2]. v;

glTexCoord2f (u_m, v_m); glVertex3f (x_m, y_m, z_m);

glEnd ();

}

}

if (weapon. active) {

glTranslatef (weapon. getX (), -0. 2f, weapon. getZ ());

glRotatef (weapon. rotate, 1. 0f, 1. 0f, 1. 0f);

glBindTexture (GL_TEXTURE_2D, 6);

glBegin (GL_QUADS);

glVertex3f (0. 2f, 0. 2f,-0. 2f);

glVertex3f (-0. 2f, 0. 2f,-0. 2f);

glVertex3f (-0. 2f, 0. 2f, 0. 2f);

glVertex3f (0. 2f, 0. 2f, 0. 2f);

glVertex3f (0. 2f,-0. 2f, 0. 2f);

glVertex3f (-0. 2f,-0. 2f, 0. 2f);

glVertex3f (-0. 2f,-0. 2f,-0. 2f);

glVertex3f (0. 2f,-0. 2f,-0. 2f);

glVertex3f (0. 2f, 0. 2f, 0. 2f);

glVertex3f (-0. 2f, 0. 2f, 0. 2f);

glVertex3f (-0. 2f,-0. 2f, 0. 2f);

glVertex3f (0. 2f,-0. 2f, 0. 2f);

glVertex3f (0. 2f,-0. 2f,-0. 2f);

glVertex3f (-0. 2f,-0. 2f,-0. 2f);

glVertex3f (-0. 2f, 0. 2f,-0. 2f);

glVertex3f (0. 2f, 0. 2f,-0. 2f);

glVertex3f (-0. 2f, 0. 2f, 0. 2f);

glVertex3f (-0. 2f, 0. 2f,-0. 2f);

glVertex3f (-0. 2f,-0. 2f,-0. 2f);

glVertex3f (-0. 2f,-0. 2f, 0. 2f);

glVertex3f (0. 2f, 0. 2f,-0. 2f);

glVertex3f (0. 2f, 0. 2f, 0. 2f);

glVertex3f (0. 2f,-0. 2f, 0. 2f);

glVertex3f (0. 2f,-0. 2f,-0. 2f);

glEnd ();

weapon. rotate += 0. 8f;

}

glLoadIdentity ();

glRotatef (lookupdown, 1. 0f, 0, 0);

glRotatef (sceneroty, 0, 1. 0f, 0);

glTranslatef (xtrans, ytrans, ztrans);

glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);

for (int i = 0; i < enemy_count; i++) {

glTranslatef (enemy[i]-> getX (), -0. 25f, enemy[i]-> getZ ());

enemy[i]-> move ();

enemy[i]-> model->DrawModel (timesec);

if (i == enemy_count-1)

break;

glLoadIdentity ();

glRotatef (lookupdown, 1. 0f, 0, 0);

glRotatef (sceneroty, 0, 1. 0f, 0);

glTranslatef (xtrans, ytrans, ztrans);

}

if (enemy_count & & rand ()%1000 < 30) {

enemy[rand ()%enemy_count]-> setMove (player. getX (), player. getZ ());

}

glLoadIdentity ();

glClear (GL_DEPTH_BUFFER_BIT);

glPrint (-16. 0f, 11. 0f, -30. 0f, «FPS: %2. 2f», CTimer: :GetInstance ()->GetFps ());

glLoadIdentity ();

if (player. charged) {

glPrint (-8. 0f, -6. 0f, -15. 0f, «ATTACK!»);

} else {

glPrint (-8. 0f, -6. 0f, -15. 0f, «GET A CUBE!»);

}

glLoadIdentity ();

glPrint (6. 7f, -7. 0f, -20. 0f, «LIFES: %d», player. lifes);

glLoadIdentity ();

glPrint (6. 7f, -8. 0f, -20. 0f, «FRAGS: %d», player. killed);

if (frag_timer > 0) {

if ((frag_timer + 3) < (CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0))

frag_timer = 0;

else {

glLoadIdentity ();

glPrint (-1. 0f, 1. 0f, -10. 0f, «FRAG!»);

}

}

if (life_timer > 0) {

if ((life_timer + 3) < (CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0))

life_timer = 0;

else {

glLoadIdentity ();

glPrint (-2. 1f, -1. 0f, -10. 0f, «LOST LIFE!»);

}

}

if (game_over > 0) {

if ((game_over + 3) < (CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0))

game_over = 666;

else {

glLoadIdentity ();

glPrint (-2. 9f, 0. 0f, -6. 0f, «GAME OVER»);

}

}

if (win > 0) {

if ((win + 3) < (CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0))

win = 666;

else {

glLoadIdentity ();

glPrint (-2. 0f, -0. 1f, -6. 0f, «YOU WIN!»);

}

}

if (start > 0) {

if ((start + 5) < (CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0))

start = 0;

else {

glLoadIdentity ();

glPrint (-10. 0f, 5. 0f, -19. 0f, «FIND THE CUBE, THEN FRAG THE MONSTER!»);

glLoadIdentity ();

glPrint (-4. 0f, -4. 0f, -23. 0f, «FRAG 5 MONSTERS»);

glLoadIdentity ();

glLoadIdentity ();

glPrint (-10. 5f, -5. 0f, -20. 0f, «DON'T GET HIT BY THE MONSTER, OR YOU DIE!»);

}

}

return true;

}

GLvoid KillGLWindow (GLvoid)

{

if (fullscreen)

{

ChangeDisplaySettings (NULL, 0);

ShowCursor (TRUE);

}

if (hRC)

{

if (!wglMakeCurrent (NULL, NULL))

MessageBox (NULL,(LPCWSTR)L"Release Of DC And RC Failed. «,(LPCWSTR)L"SHUTDOWN ERROR», MB_OK

if (!wglDeleteContext (hRC))

MessageBox (NULL,(LPCWSTR)L"Release Rendering Context Failed. «,(LPCWSTR)L"SHUTDOWN ERROR», MB_OK

hRC = NULL;

}

if (hDC & & !ReleaseDC (hWnd, hDC))

MB_ICONINFORMATION);

hDC = NULL;

if (hWnd & & !DestroyWindow (hWnd))

MessageBox (NULL,(LPCWSTR)L"Could Not Release hWnd. «,(LPCWSTR)L"SHUTDOWN ERROR», MB_OK

if (!UnregisterClass ((LPCWSTR)L"OpenGL", hInstance))

MessageBox (NULL,(LPCWSTR)L"Could Not Unregister Class. «,(LPCWSTR)L"SHUTDOWN ERROR», MB_OK

}

BOOL CreateGLWindow (char* title, int width, int height, int bits, bool fullscreenflag)

{

GLuintPixelFormat;

WNDCLASSwc;

DWORDdwExStyle;

DWORDdwStyle;

RECTWindowRect;

WindowRect. left= (long)0;

WindowRect. right= (long)width;

WindowRect. top= (long)0;

WindowRect. bottom= (long)height;

fullscreen = fullscreenflag;

hInstance= GetModuleHandle (NULL);

wc. style= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;

wc. lpfnWndProc= (WNDPROC) WndProc;

wc. cbClsExtra= 0;

wc. cbWndExtra= 0;

wc. hInstance= hInstance;

wc. hIcon= LoadIcon (NULL, IDI_WINLOGO);

wc. hCursor= LoadCursor (NULL, IDC_ARROW);

wc. hbrBackground= NULL;

wc. lpszMenuName= NULL;

wc. lpszClassName= (LPCWSTR)L"OpenGL";

if (!RegisterClass (& wc))

MessageBox (NULL,(LPCWSTR)L"Failed To Register The Window Class. «,(LPCWSTR)L"ERROR», MB_OK

if (fullscreen)

{

DEVMODE dmScreenSettings;

memset (& dmScreenSettings, 0, sizeof (dmScreenSettings));

dmScreenSettings. dmSize= sizeof (dmScreenSettings);

dmScreenSettings. dmPelsWidth= width;

dmScreenSettings. dmPelsHeight= height;

dmScreenSettings. dmBitsPerPel= bits;

dmScreenSettings. dmFields= DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

if (ChangeDisplaySettings (& dmScreenSettings, CDS_FULLSCREEN) ≠ DISP_CHANGE_SUCCESSFUL)

{

if (MessageBox (NULL,(LPCWSTR)L"Полноэкранный режим не поддерживается вашей видеокартойnЗапустить в оконном режиме?",(LPCWSTR)L"Внимание", MB_YESNO|MB_ICONEXCLAMATION)==IDYES)

{

fullscreen = FALSE;

}

else

MB_ICONSTOP);

return FALSE;

}

}

ShowCursor (FALSE);

if (fullscreen)

{

dwExStyle= WS_EX_APPWINDOW;

dwStyle= WS_POPUP;

} else WS_EX_WINDOWEDGE;

dwStyle = WS_OVERLAPPEDWINDOW;

AdjustWindowRectEx (& WindowRect, dwStyle, FALSE, dwExStyle); if (!(hWnd=CreateWindowEx (dwExStyle,(LPCWSTR)L"OpenGL",

(LPCWSTR)L"Frag The Monster", dwStyle |WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, 0, WindowRect. right-WindowRect. left, WindowRect. bottom-WindowRect. top, NULL, NULL, hInstance, NULL)))

MB_ICONEXCLAMATION);

return FALSE;

staticPIXELFORMATDESCRIPTOR pfd=

PFD_SUPPORT_OPENGL;

if (!(hDC = GetDC (hWnd)))

KillGLWindow ();

MessageBox (NULL,(LPCWSTR)L"Can't Create A GL Device Context. «,(LPCWSTR)L"ERROR», MB_OK

if (!(PixelFormat=ChoosePixelFormat (hDC,& pfd)))

KillGLWindow ();

MessageBox (NULL,(LPCWSTR)L"Can't Find A Suitable PixelFormat. «,(LPCWSTR)L"ERROR», MB_OK

if (!SetPixelFormat (hDC, PixelFormat,& pfd))

KillGLWindow ();

MessageBox (NULL,(LPCWSTR)L"Can't Set The PixelFormat. «,(LPCWSTR)L"ERROR», MB_OK

if (!(hRC=wglCreateContext (hDC)))

KillGLWindow ();

MessageBox (NULL,(LPCWSTR)L"Can't Create A GL Rendering Context. «,(LPCWSTR)L"ERROR», MB_OK

if (!wglMakeCurrent (hDC, hRC))

MB_ICONEXCLAMATION);

return FALSE;

ShowWindow (hWnd, SW_SHOW);

SetForegroundWindow (hWnd);

SetFocus (hWnd);

ReSizeGLScene (width, height);

if (!InitGL ())

MB_ICONEXCLAMATION);

return FALSE;

return TRUE;

}

int DI_Init ()

{

if (DirectInput8Create (hInstance,

DIRECTINPUT_VERSION,

IID_IDirectInput8,

(void**)& g_DI,

NULL))

{

return (false);

}

if (g_DI-> CreateDevice (GUID_SysKeyboard,

& g_KDIDev,

NULL))

{

return (false);

}

if (g_KDIDev-> SetDataFormat (&c_dfDIKeyboard))

{

return (false);

}

if (g_KDIDev-> SetCooperativeLevel (hWnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE))

{

return (false);

}

if (g_KDIDev)

g_KDIDev-> Acquire ();

else

return (false);

return (true);

}

void DX_End ()

{

if (g_DI)

{

if (g_KDIDev)

{

g_KDIDev-> Unacquire ();

g_KDIDev-> Release ();

g_KDIDev = NULL;

}

g_DI-> Release ();

g_DI = NULL;

}

}

LRESULT CALLBACK WndProc (HWNDhWnd, UINTuMsg, WPARAMwParam, LPARAM lParam)

{

switch (uMsg)

{

case WM_ACTIVATE:

{

if (!HIWORD (wParam))

{

active = TRUE;

}

else

{

active = FALSE;

}

return 0;

}

case WM_SYSCOMMAND:

{

switch (wParam)

{

case SC_SCREENSAVE:

case SC_MONITORPOWER:

return 0;

}

break;

}

case WM_CLOSE:

{

PostQuitMessage (0);

return 0;

}

case WM_SIZE:

{

ReSizeGLScene (LOWORD (lParam), HIWORD (lParam));

return 0;

}

}

return DefWindowProc (hWnd, uMsg, wParam, lParam);

}

int WINAPI WinMain (HINSTANCEhInstance, HINSTANCEhPrevInstance, LPSTRlpCmdLine, intnCmdShow)

{

MSGmsg;

BOOLdone = false;

if (MessageBox (NULL,(LPCWSTR)L"Запустить в полноэкранном режиме?", (LPCWSTR)L"На весь экран?", MB_YESNO|MB_ICONQUESTION)==IDNO)

{

fullscreen = false;

}

if (!CreateGLWindow («Frag The Monster», 1024, 768, 32, fullscreen))

{

return 0;

}

if (!DI_Init ())

{

return 0;

}

TimerInit ();

while (!done)

{

if (PeekMessage (& msg, NULL, 0, 0, PM_REMOVE))

{

if (msg. message == WM_QUIT)

{

done = true;

}

else

{

TranslateMessage (& msg);

DispatchMessage (& msg);

}

}

else

{

float start = TimerGetTime ();

if ((active & & !DrawGLScene ()))

{

done = true;

}

else

{

if (game_over == 666 || win == 666)

done = true;

while (TimerGetTime () < start + float (adjust*2. 0f))

SwapBuffers (hDC);

GetCursorPos (& mpos);

SetCursorPos (512, 384);

player. setH (player. getH () + (float)(512 — mpos. x)/100 * 5);

yrot = player. getH ();

lookupdown-= (float)(384 — mpos. y)/100 * 5;

HRESULT hr = g_KDIDev-> GetDeviceState (sizeof (buffer), & buffer);

float xpos_tmp, zpos_tmp;

if (buffer[DIK_ESCAPE] & 0×80)

{

done = true;

}

if (floor (player. getX ()) == floor (weapon. getX ()) & & floor (player. getZ ()) == floor (weapon. getZ ())) {

weapon. active = false;

player. charged = true;

}

for (int i = 0; i < enemy_count; i++) {

if (floor (player. getX ()) == floor (enemy[i]-> getX ()) & & floor (player. getZ ()) == floor (enemy[i]-> getZ ())) {

if (player. charged) {

player. killed++;

if (player. killed == 5) {

win = CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0;

break;

}

weapon. active = true;

weapon. spot ();

player. charged = false;

enemy_count += 1 + rand ()%2;

if (enemy_count > 5)

enemy_count = 5;

for (int k = 0; k < enemy_count; k++) {

enemy[k] = new Enemy ();

enemy[k]-> model = new CMD2Model ();

enemy[k]-> model->LoadModel («Data/Models/Ogr. md2»);

enemy[k]-> model->LoadSkin («Data/Models/Ogr. pcx»);

enemy[k]-> model->SetAnim (STAND);

enemy[k]-> model->ScaleModel (0. 03);

enemy[k]-> spot ();

}

frag_timer = CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0;

} else {

player. lifes -= 1;

life_timer = CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0;

enemy[i]-> spot ();

if (player. lifes == 0 & & game_over ≠ 666) {

game_over = CTimer: :GetInstance ()->GetTimeMSec () / 1000. 0;

}

}

break;

}

}

if (game_over == 0) {

if (buffer[DIK_UP] || buffer[DIK_W] & 0×80)

{

xpos_tmp = player. getX () — (float)sin (player. getH ()*piover180) * 0. 05f;

zpos_tmp = player. getZ () — (float)cos (player. getH ()*piover180) * 0. 05f;

if (point_in (xpos_tmp, zpos_tmp))

{

player. setX (xpos_tmp);

player. setZ (zpos_tmp);

}

if (walkbiasangle >= 359. 0f)

walkbiasangle = 0. 0f;

else

walkbiasangle+= 10;

walkbias = (float)sin (walkbiasangle * piover180)/20. 0f;

}

if (buffer[DIK_DOWN] || buffer[DIK_S] & 0×80)

{

xpos_tmp = player. getX () + (float)sin (player. getH ()*piover180) * 0. 05f;

zpos_tmp = player. getZ () + (float)cos (player. getH ()*piover180) * 0. 05f;

if (point_in (xpos_tmp, zpos_tmp))

{

player. setX (xpos_tmp);

player. setZ (zpos_tmp);

}

if (walkbiasangle <= 1. 0f)

walkbiasangle = 359. 0f;

else

walkbiasangle-= 10;

walkbias = (float)sin (walkbiasangle * piover180)/20. 0f;

}

if (buffer[DIK_LEFT] || buffer[DIK_A] & 0×80)

{

xpos_tmp = player. getX () + (float)sin ((player. getH () — 90)*piover180) * 0. 05f;

zpos_tmp = player. getZ () + (float)cos ((player. getH () — 90)*piover180) * 0. 05f;

if (point_in (xpos_tmp, zpos_tmp))

{

player. setX (xpos_tmp);

player. setZ (zpos_tmp);

}

if (walkbiasangle <= 1. 0f)

walkbiasangle = 359. 0f;

else

walkbiasangle-= 10;

walkbias = (float)sin (walkbiasangle * piover180)/20. 0f;

}

if (buffer[DIK_RIGHT] || buffer[DIK_D] & 0×80)

{

xpos_tmp = player. getX () + (float)sin ((player. getH () + 90)*piover180) * 0. 05f;

zpos_tmp = player. getZ () + (float)cos ((player. getH () + 90)*piover180) * 0. 05f;

if (point_in (xpos_tmp, zpos_tmp))

{

player. setX (xpos_tmp);

player. setZ (zpos_tmp);

}

if (walkbiasangle <= 1. 0f)

walkbiasangle = 359. 0f;

else

walkbiasangle-= 10;

walkbias = (float)sin (walkbiasangle * piover180)/20. 0f;

}

}

if (buffer[DIK_ADD] & 0×80)

{

adjust += 1;

}

if (buffer[DIK_SUBTRACT] & 0×80)

{

adjust -= 1;

if (adjust < 1)

adjust = 1;

}

if (buffer[DIK_F12] & 0×80)

{

if (!fsb)

{

fsb = true;

KillGLWindow ();

fullscreen = !fullscreen;

if (!CreateGLWindow («Frag The Monster», 1024, 768, 32, fullscreen))

{

return 0;

}

if (!DI_Init ())

{

return 0;

}

}

}

else

{

fsb = false;

}

}

}

}

DX_End ();

KillGLWindow ();

player. ~Player ();

return (msg. wParam);

}

ПоказатьСвернуть
Заполнить форму текущей работой