На главную

Библиотека Интернет Индустрии I2R.ru

Rambler's Top100

Малобюджетные сайты...

Продвижение веб-сайта...

Контент и авторское право...

Забобрить эту страницу! Забобрить! Блог Библиотека Сайтостроительства на toodoo
  Поиск:   
Рассылки для занятых...»
I2R » Сайтостроительство » Flash

Flash 8 и ActionScript. Создаем игры

Данный материал представляет собой одну главу книги "Flash 8 и ActionScript. Библиотека пользователя (+CD)", подробнее о которой вы можете узнать в нашем анонсе, а заказать - в Издательском доме "Питер"

Авторы: Д. Гурский, Ю. Гурский

Глава 10

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

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

Готовый файл kr&nol.fla данного проекта находится на прилагаемом к книге компакт-диске в папке Проекты\Глава 10. Обращайтесь к нему, если что-то вам покажется непонятным.

Для начала, как и всегда во Flash-программировании, необходимо создать объекты, которыми мы будем управлять. В нашем случае это будет игровое поле и, что очевидно, символы крестика и нолика.

Начнем с игрового поля. Чтобы его нарисовать, зайдите в режим редактирования нового клипа (Ctrl+F8) и включите режим отображения сетки (команда Grid->Show Grid (Сетка->Показать сетку) контекстного меню рабочей области). Используя инструмент Rectangle (Прямоугольник), создайте желтый квадрат размером 3 * 3 клетки. Инструментом Line (Линия) проведите в нем разделительные линии. Чтобы они получились равноотстоящими друг от друга, активизируйте режим Snap to Grid (Привязать к сетке), выполнив одноименную команду подменю Snapping (Привязка) контекстного меню рабочей области (при этом начало и конец линий будут привязываться к узлам сетки).

Нарисовав поле, увеличьте его до размеров 90 * 90 пикселов. Для этого, выделив его, введите необходимые значения в поля W (Ширина) и Н (Высота) инспектора свойств.

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

Закончив рисование поля, вернитесь на основную временную шкалу и перетяните на нее из библиотеки экземпляр созданного клипа. Расположив его в центре листа, назовите pole.

СОВЕТ
Отменить неверное действие во Flash можно командой Edit->Undo (Правка->Откат) или сочетанием клавиш Ctrl+Z. Однако если к неверному результату привела целая последовательность действий, то вернуться к исходному состоянию может быть не так просто (особенно если не все операции имеют видимый эффект). Помочь в этом случае может палитра History (История) (рис. 10.1), которая открывается одноименной командой меню Window->Other Panels (Окно->Другие палитры). На ней отображается список всех последних действий, даже самых незначительных. Переместив ползунок, находящийся в левой части палитры, вверх, вы отмените нужное количество действий. Палитра History (История) позволяет также повторять группу действий (для этого служит кнопка Replay (Повторить)), ускоряя тем самым выполнение многих операций.

Рис. 10.1. Палитра History (История)
Рис. 10.1. Палитра History (История)

Нарисовать символы крестика и нолика несложно. Сделав это, переведите их в клипы и подберите на созданном ранее игровом поле для них размеры так, чтобы они максимально удачно вписывались в его клетки. Крестик назовите krestik, а нолик, следовательно, — nolik. Проверьте, чтобы точка начала координат клипов соответствовала центру их графической составляющей. Разместите созданные клипы вне поля фильма.

Этап рисования на этот раз оказался очень коротким. Приступим к написанию кода.

В тот момент, когда пользователь щелкнет кнопкой мыши на игровом поле, на нем должен появиться новый крестик или нолик — в зависимости от того, за какую «команду» он играет. Чтобы «отловить» это событие, воспользуемся обработчиком onMouseDown:

pole.onMouseDown=function(){};

Если кнопка мыши нажимается, то в первую очередь нужно проверить, где располагался указатель. Вполне вероятно, что щелчок был вовсе не на игровом поле. Для этого воспользуемся свойствами _xmouse и _ymouse, хранящими координаты указателя мыши. Для разных клипов значения этих свойств будут различными, так как точки начала координат у них почти никогда не совпадают. Нас будут интересовать значения _xmouse и _ymouse в системе координат клипа pole. Если они окажутся больше нуля и меньше 90, то щелчок был произведен на игровом поле, следовательно, можно выполнять дальнейшие действия:

