Читайте также: |
|
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ /////////////////////////////////////////
#include <dos.h>
#include <bios.h>
#include <stdio.h>
#include <math.h>
#include <conio.h>
#include <graph.h>
// определения /////////////////////////////////////////////
#define ANT_NORTH 0
#define ANT_EAST 1 #define ANT_SOUTH 2
#define ANT_WEST 3 #define NUM_ANTS 50
// структуры ////////////////////////////
// структура муравья
typedef struct ant_typ
{
int x,y; // позиция муравья
int state; // состояние муравья
unsigned char color; // цвет муравья: красный или зеленый
unsigned back_color; // фон под муравьем
} ant, *ant_ptr;
// ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ ///////////////////////////////////
unsigned char far *video_buffer: = (char far *)0xA0000000L;
// указатель на видеобуфер
unsigned int far *clock = (unsigned int far *)0x0000046C;
// указатель на внутренний таймер
// наши маленькие муравьи
ant ants[NUM_ANTS];
// ФУНКЦИИ /////////////////////////////////////////////////
void Timer(int clicks)
{
// эта функция использует внутренний таймер с частотой 18.2 "тик"/с.
//32-битовое значение этого таймера находится по адресу 0000:046Ch
unsigned int now;
//получаем текущее время
now = *clock;
//Ожидаем до истечения указанного периода времени.
//Заметьте; что каждый,"тик" имеет длительность примерно в 55мс.
while(abs(*clock - now) < clicks){}
) // конец Timer
////////////////////////////////////////////////////////////
void Plot_Pixel_Fast(int x,int y,unsigned char color)
{
// эта функция рисует точку заданного цвета несколько быстрее чем
// обычно, за счет применения операции сдвига вместо операции
// умножения
// используется тот факт, что 320*у = 256*у + б4*у = у<<8 + у<<6
video_buffer[ ((у<<8) + (у<<6)) + х] = color;
} // конец Plot_Pixel_Fast ////////////////////////////////////////////////////////////
unsigned char Read_Pixel_Fast(int x,int у)
{
// читаем значение пикселя из видеобуфера
return (video_buffer [((у<<8) + (у<<6)) + х]);
} // конец Read_Pixel_Fast
///////////////////////////////////////
void Draw_Ground(void)
{
int index;
// эта функция рисует разбросанные по экрану серые камешки
for (index=0; index<200; index++)
{
Plot_Pixel_Fast(rand()%320,rand()%200, 7 + rand()%2);
} // конец цикла
} // конец Draw_Ground ///////////////////////////////////////////////
void Initialize_Ants(void)
{
int index;
for (index=0; index<NUM_ANTS; index++)
{
// выбираем случайным образом начальную позицию, цвет и состояние
// для каждого муравья, а также определяем его фон
ants[index].х = rand(}%320;
ants[index].у = rand()%200;
ants[index].state = rand()%4;
if (rand()%2==1)
ants[index].color = 10;
else
ants[index].color = 12;
// сканирование фона
ants[index].back_color = Read_Pixel_Fast(ants[index].х, ants[index].y);
} // конец цикла
} // конец Initialize_Ants ////////////////////////////////////////////////////////////
void Erase_Ants(void)
{
int index;
// в цикле обрабатывается массив муравьев, все муравьи замещаются
// точками, цвета соответствующего фона
for (index=0; index<NUM_ANTS; index++)
{
Plot_Pixel_Fast(ants[index].х, ants[index].y,
ants[index].back_color);
} // конец цикла
} // конец Erase Ants
////////////////////////////////////////////////////////////
void Move_Ants(void)
{
int index,rock;
//в цикле обрабатывается массив муравьев, каждый муравей перемещается
//в соответствии со своим состоянием
for (index=0; index<NUM ANTS; index++)
{
// каково состояние муравья?
switch(ants[index].state)
{
сазе ANT_NORTH:
{
ants[index].у—;
} break;
case ANT_SOUTH:
{
ants[index].y++;
} break;
case ANT_WEST:
{
ants[index].x--;
} break;
case ANT_EAST:
{
ants[index].x++;
} break;
} // конец оператора switch
// проверка, не столкнулся ли муравей
// с границами экрана или с камнем
if (ants[index].x > 319) ants[index].x = 0;
else if (ants[index].x <0)
ants[index].x = 319;
if (ants[index].у > 200)
ants[index].у = 200;
else if (ants[index].у <0)
ants[index].у = 199;
// здесь проверяем, не столкнулся ли муравей с камнем
rock = Read_Pixel_Fast(ants[index].x, ants[index].у);
if (rock)
{
// изменение состояния
ants[index].state =rand()%4; // выбор нового состояния
} // конец оператора if
} // конец цикла
} // конец Move_Ants
////////////////////////////////////////////////
void Behind_Ants(veid)
{ int index;
// в цикле обрабатывается массив муравьев,
// определяется цвет фона для каждого муравья
for (index=0; index<NUM_ANTS; index++)
{ // читается пиксель и его значение сохраняется
// для дальнейшего использования
ants[index].back_color = Read_Pixel_Fast(ants[index].x, ants[index].y);
} // конец цикла
} // конец Behind_Ants ////////////////////////////////////////////////////////////
void Draw_Ants(void)
{
int index;
// в цикле обрабатывается массив муравьев, рисуется каждый
// муравей соответствующим цветом
for (index=0;index<NUM_ANTS; index++)
{
Plot_Pixel_Fast(ants[index].x, ants[index].y, ants[index].color);
} // конец цикла
} // конец Draw_Ants
// ОСНОВНАЯ ПРОГРАММА //////////////////////////////////////
void main (void)
{
// установка видеорежима 320х200х256
_setvideomode(_MRES256COLOR);
_settextposition(2,0);
printf("Hit any key to exit.");
//построение игрового пространства
Draw_Ground();
/ создаем муравьев
Initialize_Ants();
while(!kbhit())
{ // стираем всех муравьев
Erase_Ants (};
// перемещаем всех муравьев
Move_Ants ();
// определяем фон под муравьями
Behind_Ants();
// рисуем всех муравьев
Draw_Ants (),;
// немного подождем
Timer(2);
} // конец оператора while
// восстановление первоначального видеорежима
_setvideomode(_DEFAULTMODE);
} // конец функции main
Если вы запустите программу, то увидите кучу точек на экране. Красные и зеленые точки — это муравьи, а серые — это камни. Когда муравьи натыкаются на камни, они меняют направление движения. Эта программа показывает использование переменных состояния. Позже мы узнаем, как использовать переменные состояния для создания более сложных для вычисления структур, называемых состоянием машины.
Теперь изменим тему и поговорим о том, как выглядит игра с точки зрения игрока.
Интерфейс пользователя
Человек познает мир игры через графику и звук. Тем не менее, нельзя забывать еще об одной детали, влияющей на восприятие игры - интерфейсе пользователя. С помощью интерфейса пользователя игрок выбирает уровень сложности, настройки, задает количество участников и т. д. Поэтому интерфейс пользователя должен быть максимально простым в управлении. Ничто так не раздражает, как непонятные и запутанные команды и настройки. (Зачастую этим грешат спортивные игры. У них миллион настроек, и пока вы разбираетесь с ними, у вас пропадает желание поиграть).
В компьютерных играх с помощью интерфейса решаются две.задачи:
§ Во-первых, интерфейс пользователя в течение всего времени игры выводит на экран жизненно важную информацию о статусе игры, количестве набранных очков и т. д.
§ Во-вторых, с помощью интерфейса пользователя можно при необходимости изменять настройки игры.
Причем это должно осуществляться просто и понятно. Необходимо, чтобы игровой интерфейс акцентировал внимание на наиболее важных состояниях, возникающих в процессе игры. Более того, по-возможности надо использовать текст. Конечно, пиктограммы выглядят заманчиво, но как-то я столкнулся с пиктограммой, изображающей вулкан, но так и не понял, зачем она нужна.
Интерфейс пользователя должен удовлетворять следующим требованиям:
§ Быть доступным в любой момент игры;
§ Использовать слова, написанные большими буквами и не выводить на экран много пунктов настроек одновременно;
§ С одной стороны позволять игроку настраивать программу, а с другой - защищать данные от уничтожения и случайных ошибок;
§ Учитывать возможность того, что игрок не знает, что делает.
Интерфейс пользователя подобен сахарной глазури на кексе. Вы должны думать о том, как лучше всего ее употребить. Помните: интерфейс должен быть простым. Не загружайте его деталями и избегайте символов (если только они не будут абсолютно понятными).
Демонстрационный режим
После того как вы окончите работу над созданием компьютерной игры, вы наверняка захотите включить в нее режим демонстрации для показа ее возможностей. Если вы создавали игру с учетом такой необходимости (например, предусмотрели возможность получения исходных данных из файла, а не от игрока), то сделать это достаточно просто.
Во время игры изменяется состояние устройства ввода-вывода. (Более подробно об этом можно прочесть в третьей главе, «Основы устройств ввода»). С помощью этих устройств игрок может влиять на события. Во время игры логический контроль за вводом осуществляется с помощью определенной функции, такой, например, как Get_Input (). Эта функция отвечает за отслеживание текущего состояния устройства ввода.
Таким образом, все что мы должны сделать, это добавить в функцию контродя за вводом возможность считывания данных из заранее созданного файла. Сама по себе игра не почувствует никакой разницы. Рисунок 11.8 наглядцо показывает реализацию этого метода.
Но, спросите вы, как создать такой файл? Для этого необходим особый режим игры. В таком режиме данные от устройства ввода будут оцифровываться с некоторым постоянным интервалом времени (скажем, 10 раз в секунду) и записываться в специальный файл. В демонстрационном режиме функция ввода будет вместо информации от устройства ввода использовать информацию из этого файла.
Это самый распространенный метод реализации демонстрационных режимов. Конечно, существуют и другие способы, но все они используют либо заранее подготовленные данные определенного формата, либо подобия системы искусственного интеллекта.
Вы можете решить, что сохранение всей информации о вводе потребует много памяти. Давайте посмотрим. Если мы сохраняем состояние устройства ввода 10 раз в секунду, то за минуту набежит 600 байт, а за 10 минут - всего 6 килобайт. Как видите, это не проблема, поэтому я советую вам пользоваться именно таким методом. Однако еще до начала составления программы вы должны предусмотреть в функции ввода «переключатель», с помощью которого можно выбирать между мышью, клавиатурой, джойстиком или воспроизведением файла. Возможность воспроизведения файла позволяет также реализовать в игре режим "замедленного повтора".
Сохранение игры
Физики верят, что если бы они знали координаты и состояние всех частиц Вселенной, то смогли бы предсказывать будущее. Возможно, это и так. Перед нами же стоит задача попроще. Нам надо уметь записывать состояние нашей игры с тем, чтобы при необходимости его можно было восстановить.
Итак, проблема заключается в следующем: как запомнить игру так, чтобы в любой момент мы могли восстановить ее в прерванном месте? Ответ довольно Прост: надо создать список всех игровых объектов и факторов, которые могут измениться в течение игры. Затем создать файл определенного формата и записать в него всю эту информацию. Теперь, когда игрок хочет сохранить игру, мы просто записываем необходимую информацию на диск.
Для примера рассмотрим, как можно сохранить игру в DOOM или Wolfenstein 3-D:
§ В каждой игре присутствует множество неподвижных объектов. Поэтому их сохранять не надо. Однако во время сохранения игры нам необходимо помнить, что они существуют;
§ Также мы должны принимать во внимание настройки игры. Для каждой настройки мы должны запомнить копию ее структуры. Эти структуры должны содержать положение, состояние и т. д.;
§ Наконец, надо запомнить, какой инвентарь имеет при себе играющий на данный момент, а также каково его состояние (позиция, здоровье и т. д.), иными словами, то, что необходимо для правильного сохранения статуса игры.
Это все. Если кратко, мы делаем моментальный снимок нашего мира и представляем его в оцифрованном виде.
Моделирование реального мира
Хоть в нашей игре реальный мир будет, в основном, составлен из стен, тем не менее, мы должны хотя бы вкратце обсудить эту тему. Конечно, вам захочется, чтобы в вашей игре были те эффекты, с которыми вы сталкиваетесь в реальном мире и которые вызываются силами трения, притяжения, сохранения импульса и т. д. Например, без них не обойтись при имитации скачек, при запуске ракеты в военных играх и при столкновении шаров в симуляторе бильярда. В любом лyчae, я хочу вам преподать маленький курс основ механики.
Каждый из нас знает, что такое скорость. Это просто изменение расстояния за единицу времени. Например, если я хочу перемещать объект со скоростью два пикселя в секунду, я могу это сделать так:
Object_Position += 2;
Если вы посмотрите на координаты объекта как на функцию времени, та увидите график, приведенный на рисунке 11.9.
Что такое ускорение? Ускорение - это изменение скорости за единицу времени или, другими словами, приращение скорости. Когда вы в своем автомобиле нажимаете на акселератор, то скорость становится все 6ольше ибольше. Ускорение может быть записано в следующем виде:
Object_Position += velocity;
velocity += acceleration_factor;
Приведенный фрагмент программы увеличивает скорость. Это выглядит как ускорение. Чаще всего мы сталкиваемся с ускорением свободного падения. Когда объект падает на землю, его ускорение составляет 9,8 м/сек. То есть если в первую секунду падения его скорость достигнет 9,8 м/сек, то во вторую она вырастет до 19,6 м/сек.
Чтобы увидеть, как это осуществляется, посмотрим на текст программы в Листинге 11.5. Она показывает падение мяча под действием силы тяжести. Вы можете изменять ускорение с помощью клавиш + и -.
Дата добавления: 2015-07-12; просмотров: 114 | Нарушение авторских прав
<== предыдущая страница | | | следующая страница ==> |
Листинг 11.3. Функции полета мухи. | | | Листинг 11.5. Падение мяча (BALL.C). |