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

Шаблонные мысли


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

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

Когда они выполняют эти движения, то всего лишь следуют командам, заранее написанных шаблонов. Конструирование шаблонов - чрезвычайно легкое занятие и они нашли использование во многих сценариях. Как пример, используем шаблоны и случайные числа для моделирования «разума», который можно использовать, например, для управления небольшим космическим кораблем. Он пытается уклониться от вас, и в то же время пробует прицельно стрелять. То, что можно для этого сделать, показано в Алгоритме 13.3.

Алгоритм 13.3. Шаблоны со случайным выбором.

// Предположим, что pattern

- это массив, содержащий набор команд

// для реализации десяти различных шаблонов поведения

while(идет игра)

{

...код программы

// Проверяем, закончена ли обработка текущего шаблона

if (если обработка команд текущего шаблона закончена)



{

// Выбираем

новый шаблон

current_pattern = pattern[rand()%10];

позиция противника = старая позиция +следующий элемент текущего шаблона

Увеличиваем на единицу значение индекса элементов шаблона

...код программы

}

Алгоритм 13.3 кажется сложнее предыдущих Алгоритмов Преследования и Уклонения, но на самом деле это не так. В сущности:

§

Случайным образом выбирается некоторый шаблон;

§          Движение созданий в каждом проходе цикла изменяется в соответствии с направлением, указанным в шаблоне;

§          Затем мы переходим к следующему элементу шаблона.


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

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

Наконец, мы могли бы связать выбор случайного номера шаблона с действиями на основе некой другой логики - например, описываемой Алгоритмом 13.1.

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



По аналогии с нервной системой, случайное число можно представить как нервный импульс, а выбранный шаблон действий - как реакцию на него. Посмотрите на рисунок 13.2, чтобы увидеть тот процесс, о котором я говорю.

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

Алгоритм 13.4. Преследование и Танец.

while(идет игра)

{

...код программы

if (игрок вне круга с радиусом 50 точек) then

преследуем его

else

выбираем случайный шаблон и реализуем его

...код программы

}

Для демонстрации использования шаблонов я переработал программу из Листинга 13.1 и привел ее в соответствие с Алгоритмом 13.4. Новая программа показана в Листинге 13.2. Когда враг приближается к игроку, он выбирает один из трех шаблонов и выполняет его до завершения. Далее, в зависимости от расстояния до игрока, противник либо преследует игрока, либо выбирает другой шаблон.

Листинг 13.2. Муха (FLY.C).

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

#include <stdio.h>

#include <graph.h>

#include <math.h>

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



//указатель на системную переменную, содержащую

//значение таймера. Содержимое этой 32-битовой ячейки

//обновляется 18.2 раз в секунду

usigned int far *clock=(unsigned int far *)0x0000046C;

// Х- и Y- компоненты шаблонов траекторий, по которым будет

// двигаться "муха"

int patterns_x[3] [20]={1,1,1,1,1,2,2,-1,-2,-3,-1, 0,0,1,2,2,-2,-2,-1,0, 0,0,1,2,3,4,5,4,3,2,1,3,3,3,3, 2,1,-2,-2,-1, 0,-l,-2,-3,-3,-2,-2, 0,0,0,0,0,0,1,0,0,0,1,0,1};

int patterns_y[3] [20]={0,0,0,0,-1,-1,-1,-1,-1, 0,0,0,0,0,2,2,2,2,2,2, 1,1,1,1,1,1,2,2,2,2,2, 3,3,3,3,3,0,0,0,0, 1,1,1,2,2,-1,-1,-1,-2,-2, -1,-1,0,0,0,1,1,1,1,1};

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

void Timer(int clicks)

{

// Эта функция использует значение таймера для формирования

// задержки. Необходимое время задержки задается в "тиках"

// интервалах в 1/18.2 сек. Переменная, содержащая 32-битовое

// текущее значение системного таймера, расположена

// по адресу 0000:0:46Ch

unsigned int now;

// получить текущее время

now = *clock;

// Ничего не делать до тех пор, пока значение таймера не

// увеличится на требуемое количество "тиков".

// Примечание: один "тик" соответствует примерно 55мс.

while(abs(*clock - now) < clicks) {}

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

// ОСНОВНАЯ ФУНКЦИЯ //////////////////////////////////////

void main(void)

{

int px=160,py=100,    // начальные координаты игрока

ex=0,ey=0;        // начальные координаты противника

int done=0,           // флаг окончания работы программы

doing_pattern=0,  // флаг выполнения команд шаблона

current_pattern, // номер выполняемого шаблона,

             // принимает значение в интервале 0-2

pattern_element; <// номер выполняемой команды шаблона

_setvideomode(_MRES256COLOR,) ;

printf("             The Fly - Q to Quit");

// главный игровой цикл

while(!done)

{

// очищаем точки

_setcolor(0) ;

_setpixel(px,py);

_setpixel(ex,ey) ;

// Перемещение игрока

if (kbhit())

{

// Определяем направление движения



switch(getch())

{

case 'u': // Вверх

{

py—2;.

} break;

case 'n': // Вниз

{

py+=2;

} break;

case 'j': // Вправо

{

px+=2 ;

} break;

case 'h': // Влево

{ px-=2 ;

} break;

case 'q':

{

done=1;

} break;

} // конец

оператора

switch

} // конец обработки нажатия клавиши

// Теперь перемещаем противника

// Начинается работа "мозга"

if (!doing_pattern)

{

if(px>ex) ex++;

if(px<ex) ex--;

if(py>ey) ey++;

if(py<ey} ey--;

// Теперь проверяем, не надо ли начать выполнять

// шаблон. Он начинает выполняться, если игрок

// оказывается в радиусе 50 точек от противника.

if (sqrt(.1+(рх-ех)*(рх-ех)+(ру-еу)*(ру-еу))<15)

{

// Даже не думайте использовать функцию sqrt в

// настоящей игре!

// Получаем случайный номер шаблона

curent_pattern = rand()%3;

// Переводим "мозг" в режим действий по шаблону

doing_pattern = 1;

pattern_element=0;

} // конец проверки на попадание игрока

// в "радиус действия"

} // конец действий, для случая, когда шаблон не выполнялся

else {

// перемещаем противника, используя следующий

// элемент

текущего шаблона

ex+=patterns_x[current_pattern][pattern_element];

ey+=patterns_y[current_pattern] [pattern_element];

// мы закончили обработку шаблона?

if (++pattern_element==20)

{

pattern_element = 0;

doing_pattern = 0;

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

} // конец оператора else

//конец работы, "мозга"

// рисуем точки

_setcolor(9);

_setpixel(px,py);

_setcolor(12);

_setpixel(ex,ey) ; // Немного

подождем...                                        

Timer(1);                                                     

} // конец

цикла while

// восстановление начального видеорежима

_setvideomode(_DEFAULTMODE) ;

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

Когда вы запустите программу из Листинга 13.2, то поймете, почему я назвал ее "Муха". Точка, бегающая по экрану и в самом деле напоминает муху. Она приближается к вам и вдруг начинает быстро летать вокруг. И такое поведение персонажа воплощено всего в нескольких строках программы с применением описанных выше алгоритмов. (Гм, так как вы думаете, может быть люди - это и в самом деле комплекс действий и реакций?) Теперь рассмотрим случайные передвижения.


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