if (pole._xmouse>0 && pole._ymouse>0 && pole._xmouse<90 && pole. _ymouse<90) {}

Проверить, находился ли указатель мыши над клипом в момент щелчка, можно также, используя уже знакомый нам метод hitTest().

Если условие о позиции указателя окажется выполненным, то в положенную клетку поля следует поместить экземпляр крестика или нолика. Для этого он прежде всего должен быть «изготовлен». Создать копию имеющегося в кадре клипа можно, воспользовавшись функцией duplicateMovieClip():

duplicateMovieClip(user,"obj"+n,n);

Функция duplicateMovieClip() требует задания трех параметров.

user — строка с именем клипа, копия которого должна быть создана. Так как в нашей игре символ, которым обозначаются ходы противников, будет определяться случайным образом, используем в качестве этого параметра не krestik или nolik, а переменную user. Определять ее значение будет следующий код:

// Явно задаем переменные
var user=null;
var computer=null; // Переменная, хранящая символ,
                   // которым играет компьютер
function rand() {
/* Бросаем монетку (результат округления до целых случайного числа от 0 до 1 — это или 0, или 1) */
   if (Math.round(Math.random())==1) { // Если выпало 1, 
                  // то пользователю соответствует крестик
      user="krestik";
      computer="nolik";
   } else {
      user="nolik"; // Если выпало 0, то соперник
                    // играет ноликами
      computer="krestik";
   }
}
rand(); // Определяем значения переменных user и computer

"obj"+n — имя копии клипа. Создается динамически (это необходимо, чтобы экземпляры имели разные идентификаторы) слиянием корня "obj" со значением переменной n. Данная переменная в нашем сценарии будет хранить порядковый номер добавляемого клипа. Задать ее нужно вместе с остальными переменными равной 1:

var n=l;

В конец блока кода, осуществляющего ход пользователя, необходимо добавить:

n++; // На поле появился новый символ —
     // увеличиваем n на единицу

n — глубина клипа. Эта величина задает, как вы помните, выше или ниже других объектов будет располагаться клип. В нашем случае относительность размещения экземпляров не имеет значения, поэтому полагаем данный параметр равным определенной ранее переменной n (значения глубины клипов должны быть различными, поэтому нельзя его задать просто как некоторое число).

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

var stroka=Math.round((pole._xmouse–15)/30)*30;
var stolbec=Math.round((pole._ymouse–15)/30)*30;
_root["obj"+n]._x=pole._x+stroka+15;
_root["obj"+n]._y=pole._y+stolbec+15;

Несмотря на внушительный вид, данные формулы достаточно прозрачные. Х- и Y-координатам созданного последним экземпляра из группы obj (обращаемся к нему с помощью оператора доступа к свойствам по строковым ключам «[]») присваиваются координаты центра той клетки игрового поля, на которой был произведен щелчок. Определяются они следующим образом. Координата указателя мыши в системе отсчета клипа pole делится на значение длины ребра одной клетки игрового поля (она равна 30 пикселам), а затем результат округляется. При этом узнается, к какой по счету строке или столбцу относится клетка (переменные stroka и stolbec). От координаты указателя предварительно необходимо отнять величину, равную половине длины ребра клетки. Если этого не сделать, то для разных точек одной и той же клетки будут вычисляться различные номера строки и столбца. Далее, умножив полученные значения на 30, мы определим координаты левого верхнего угла клетки. Чтобы вычислить координаты ее центра, к ним нужно прибавить значение, равное половине длины ее ребра.

