Главная страница Случайная страница Разделы сайта АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Листинг 13.4. Умная «Муха» (BFLY.C).
// ВКЛЮЧАЕМЫЕ ФАЙЛЫ ///////////////////////////////////// #include < stdio.h> #include < graph.h> #include < math.h> // ОПРЕДЕЛЕНИЯ ////////////////////////////// #define STATE_CHASE 1 #define STATE_RANDOM 2 #define STATE_EVADE 3 #define STATE_PATTERN 4 // ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ /////////////////////// // Указатель на системную переменную, содержащую значение таймера. // Содержимое этой 32-битовой ячейки обновляется 18.2 раза //в секунду unsigned int far *clock=(unsigned int far *)0х0000046C; // Х- и Y-компоненты шаблонов траекторий, по которым // будет двигаться " Муха" int patterns_x[33[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, -1, -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, -l, -l, -l, -l, -l, 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: 046Ch 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, // номер текущего шаблона pattern element, // текущая команда шаблона select_state=0, // флаг необходимости смены состояния clicks=20, // количество циклов, в течение которых // сохраняется текущее состояние fly_state = STATE CHASE; // " Муха" начинает с преследования float distance; // используется при расчете // расстояния между игроком и " Мухой" _setvideomode(_MRES256COLOR); printf(" Brainy 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=l; } break; } // конец оператора switch } // конец обработки нажатия клавиши // теперь перемещаем противника // начинается работа " мозга" // определяем текущее состояние КА switch(fly_state) { case STATE_CHASE: { _settextposition(24, 2); printf(" current state: chase " };. // реализуем Алгоритм Преследования if (px> ex) ex++; if (px< ex) ex--; if (py> ey) ey++; if (py< ey) ey--; //не пора ли перейти к другому состоянию? if (--clicks==0) select_state=l; } break; case STATE_RANDOM: ( _settextposition(24, 2}; printf(" current state: random "); // перемещаем " Муху" в случайном направлении ex+=curr_xv; ey+=curr_yv; //не пора ли перейти к другому состоянию? if (--clicks=0) select_state=l; } break; case STATE_EVADE: { _settextposition(24, 2); printf(" current state: evade "); // реализуем Алгоритм Уклонения if (px> ex) ex--; if (px< ex) ex++; if (py> ey) ey—; if (py< ey) ey++; //не пора ли перейти к другому состоянию? if (--clicks==0) select_state=l; } break; case STATE_PATTERN: { _settextposition(24, 2); printf(" current state: pattern "); // перемещаем " Муху", используя следующий // элемент текущего шаблона ex+=patterns_x[current_pattern][pattern_element]; ey+=patterns_y[current_pattern][pattern_element]; // обработка шаблона закончена? if (++pattern element==20) { pattern_element = 0; select_state=l; } // конец проверки завершения шаблона } break; default; break; } // конец обработки текущего состояния // надо ли менять, состояние? if (select_state==l) { // Выбор нового состояния основан на // игровой ситуации и неявной логике. // Для выбора используется расстояние до игрока distance = sqrt(.5+fabs((рх-ех)*(рх-ех)+(ру-еу)*(ру-еу))); if (distance> 5& & distance< 15& & rand()%2==1) { // выбираем новый шаблон current_pattern = rand()%3; // переводим " мозг" в состояние действий по шаблону fly_state = STATE_PATTERN; pattern_element = 0; } // конец обработки ситуации " близко к игроку" else if (distance< 10) // слишком близко, убегаем! clicks=20; fly_state = STATE_EVADE; } // конец обработки ситуации " слишком близко" else if (distance> 25& sdistance< 100& & rand()%3==1) { // преследуем игрока clicks=15; fly_state = STATE_CHASE; } // конец обработки ситуации Преследование else if (distance> 30& & rand()%2==l) { clicks=10; fly_State = STATE_RANDOM; curr_xv = -5 + rand()%10; //от -5 до +5 curr_yv = -5 + rand()%10; //от -5 до +5 } // конец " неявной логики" else { clicks=5; fly_state = STATE_RANDOM; curr_xv = -5 + rand()%10; //от -5 до +5 curr_yv = -5 + rand()%10; //от -5 до +5 } // конец оператора else // сбрасываем флаг смены состояния select_state=0; } // конец Алгоритма Смены Состояния // Убеждаемся, что " Муха" находится в пределах экрана if (ex> 319) ех=0; i£ (ex< 0) ех=319; if (ey> 199) еу=0; if (ey< 0) еу=199; // конец работы " мозга" _setcolor(12); _setpixel(ex, ey); // Немного подождем... Timer(1); } // Конец цикла while _setvideomode(_DEFAULTMODE); } // Конец функции main Запустив программу, вы наверняка обратите внимание на кажущуюся сложность поведения «Мухи». А ведь для получения такого результата использована весьма простая схема! Возможно, и вы заметите то, что увидел я - чуть ли не человеческую способность мыслить. Управление приоритетным состоянием Можно еще усовершенствовать наш КА, если ввести управление сменой состояний с помощью некоторых переменных и функций. На практике это означает возможность изменения текущего режима, не дожидаясь полного завершения программы, отвечающей за его выполнение. В имитаторе движения «Мухи» каждое состояние выполнялось до полного завершения. Но если включить в программу проверку выполнения или невыполнения некоторых условий, это позволило бы КА «выпрыгнуть» из состояния, не дожидаясь окончания его «отработки». Этим заканчивается наш разговор о конечных автоматах, которые могут быть использованы в наших играх для моделирования поведения существ и придания им видимости наличия интеллекта. Теперь к имеющейся у нас системе высокоуровневого управления не помешает добавить низкоуровневое функционирование. Вероятностные автоматы Наверное, вы уже поняли, как вероятность и случайные числа могут быть использованы для выбора направлений и состояний. Мы научились использовать случайные последовательности для конструирования «характера» персонажей. Я имею в виду, что «Муха» в нашем предыдущем примере могла самостоятельно выбирать различные состояния, основываясь на окружающей обстановке. Если несколько изменить метод выбора состояний, основанны на генерации случайных чисел (то есть, создать условия, при которых вход в опредёленное состояние стал бы легче или тяжелее), то, в конечном счете, нам удалось бы изменить " характер" «Мухи». Скажем, нам захотелось иметь в игре две «мухи». Если одну и ту же программу использовать для создания траектории движения каждой «мухи», они бы действовали одинаково. Во многих случаях большего и не требуется. Однако гораздо интересней иметь много «мух» с небольшими различиями в поведении. Это можно было бы реализовать изменением диапазона случайных чисел-во всех строках программы, где выбираются состояния «мухи». Но такой подход будет очень грубым. Мы пойдем другим путем — путем создания общего метода управления характером персонажей, основанного на вероятности. В искусственном интеллекте «индивидуальность» означает возможность существ по-разному выполнять определенные действия при одних и тех же обстоятельствах. Например, у меня есть несколько достаточно активных друзей, которые захотели бы слегка проучить плута, попытавшегося их надуть. Но у меня также есть друзья, которые более спокойны и предпочитают сначала думать, а потом действовать. Скорее всего, мошеннику удалось бы как-то с ними договориться. То, что мы видим на данном примере и является «индивидуальностью». Каким именно способом это будет достигнуто, не принципиально, важен конечный результат. В видеоиграх мы могли бы иметь несколько противников, которые постоянно преследуют нас, пока другие в это время неподвижны и стреляют. Третьи трусливы и предпочитают убегать, а не сражаться. Анализируя ситуацию, мы видим, что имеется все тот же набор состояний, но вероятности перехода в них различны для каждого создания. Для моделирования этого процесса мы могли бы сослаться на «таблицу вероятностей» в той части программы, которая выбирает новое состояние. Эта таблица могла бы содержать различные степени вероятности переходов существ в то или иное состояние. К примеру, взгляните на таблицу 13.1, в которой перечислены соотношения вероятностей для трех различных существ в одной игре. Таблица 13.1. Распределение вероятностей для трех существ в игре.
|