Найденные значения координат центра клетки соответствуют системе отсчета клипа pole. Наш же дубликат расположен на основной временной шкале. Чтобы пересчитать полученные значения для системы координат _root, к ним достаточно прибавить координаты начальной точки клипа pole в этой системе отсчета (pole._x и pole._y). Видите, каким удачным решением было совместить левый верхний угол игрового поля с точкой начала координат клипа!

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

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

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

  1. Высший приоритет должен быть у ситуации, когда ход в данную клетку может победно завершить игру. Она возникает, если в соответствующем ряду ком¬пьютером уже закрыты две клетки.
  2. Второй по приоритету будет комбинация двух знаков противника и свободной клетки в одном ряду. Она означает, что на следующем ходу игра может закончиться проигрышем компьютера. Поэтому, если нельзя победить на этом ходу, опасную позицию следует закрыть.
  3. На третьем месте в иерархии находится позиция, когда в ряду стоит один знак компьютера и две клетки свободны. Значит, потенциально, через два хода можно победить.
  4. Четвертую позицию необходимо отдать комбинации «знак противника плюс две свободные клетки», так как она грозит возможным проигрышем через два хода.
  5. Пятое место занимает строка из пустых клеток. Здесь до победы далеко, но она вполне возможна.
  6. Последняя по ценности позиция соответствует сочетанию знака противника, знака компьютера и пустой клетки. Такая комбинация не может закончить игру ни победой, ни проигрышем, поэтому завершать заполнение такого ряда нужно в последнюю очередь.

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

Как видите, на уровне идей алгоритм крестиков-ноликов совсем не сложный. Гораздо труднее будет реализовать его в коде с учетом того, что мы решили не использовать массивы.

В первую очередь необходимо создать величины, в которых будет храниться информация о содержимом каждой клетки. Достаточно логичным будет сделать их свойствами клипа pole (так как клетки — это его фрагменты). Назовем величины по следующему принципу: общий корень + номер строки + номер столбца. Таким образом мы имитируем массивы, которые нам недоступны.

Изначально каждую клетку нужно связать со значением 1, которое будет обозначать, что она пустая:

// Функция, создающая описание пустого поля
function pole_null() {
   for (var i=0; i<=2; i++) { // Отсчет ведем с нуля —
                  // так в ActionScript индексируются массивы
      for (var j=0; j<=2; j++) {
         pole["kl"+i+j]=1; 
      }
   }
}
pole_null();

Когда пользователь делает ход, свойству, соответствующему заполняемой клетке, должно быть присвоено значение 10 (в случае хода компьютера это будет 100). Реализовать это очень просто, так как ранее в обработчике события onMouseDown мы уже создали переменные, хранящие номера строки и столбца той клетки игрового поля, на которой был произведен щелчок (stroka и stolbec):

pole["kl"+stroka+stolbec]=10;

ВНИМАНИЕ
В этом проекте для преобразования строки в идентификатор свойства мы применяем оператор «[]». Это гораздо техничнее по сравнению с ресурсоемкой eval() и является признаком хорошей техники программирования. Тем более eval() не может находиться в левой части операции присваивания, а выражение с квадратными скобками — вполне.

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

if (pole["kl"+stroka+stolbec]==1) {} // Условие возможности
                                     // хода пользователя

Сейчас нам предстоит самая сложная в этом проекте задача — реализовать функцию-«мозг», которая будет решать, в какую клетку нужно сделать ход.

Первым шагом в этом направлении будет создание переменных, хранящих маршрут обхода рядов для каждой клетки. Как вы помните, необходимо проанализировать ценность позиции клетки относительно всех рядов, к которым она относится, а вывод сделать по их сумме. Конечно, можно попытаться написать и универсальный алгоритм, способный обходить все ряды, которым принадлежит клетка, вне зависимости от ее положения. Но это слишком сложно для крестиков-ноликов. Гораздо проще и быстрее будет перечислить в индивидуальной для каждой клетки переменной индексы клеток, образующих ряды, к которым она относится:

var hod_kl00="000102001020001122";
var hod_kl01="000102011121";
var hod_kl02="020100021222021120";
var hod_kl10="101112001020";
var hod_kl11="011112011121001122021120";
var hod_kl12="101112021222";
var hod_kl20="001020202122201102";
var hod_kl21="202122011121";
var hod_kl22="202122021222221100";

На первый взгляд приведенный код кажется сложным и непонятным. На самом деле это не так.

Проанализируем, например, первую строку. Имя переменной: hod_kl — общий корень, 00 — индексы столбца и строки, к которым относится клетка (то есть это левая верхняя клетка поля). Значение такое: 000102001020001122. Первые шесть цифр соответствуют верхней строке, следующие шесть — левому столбцу, а оставшиеся — ряду по диагонали. Каждая пара цифр определяет одну клетку. Как видите, все просто.

Задав переменные маршрута обхода рядов, можно приступать к созданию самой функции «интеллекта» игры:

function mozg() {} // "Мозг" игры будет громоздким,
                   // но примитивным...

Запускаться функция mozg() будет тогда, когда компьютер должен сделать ход. Что при этом станет происходить? Очевидно, будет проверяться, в какую клетку выгоднее сделать ход. Следовательно, в первую очередь необходимо реализовать механизм, который позволит просматривать все клетки поля. Сделать это очень просто, задав два цикла. Первый будет изменять индекс строки в имени свойства pole.klnm, а второй — столбца:

for (var i=0; i<3; i++) { // i — индекс строки, к которой
                          // относится клетка
   for (var j=0; j<3; j++) {} // j — индекс столбца
}

Совершенно излишне проверять ценность позиции клетки, если в нее уже был сделан ход. Поэтому, прежде чем запустить «умный» код, проверяем, является ли текущая клетка пустой:

if (pole["kl"+i+j]==1) {}

Если клетка пустая, то активизируем функцию obhod(), присваивая возвращенное ею значение (рейтинг клетки) специальной переменной:

var ves=obhod(i,j);

Функция obhod() будет проверять, сколько и каких знаков в рядах, которым принадлежит клетка. Затем она оценивает, насколько имеющиеся сочетания удачны. Таким образом, именно эта функция, а не «мозг» будет выполнять подлинно «интеллектуальную» работу (увы, думать за начальника — удел многих подчиненных). Вынести соответствующий код в отдельную функцию необходимо, так как помимо ходов компьютера нужно оценивать и ходы пользователя. Дублировать же значительный участок кода нерационально.

Немного отвлечемся от функции mozg() и займемся созданием ее «подчиненной» — функции obhod():

function obhod(i,j) {} // i и j — индексы клетки, положение
                       // которой нужно оценить

Для того чтобы сократить код функции obhod(), создадим переменную, которая будет ссылаться на строку с маршрутом обхода рядов для клетки с индексами i и j:

var way=_root["hod_kl"+i+j];

Определять, какое сочетание знаков соответствует каждому ряду, к которому относится клетка, мы будем по сумме значений свойств pole.klnm его клеток. Например, величина 102 будет обозначать, что в ряду имеется один знак компьютера (pole.klnm=100) и две пустые клетки (pole.klnm=1). Индексы nm клеток рядов упакованы в переменной way таким образом, что каждые шесть символов отвечают за один ряд. Чтобы последовательно исследовать все ряды, запускаем цикл. Предел изменения его итератора определяем по тому, сколько шестерок символов может поместиться в хранимой way строке:

for (var k=0; k

Чтобы вычислить сумму свойств pole.klnm для ряда, нужно последовательно выделить из текущих шести символов три пары знаков, являющихся необходимыми индексами nm. Получив нужную подстроку, ее необходимо слить с корнем pole.kl и, переведя результат в идентификатор, прибавить связанное с ним значение к специальной переменной. Данная переменная должна быть изначально определена как ноль:

var ves=0;
for (var m=0; m<3; m++) {
   ves+=pole["kl"+way.substring(6*k+m*2, 6*k+m*2+2)];
}

Узнав, какая комбинация знаков расположена в ряду, нужно ее оценить. Критерии такой оценки мы уже определили. Необходимо только перевести их в код.

Для этого создадим специальную функцию ocenka() (можно прописать критерии и в функции obhod(), но тогда она станет очень громоздкой):

function ocenka(ves) {
   switch (ves) { // ves — сумма свойств pole.klnm
                  // для некоторого ряда
   case 201: // Два знака компьютера в ряду —
             // высший приоритет (ход дает победу)
      return 1000; 
   case 21: // Два знака пользователя в ряду —
            // если не сделать ход, то проигрыш неизбежен
      return 100; 
   case 102: // Знак компьютера и две пустые клетки
      return 50; 
   case 12: // Знак пользователя и две пустые клетки
      return 20; 
   case 3: // Пустой ряд
      return 7; 
   case 111: // В ряду есть и знак компьютера, 
             // и знак пользователя
      return 3; 
   /* Это значение нужно, чтобы было можно определить, что ход
   пользователя закончил игру */
   case 30: 
      return "user_victory";
   }
}

При создании функции ocenka() мы использовали предложение switch(). Оно позволяет проверить сразу несколько условий и поэтому иногда удобнее if(). Так как синтаксис данного предложения предельно прост, комментировать его не будем.

Если окажется, что некоторая клетка принадлежит ряду, в котором все клетки заполнены знаками пользователя (в этом случае функция ocenka() возвращает специальное значение — строку "user_victory"), то работа функции obhod() должна быть прервана (зачем проверять все клетки, если и так ясно, кто победил):

// Добавьте этот код в блок цикла к функции obhod()
if (ocenka(ves)=="user_victory") {
   end("user");
   return "end";
}

Пока не созданная функция end() будет выполнять необходимые действия, если компьютер или пользователь будет завершит ряд или на поле не останется пустых клеток. Действия эти будут зависеть от того, кто выиграл (или поединок закончился ничьей), поэтому ей необходимо передать информацию об этом. Если значение параметра функции end() равно "user", то ей сообщается, что выиграл пользователь.

Если функция obhod() обрабатывает запрос функции mozg(), то значение "user_victory" быть получено не может (так как она проверяет только пустые клетки). В этом случае нужно просто суммировать рейтинги клетки в каждом ряду, к которому она относится:

else {
   summ_ves+=ocenka(ves);
}

Переменную summ_ves, хранящую сумму рейтингов клетки, нужно объявить выше цикла по k равной нулю:

var summ_ves=0;

Значение, которое будет сохранено в результате полной прокрутки цикла k в переменной summ_ves, должно быть возвращено функцией obhod() как итоговый рейтинг клетки:

return summ_ves;

Функция mozg() должна выбрать среди всех пустых клеток ту, которой соответствует максимальный приоритет. Следовательно, рейтинг клеток должен быть где-то сохранен, чтобы по завершении оценки всех вакантных позиций полученные результаты можно было сопоставить. Однако создавать еще одну группу переменных не очень хочется — наш сценарий и так уже достаточно сложный. Мы поступим по-другому. Каждое поступающее от функции obhod() значение будем сравнивать со специальной переменной max, хранящей наибольший из определенных ранее рейтингов. Если рейтинг текущей клетки окажется больше max, то мы его ей присваиваем. В противном случае его можно просто «забыть». Помимо максимального рейтинга, сохранить нужно индексы клетки-«победительницы». Для этого создадим переменную hod:

if (ves>max) {
   max=ves; // Переменную max нужно объявить в начале блока
            // кода функции mozg() равной нулю
   // Переменную hod создаем в начале блока функции mozg()
   // равной null
   hod=""+i+j; // Индексы объединяем в одну строку
}

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

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

comp_hod(hod); // Наберите данное выражение в конце блока
                // функции mozg()

Код в «теле» функции comp_hod() будет идентичен тому, который мы создали для реализации хода пользователя. Единственное отличие в том, что значения индексов клетки функция будет получать в качестве параметра:

function comp_hod(kletka) {
   duplicateMovieClip(computer,"obj"+n,n);
   var stroka=kletka.substring(0, 1);  // Выделяем индекс строки
   var stolbec=kletka.substring(1, 2); // Выделяем индекс столбца
   this["obj"+n]._x=pole._x+stroka*30+15;
   this["obj"+n]._y=pole._y+stolbec*30+15;
   pole["kl"+stroka+stolbec]=100; // Знаку компьютера
                                  // соответствует значение 100
   n++;
}

В общем алгоритм крестиков-ноликов практически завершен. Осталось предусмотреть некоторые детали.

Когда пользователь сделает ход, необходимо проверить, не стал ли он победным. Для этого следует протестировать с помощью функции obhod() клетку, в которую был сделан ход. Если она возвратит значение "end", то работу обработчика нужно прервать:

/* Располагаем код в блоке if() обработчика onMouseDown (строго ниже инкрементирования n) */
if (obhod(stroka, stolbec)=="end") {
   game=false;
   return;
}

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

var game=true;

Остановить выполнение кода в обработчике onMouseDown и вызвать функцию конца игры end() необходимо, если пользователь сделал ход в последнюю пустую клетку поля. Определить это событие можно по значению n, которое будет равно 10:

if (n==10) {
   game=false;
   end("null");
   return;
}

Если пользователь не одержал последним ходом победу и на поле еще есть пустые клетки, то должна быть вызвана функция, выполняющая ход компьютера:

mozg(); // Строка должна размещаться ниже
        // приведенного ранее фрагмента

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

if (max>=1000) { // Набираем эти выражения в конце блока
                 // функции mozg()
   game=false;
   end("computer");
   return;
}

Закончить игру вничью может и ход компьютера. Чтобы «отловить» это событие, добавляем в функцию mozg() (строго ниже вызова функции comp_hod()) следующие строки:

if (n==10) {
   game=false;
   end("null");
   return;
}

Результат игры будем отображать в специальном информационном поле. Пока же, чтобы можно было провести полное тестирование игры, будем выводить его в окне Output (Вывод):

function end(par) {
   trace(par);
}

Вроде бы все. Какой непростой оказалась реализация самой элементарной игры! Запускаем режим тестирования и пробуем играть. Что же, неплохо... Совсем неплохо! Авторам ни разу не удалось выиграть у компьютера. Правда, и машине тоже не слишком везло с победой. Но это уже вопросы техники игры. Главное, что все получилось!

Единственный заметный недостаток в наших крестиках-ноликах — это то, что компьютер делает ход тотчас же после игрока. Это выглядит очень неестественно, поэтому промежуток времени, в течение которого компьютер «обдумывает» ход, нужно искусственно увеличить. Чтобы это сделать, замените вызов функции mozg() следующей строкой:

time=setInterval(mozg,1500);

Функция setInterval() позволяет периодически вызывать функции. Ее первый параметр соответствует имени вызываемой функции, а второй — периоду времени, через который должна производиться ее активизация. Частота вызова задается в миллисекундах (1 с = 1000 мс). Пожалуй, 1,5 секунды на обдумывание хода для компьютера будет вполне достаточно.

Переменная time, хранящая таймер setInterval(), должна быть объявлена вместе с остальными переменными равной null:

var time=null;

Когда произойдет вызов функции mozg(), работа setInterval() должна быть прекращена. Для этого в первую строку ее блока помещаем:

clearInterval(time); // Функция, останавливающая таймер

Тестируем фильм. Вот сейчас компьютер играет вполне «по-человечески»!

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

game=false;

Разрешить продолжать игру пользователю можно тогда, когда ход сделает компьютер. Для этого в блок функции mozg() добавьте:

game=true;

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

function rand_hod() {
   if (Math.round(Math.random())==1) { // Бросаем жребий
      mozg(); // Если выпадает единица, то ходит компьютер. 
   }          // При выпадении нуля ходит пользователь
}
rand_hod(); // При запуске фильма игра начинается автоматически

Расположить вызов функции rand_hod() нужно внизу палитры Actions (Действия), так как для активизации функции mozg() все переменные группы hod_kl должны быть уже инициализированы.

Играя в крестики-нолики, противники редко ограничиваются одной партией. Поэтому в наш фильм необходимо добавить кнопку, которая будет начинать новую игру. Рисовать ее не будем, а позаимствуем из библиотеки кнопок Flash: Window->Common Libraries->Buttons (Окно->Общие библиотеки->Кнопки). Выбрав подходящую кнопку, перетащите ее на поле и назовите new_game.

Нажатие кнопки «слушает» обработчик событий onRelease:

new_game.onRelease=function(){};

Чтобы начать новую игру, в первую очередь нужно удалить с поля оставшиеся после предыдущего поединка знаки. Сделать это будет очень просто, так как и крестики и нолики имеют однотипные названия, образованные корнем "obj" и их порядковыми номерами. Удалить же экземпляр клипа можно, используя метод removeMovieClip():

for (var i=1; i<=9; i++) { // Максимальное количество
                           // объектов на поле — девять
   _root["obj"+i].removeMovieClip();
}

Также необходимо обнулить используемые алгоритмом переменные и свойства:

n=1;         // Отсчет объектов начинаем с единицы
game=true;   // Если пользователю повезет со жребием,
             // он должен иметь возможность делать первый ход
pole_null(); // Всем свойствам pole.klnm присваиваем
             // значение 1 — все клетки снова вакантны

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

rand_hod();

Готово. Запускаем режим тестирования и играем несколько партий подряд. Если все в порядке, то продолжаем работу.

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

Введите динамическое текстовое поле такого размера, чтобы в него могли поместиться два слова средней длины. Расположите его рядом с игровым полем на подложке такого цвета, который бы выделялся на окружающем фоне. Свяжите текстовое поле (строка Var (Переменная) инспектора свойств) с переменной info.

Какую информацию будем выводить в созданное поле? Во-первых, мы должны сообщать игроку об исходе партии. Для этого перепишите функцию end() следующим образом:

function end(par) {
   switch (par) {
   case "user":
      info="Baшa победа!";
      // Если не использовать предложение break,
      // то будут выполнены расположенные ниже выражения
      break; 
   case "computer":
      infо="Вы проиграли!";
      break; 
   case "null":
      info="Hичья";
      break; 
   }
}

Во-вторых, пользователь должен знать, что наступила его очередь делать ход. Поэтому последним выражением в функции mozg() должно быть такое:

info="Baш ход!!!";

После хода игрока компьютер искусственно «изображает» 1,5-секундное раздумье и лишь затем ставит в нужную клетку знак. Чтобы пользователь не решил, что фильм завис или в нем проявился «глюк», в информационное поле выводим

infо="Думаю...";

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

Последним штрихом в реализации крестиков-ноликов будет окно со счетом игры. Чтобы его создать, введите небольшое текстовое поле (в него должно поместиться пять знаков) и свяжите его с переменной schet. Саму эту переменную нужно объявить в начале сценария:

var schet="0:0"; // Счет в начале игры

Чтобы можно было сохранять информацию о количестве побед каждого участника, объявим специальные переменные:

var user_schet=0;
var computer_schet=0;

При завершении игры в функции end() в зависимости от значения поступившего параметра должна быть увеличена либо первая, либо вторая переменная:

case "user":
   infо="Ваша победа!";
   user_schet+=1;
   break;
case "computer":
   info="Bы проиграли!";
   computer_schet+=1;
   break;
Затем должно быть обновлено значение переменной schet:
schet=""+user_schet+":"+computer_schet; // Эту строку
                     // добавляем в конец блока функции end()

Подписываем информационные поля и создаем заголовок игры. Как крестики-нолики получились у авторов, показано на рисунке.

Вот и все... Каким все-таки непростым оказалось создание самой элементарной игры! Представляете, сколько сил нужно потратить, чтобы написать, например, тетрис? На самом деле не так много — при условии неплохого знания языка и наличия в голове продуманного алгоритма. Этой работой займемся после теоретической вставки 23, посвященной особенностям типизации в ActionScript.

Рис. 10.2. Крестики-нолики
Рис. 10.2. Крестики-нолики
Материалы по теме:

Спонсор раздела

Рассылки Subscribe.ru:

Библиотека сайтостроительства - новости, статьи, обзоры
Дискуссионный лист для web-разработчиков
Подписка на MailList.Ru
Автор: NunDesign
Другие разделы
Оптимизация сайтов
Web-студии
» Новое в разделе
Web-дизайн
Web-программирование
Интернет-реклама
Раскрутка сайта
Web-графика
Flash
Adobe Photoshop
Рассылка
Инструменты вебмастера
Контент для сайта
HTML/DHTML
Управление web-проектами
CSS
I2R-Журналы
I2R Business
I2R Web Creation
I2R Computer
рассылки библиотеки +
И2Р Программы
Всё о Windows
Программирование
Софт
Мир Linux
Галерея Попова
Каталог I2R
Партнеры
Amicus Studio
NunDesign
Горящие путевки, идеи путешествийMegaTIS.Ru

2000-2008 г.   
Все авторские права соблюдены.
Rambler's Top100