Создание Flash-игр



Создание Flash-игр

         

Игра на развитие памяти

Исходный файл: Memory.fla

Иногда эту игру называют "Simon", потому что именно так называлось популярное электронное устройство, которое позволяло в нее играть. В игре имеется четыре разных фрагмента, которые проигрываются в произвольном порядке. Вы можете это увидеть, запустив файл Memory.fla. При проигрывании фрагмента загорается световое табло и воспроизводится звуковой сигнал. Элементами этой игры являются четыре птицы, сидящие на ветке (рис. 14.1).

Рисунок 14.1 В игре на развитие памяти на экране показаны четыре птицы

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

Подход

Последовательность мелодий хранится в массиве. Каждый раз в массив добавляется новый, случайный номер от 1 до 4. Номер определяет, какая птица должна чирикать.
В первой части игры воспроизводится чириканье птиц. Этот кадр управляется клипом "actions", который анализирует номера в последовательности и сообщает программе, какая птица когда должна петь.
В следующей части игра ждет, когда пользователь начнет щелкать по птицам. После каждого щелчка проверяется, правильно ли была выбрана птица. Таким образом программа все время следит за пользователем, ожидая момента, когда он ошибется. Если игрок сделал все правильно, в последовательность добавляется новая мелодия, и все начинается заново.

Подготовка ролика



В ролике шесть кадров ( рис. 14.2). Из них кадры под номерами 3 и 4 -ключевые, они называются "play" и "repeat" соответственно. В кадре "play" воспроизводится чириканье птиц, а в кадре "repeat" игрок может щелкать по птицам.

Рисунок 14.2 Шесть кадров игры на развитие памяти: "start", "wait", "play", "repeat", "correct" и "wrong"

Клип каждой птицы состоит из трех частей. Первая - непосредственно клип с самой птицей, первый кадр которого представляет собой изображение, второй и остальные кадры - анимация (птица чирикает, открывая и закрывая рот). Ролик начинается с того, что клип каждой птицы находится в первом кадре.
Вторая часть клипа - кнопка. Одна и та же кнопка используется для каждой птицы, но к ней прикреплен разный код. Кнопка расположена за изображением птицы, так что ее не видно.
Третья часть клипа каждой птицы - просто анимация, показывающая сообщение, которое «вылетает» из клюва птицы. Этот простой клип используется для каждой птицы один раз. Экземпляр анимации сообщения и птица соответственно. Например, первая птица называется «bird1», а сообщение – “note1”. В анимации сообщения первый кадр пустой, там анимация останавливается. Во втором кадре анимации происходит возврат к первому кадру. В соответствующее время мы инициализируем сообщение, которое «вылетает» из клюва птицы.

Если вы внимательно посмотрите на элемент "Bird Button" из исходного ролика, вы увидите, что кадры "Up", "Over" и "Down" пусты, а в кадре "Hit" содержится контур птицы. Это значит, что никакого изображения на рабочем поле для кнопки не будет, а область нажатия кнопки будет совпадать с формой кадра "Hit". Такой способ создания невидимой кнопки отличается от уже описанного, когда создается кнопка и ее значение _alpha обнуляется.

Если рассмотреть анимацию птиц, вы увидите, что звук прикреплен к каждой из них. Звук автоматически воспроизводится при проигрывании анимации с птицей. Каждый звук немного отличается от другого.
В различных кадрах появляются различные части клипов птиц. Клипы
с изображениями самих птиц представлены во всех шести кадрах. Однако кнопки появляются только в кадре "repeat", потому что только там
игрок может щелкать мышкой по птицам. Анимация сообщения появляется только в кадрах под номерами 3-6, в первом и втором кадрах она не нужна.
Также в каждом кадре ролика содержатся указания, что должен делать пользователь. В верхнем правом углу всех кадров, кроме первого, находится текстовое поле scoreDisplay.

Создание кода

Код этого ролика делится на две части. Первая часть - набор функций, расположенных в первом кадре ролика. Вторая часть находится в клипе "playback actions", который управляет воспроизведением мелодий в кадре "play". Небольшие фрагменты кода есть и в других местах. Функции, используемые в этой ролике, расположены в первом кадре основной временной шкалы. Они инициализируют переменные игры, отвечают за реакцию на щелчки мышью и воспроизводят мелодии.
Сначала в игре вызывается функция initGame, которая устанавливает все переменные. Эта функция вызывается в начале игры всегда и в конце, если игрок хочет сыграть заново, то есть снова переходит к первому кадру.
Функция initGame очищает массив notes, затем вызывает функцию addNextNote, чтобы поместить в этот массив случайное число. Также она указывает, что счет игры должен отображаться равным 0.

initGame();
stop();
function initGame() {
// Очищаем массив сообщений,
notes = new Array();
scoreDisplay = "Score: 0";
// Добавляем первое сообщение.
addNewNote();
}

Функция addNextNote случайным образом выбирает номер кадра от 1 до 4 и помещает его в массив notes.

function addNextNote() {
// Выбираем случайное число из диапазона от 1 до 4.
r = int(Math.Random()*4+1);
// Добавляем число в массив,
notes.push(r);
}

Остальные функции этой игры используются позже. Функция startRepeat вызывается тогда, когда игрок прослушал пение птиц и должен щелкать по их изображениям, чтобы воспроизвести соответствующие мелодии.
Переменная repeatNum отслеживает, по какому элементу должен щелкнуть игрок. Изначально ее значение равно 0, а затем оно изменяется каждый раз, когда пользователь щелкает по птице.

function startRepeat() {
// Определяем, по какому элементу
// должен теперь щелкнуть пользователь.
repeatNum = 0;
// Переходим к кадру, где размещены кнопки.
gotoAndPlay("repeat");
}

Функция clickBird вызывается теми кнопками, которые спрятаны за изображениями птиц; ей передается номер элемента, по которому щелкнули. Сначала функция проигрывает анимацию птицы и соответствующую анимацию пения. Затем сравнивает сообщение со следующим сообщением в списке. Если они совпадают, значит, игрок правильно выбрал птицу, и значение переменной repeatNum увеличивается. Если это было последнее сообщение, игра переходит к кадру "correct". В противном случае функция ждет, пока не выберут следующее сообщение. Если сообщение не совпадает с предопределенным, ролик переходит к кадру "wrong", и игра заканчивается.

function clickBird(note) {
// Воспроизводим анимацию птицы.
_root["bird"+note].gotoAndPlay(2);
// Воспроизводим анимацию сообщения.
_root["note"+note].gotoAndPlay(2);
// Проверяем, правильно ли был выбран элемент,
if (note == notes[repeatNum]) {
// Ожидаем воспроизведения следующей мелодии.
repeatNum++;
// Если мелодий больше нет, игрок правильно угадал
// последовательность.
if (repeatNum > notes.length-1) {
scoreDisplay = "Score: " + notes.length;
gotoAndPlay("correct ");
}
} else {
// Игрок ошибся. gotoAndPlay("wrong");
}}

Кадр "play" проигрывает каждую мелодию из последовательности в соответствии со сценарием, прикрепленным к клипу "playback actions". Сценарий начинается с того, что устанавливает две переменные. Переменная noteNum следит за тем, какое сообщение должно быть проиграно следующим, а переменная nextTime - когда оно должно быть проиграно.

onClipEvent(load) {
// Начинаем с мелодии, под номером 0.
noteNum = 0;
nextTime = 0 ;
}

На каждом шаге ролика в кадре "play" текущее время сравнивается со значением переменной nextTime. Если текущее время превышает это значение, проигрывается следующая мелодия. Анимация пения и птицы инициализируются точно так же, как если бы они вызывались при щелчке мышью. Затем изменяются значения переменных noteNum и nextTime, чтобы подготовиться к воспроизведению следующей мелодии. Переменная nextTime увеличивается на 1000, то есть следующая мелодия будет проиграна через одну секунду. Когда будут проиграны все сообщения, ролик вызовет функцию startRepeat, которая была рассмотрена ранее. То есть игра перейдет к кадру "repeat" и будет ждать, когда пользователь попытается восстановить последовательность.

onClipEvent(enterFrame) {
// Выясняем, пришло ли время проиграть следующую мелодию,
if (getTimerO > nextTime) {
// Получение сообщения,
note = _root.notes[noteNum];
// Проигрывается анимация пения
//и соответствующий звуковой файл.
_root["bird"+note].gotoAndPlay(2);
_root[Mnote"+note].gotoAndPlay(2);
// Ждем одну секунду, прежде чем проиграть следующую
// мелодию.
nextTime = getTimer() + 1000;
noteNUm++;
// Если больше сообщений нет, продолжаем со следующего
// шага.
if (noteNum > _root.notes.length) {
_root.startRepeat();}
}}

Каждая кнопка, расположенная на рабочем поле в кадре "repeat", при щелчке по ней должна вызывать функцию clickBird. Каждый из четырех сценариев немного отличается от остальных, так как они должны передать функции различные числа. Вот сценарий для одной из кнопок:

on (press) {
clickBird (1);
}

К сведению

Во всех шести кадрах ролика должна быть команда stop (). В кадрах со второго по шестой это единственная команда.
В кадрах "wait", "correct" и "wrong" находятся кнопки. В кадре "wait" кнопка переводит игру к кадру "play", где проигрывается последовательность мелодий. Кнопка кадра "correct" снова переносит игрока к кадру "play". Однако также должна быть вызвана функция addNewNote, чтобы добавить сообщение в последовательность.

on (press) {
addNewNote();
gotoAndPlay("play");
}

Кнопка в кадре "wrong" переводит ролик к кадру "start", где можно заново начать игру.
Также не забудьте добавить текстовое поле, связанное с переменной scoreDisplay, чтобы игроки знали о результатах своей игры.

Другие возможности

Тема игры может быть любой. Достаточно изменить фон и вид элементов. Количество элементов зависит о того, насколько сложной вы хотите сделать игру.

Дедукция

Исходный файл: Deduction.fla

Следующая игра полностью основана на логике. Один из наиболее популярных ее вариантов (для двух игроков) известен под названием "Mastermind".
Цель игры - угадать произвольную последовательность из пяти цветов. Игрок начинает с предположений. Затем компьютер отвечает, отгадано ли хоть что-то, то есть игрок получает информацию о количестве правильно расположенных цветов и количестве правильных цветов, оказавшихся не на своих местах. На основе этой информации игрок пробует угадать еще раз. Так продолжается определенное число попыток или до тех пор, пока игрок не угадает последовательность.
На рис. 14.3 показан фрагмент этой игры (см. ролик Deduction.fla,). Область игры - выпиленное полено, а цвета представлены в виде камешков. Игрок может выбрать любой из пяти цветных камешков, чтобы заполнить пустое пространство, или не выбрать вообще. Компьютер отвечает следующим образом: отображает белый камешек для каждого правильного цвета, и черный камешек для каждого правильного цвета, помещенного не на свое место.

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

Задача проекта

Цель ролика - создать простую игру под названием "Дедукция". Игроку предоставляется 10 шансов, чтобы угадать последовательность. После каждого варианта игроку выдается результат угадывания.

Подход

Игра начинается с создания произвольной последовательности из пяти цветов, которая хранится компьютером в тайне до конца игры.
При каждой попытке игроку предоставляется пять новых пустых мест, которые нужно заполнить. В дополнение к ним справа появляется кнопка Done (Готово). На рис. 14.4 показано, что видит игрок в начале игры.

Рисунок 14.4 Игра начинается с того, что отображаются пять свободных пустых мест и кнопка Done

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

Рисунок 14.5 Так выглядит игровое поде после нескольких попыток пользователя

Подготовка ролика

В клипе "rock" содержится восемь кадров, первый из которых показывает пустое место. Кадры со второго по шестой отображают пять цветов, из которых должен выбрать пользователь. Седьмой и восьмой кадры отображают белые и черные камешки, имеющие метки "white" и "black" соответственно, чтобы код мог обращаться к ним.
Теперь осталось поместить на рабочее поле фон и указания. Камешки и кнопка Done создаются кодом. Для клипа "rock" установите имя ("rock") в панели Linkage Properties. Я также создал небольшую кнопку, чтобы можно было перейти внутрь клипа камешка. Кнопку "0опе"создать очень просто, но так как нам нужно управлять ее положением, мы должны поместить ее внутри клипа и указать для него свойство "linkage".

Создание кода

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

initGame();
stop() ;

function initGame() {
// Определяется расположение и расстояние между элементами.
topRowLoc = 60;
leftColLoc = 280;
roghtColLoc = 390;
horizSpace = 21;
vertSpace = 23 ;
solutionx = 336;
solutiony = 320;
// Создается произвольная последовательность решения
solution = new Array();
for(i=0;i<5;i++) {
solution.push(int(Math.Random()*5)) ;
}
// Инициализируются переменные.
rows = new Array();
row = 0;
// Устанавливается первый ряд.
createRow();
}

В начале каждой попытки функция createRow создает пять пустых мест и определяет их положение. Вдобавок устанавливается новый клип done, который располагается справа (рис. 14.4).

function createRow() {
// Создается новый ряд из пяти пустых мест.
attachMovie("rock","rock"+row+"-"+i,row*10+i);
clip = _root["rock"+row+"-"+i];
clip._x = leftColLoc + i*horizSpace;
clip._y = topRowLoc + row*vertSpace;
clip, active = true;
}
// Создается кнопка Done.
attachMovie("done","done",1000);
_root.done._x = rightColLoc+20;
_root.done._y = topRowLoc + row*vertSpace;
}

Когда игрок щелкает по кнопке Done, вызывается функция doneGuess. Сначала пять кнопок в текущем ряду становятся неактивными. В функции createRow свойству active каждого клипа было присвоено значение true. Теперь же этому свойству присваивается значение false (1). Код, прикрепленный к каждой кнопке, с помощью этого свойства определяет, можно ли щелкнуть по кнопке или нет.
В массиве temp содержатся номера каждого цвета последовательности (2). Например, если даны два первых цвета, один четвертый и два пятых, массив будет выглядеть следующим образом: [2,0,0,1,2].
Следующий цикл проверяет, сколько цветов точно совпадают с предопределенным расположением (3). Если были найдены совпадения, числа в массиве temp уменьшаются. То есть теперь в этом массиве отображаются те цвета, совпадения с которыми еще надо найти.
Следующий цикл проверяет несовпавшие цвета в последовательности игрока и определяет, какие из этих цветов находятся в массиве temp (4). Подсчитав, можно выяснить, сколько цветов правильно угаданы, но помешены не на свое место.
Следующие два цикла создают белые и черные камешки, которые будут соответствовать числу правильно угаданных цветов и числу угаданных цветов, расположенных не на своем месте (5).
Кнопка Done удаляется, так что теперь она не будет появляться в каждой строке (6). Когда пользователю дается следующая попытка, создается новая кнопка Done.
В конце функции проверяется, совпадают ли все пять цветов или нет (7). Если да, то ролик переходит к кадру "win". В противном случае код проверяет, была ли эта попытка десятой (последней), и если так, ролик перейдет к кадру "lose", иначе для следующей попытки вызывается функция createRow.

function doneGuess() {
numRightSpot = 0;
numRightColor = 0;

(1) // Пять кнопок становятся неактивными,

for (i=0;i<5;i++) {
_root ["rock"+row+"-"+i] .active = false;
}

(2) // Определяем, сколько имеется кнопок одного цвета,

temp = [0,0,0,0,0] ;
for (i=0;i<5;i++) {
temp[solution[i] ]++;}

(3)// Выясняем, сколько цветов правильно угадано,

for (i=0;i<5;i++) {
color = _root["rock"+row+"-"+i]._currentFrame - 2;
if (color == solution[i]) {
numRightSpot++;
temp[color]--;
}}

(4)// Проверяем, сколько цветов угадано,
//но находится не на своих местах.

for (i=0;i<5;i++) {
color = _root["rock"+row+"- currentFrame - 2;
if (color != solution[i]) {
if (temp[color] > 0) {
numRightColor++;
temp[color]--;
}
}}

(5)// Создаем белые камешки.

level = row*10+5;
х = rightColLoc;
for(i=0;i attachMovie("rock","white rock"+level,level)
clip = _root["white rock"+level];
clip.gotoAndStop("white");
clip._x = x;
clip._y = topRowLoc + row*vertSpace;
level++;
x+=horizSpace;
}
// Создаем черные камешки.
for(i=0;i attachMovie("rock","black rock"+level,level);
clip = _root["black rock" + level] ;
clip.gotoAndStop ("black") ;
clip._x = x;
clip._y = topRowLoc + row*vertSpace;
level++;
x+=horizSpace;
}

(6)// Удаляем кнопку Done.

done.removeMovieClip()

(7)// Выясняем, выиграл ли игрок,

if (numRightSpot ==5) {
gotoAndPlay("win");
} else {
row++;
// Проверяем, проиграл ли игрок,
if (row >= 10) {
showSolution();
gotoAndPlay("lose");
} else {
createRow();
}}}

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

function showSolution() {
// Размещаем правильный вариант внизу экрана.
for(i=0;i<5;i++) {
attachMovie("rock","solution"+i,1001 + i) ;
clip = _root["solution"+i];
clip._x = solutionx + i*horizSpace;
clip._y = solutiony;
clip.foroAndStop(solution[i]+2);
}}

На рис. 14.6 показан фрагмент ролика, когда игра уже проиграна. Функция showSolution поместила правильную последовательность (решение) внизу экрана.

Рисунок 14.6 Игра проиграна, код поместил правильную последовательность решения внизу экрана

Единственный оставшийся фрагмент кода - небольшой сценарий, прикрепленный к кнопке в каждом клипе "rock". Его задача состоит в том, чтобы переключать цвета один за другим и возвращаться к первому кадру (пустому месту), если пользователь щелкнул определенное число раз. Этот код также проверяет свойство active, чтобы убедиться, что ряд - текущий.

on (press) {
if (active) {
f = _currentFrame+1;
if (f > 6) f = 1;
gotoAndStop(f);
}}

К сведению

He забудьте присвоить последним двум кадрам клипа "rock" метки "white” и "black". Также обязательно поместите кнопку Done внутрь клипа "done», которому потом необходимо присвоить имя "done" в панели Linkage Properties. К сожалению, это необходимо, так как ActionScript не может динамически создавать кнопки сами по себе. Считайте, что клип "done" - это просто "обертка" для кнопки Done.

Другие возможности

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


Игра "Йога"

Исходный файл: Pegs.fla

Классическая игра "Йога" известна уже тысячи лет. Современные версии сделаны из дешевого пластика. С развитием Web-технологий появился и виртуальный вариант этой игры.
Для игры требуется решетка с отверстиями для колышков (рис. 14.7). Колышки расположены во всех отверстиях, кроме одного. Игрок должен взять один колышек и "перепрыгнуть" через другой, при этом попасть на пустое место. Колышек, через который "перепрыгнули", при этом удаляется. Игра продолжается до тех пор, пока нельзя будет сделать больше ни одного передвижения.

Рисунок 14.7 Наиболее распространенная конфигурация доски с колышками. Вы можете создать свой вариант

Хороший игрок может выиграть, если у него останется только один колышек. При быстрой игре, без раздумий, может остаться примерно от 8 до 12 колышков.

Задача проекта

Цель проекта - создать компьютерный вариант игры "Йога" (рис. 14.7). Игрок щелкает мышкой и перемешает колышки. Неверный ход сделать нельзя, а правильный автоматически удаляет элемент, через который "перепрыгнули".

Подход

Вся игра происходит в одном кадре. Сначала на рабочем поле нет никаких элементов.
Отверстия и колышки - отдельные клипы, они помешаются на рабочее поле с помощью кода, что избавляет вас от необходимости размещать каждый клип и присваивать ему имя. Вместо вас всю работу выполнит программа.
Когда игрок перетаскивает колышек в новое отверстие, код проверяет, какой ход был сделан: верный или ошибочный. Во-первых, пользователь должен переставить колышек на пустое место, через одно отверстие от текущего. Затем необходимо, чтобы в отверстии, через которое "перепрыгивает" игрок, находился колышек. Если ход удовлетворяет этим условиям, он считается верным. Колышек, через который "перепрыгнули", удаляется с доски.

Подготовка ролика

Для игры требуется всего два клипа: "peg" и "hole". В клипе "peg" должна быть расположена кнопка, которая сообщает основной временной шкале о щелчке мышью (пользователь нажимает и отпускает ее кнопку). Так как перед началом ролика на рабочем поле нет ни одного клипа, им необходимо назначить свойства связи. Код обращается к ним по именами "peg" и "hole".

Создание кода

Почти весь код находится в одном кадре основной временной шкале. Он начинается с создания экземпляров клипов "peg" и "hole" и их размещения на рабочем поле. С помощью оператора if создаются необходимые для игры отверстия. Также код проверяет, во все ли отверстия, кроме одного в центре, вставлены колышки.
В конце функции переменной maxHole присваивается значение, равное количеству всех отверстиях. Эта' переменная будет использоваться в тех функциях, где необходимо выяснить, все ли клипы удовлетворяют определенным условиям.

initGame();
stop();
function initGame() {
// Определяем постоянное расположение клипов.
holeSpace =30;
puzzleLeft = 160;
puzzleTop = 80;
// Просматриваем все отверстия создаем в них колышки.
i = 0;
for(y=0;y<9;y++) {
for (x=0;x<9;x++) {
// Проверяем, должен ли быть создан колышек.
// Если да, создаем его.
if (((у < 3) or (у > 5)) and ((х < 3) or (x > 5) continue;

// Добавляем и размещаем новое отверстие. attachMovie("hole", "hole"+i, i);
_root["hole"+i]._x = x*holeSpace + puzzleLeft;
_root["hole"+i]._y - y*holeSpace + puzzleTop;
II He добавляем колышек в центральное отверстие,
if ((x != 4) or (у != 4)) {
// Добавляем и размещаем
// новое отверстие.
attachMovie("peg","peg"+i,100+i);
_root["peg"+i]._x = x*holaSpace + puzzleLeft;
_root["peg"+i]._y = y*holaSpace + puzzleTop;
}
i++;
}}
// Запоминаем количество колышков.
maxHole = i;
}

Когда игрок щелкает по колышку, на самом деле он щелкает по кнопке, расположенной внутри клипа. Оба действия, "press" и "release", передаются функциям в основной временной шкале. Функция dragPeg вызывается действием "press". Эта функция сохраняет положение колышка в переменных pegх и pegу, а затем разрешает перемешать колышек. Также она использует функцию swapDepths, чтобы колышек отображался поверх всех остальных.

function dragPeg(peg) {
// Запоминаем исходное положение колышка,
pegх = peg._х; pegу = peg._у;
// Размещаем колышек поверх остальных,
peg.swapDepths(2000);
// Разрешаем программе Flash перемещать клип.
startDrag(peg, true);
}

Функция dropDrag вызывается тогда, когда игрок отпускает кнопку мыши при перетаскивании. Сначала клип прекращает перемещение (8). Затем с помощью функции dropDrag выясняется, находится ли какое-нибудь отверстие под курсором (9).
Если курсор мыши расположен над дыркой, следующий шаг - определить, пустое ли отверстие или нет (10). Затем код проверяет отверстия во всех четырех направлениях, чтобы выяснить, из какой дырки мог быть перемешен колышек. Для определения относительного положения отверстия используются переменные dx и dy (11). Например, если игрок перемещает колышек вправо, dx присваивается 1, a dy - 0. Если вверх, то dy будет равняться -1, a dx - 0. Если отверстие, куда игрок перемещает колышек, не расположено через одну дырку вправо, влево, вверх или вниз, значения dx и dy становятся равными 0 (12).
Даже если игрок перемешает колышек через одно отверстие, помещает его в пустое место, ход засчитывается только в том случае, если он "перепрыгивает" через другой колышек. Следующий фрагмент кода проверяет, есть ли такой "серединный" колышек (13). Если да, код его удаляет и указывает, что перемещаемый колышек теперь находится в новом месте. Если одно из этих условий не выполняется, значит, ход неверен. Значение переменной placed остается равным false, оно проверяется в конце функции (14). И колышек возвращается на свое исходное место.

function dropDrag(peg) {

(8) // Клип с колышком больше не перемещается.

stopDrag();
//По умолчанию ход неверен,
placed = false;
overole = false;

(9)// Определяем местоположение отверстия, над которым
// находится курсор,

for(i=0;i hole = _root["hole"+i];
if (hole.hitTest(_xmouse, _ymouse)) {
overeHole = true;
break;
}}

(10)// Выясняем, свободно ли отверстие,

if (IpegThere(hole._x, hole._y)) {

(11)// Определяем различие между исходным и конечным
// положениями,

dx = 0;
dy = 0;
if ((pegx == hole._x) and (pegy-holeSpace*2 == hole._y ) {
// сверху
dy = -1; } else if (pegx==hole._x) and
(pegy+holeSpace*2==hole._y)) {
// внизу
dy = 1;
} else if (pegy==hole._y) and (pegx-holeSpace*2==hole._x)) {
// слева
dx = -1;
} else if (pegy==hole.__y) and (pegx+holeSpace*2==hole._x)) {
// справа
dx = 1;
}

(12)// Значения dx и dy будут равны 0, если целевое отверстие
//не находится на необходимом расстоянии,

if ((dx != 0) or (dy != 0)) {

(13)// Выясняем, есть ли колышек посередине.

midThere = false; for(i=0;i mid = _root["peg"+i];
if ((mid._x == pegx + dx*holeSpace) and y == pegy + dy*holeSpace)) {
// Раз колышек здесь находится,
// значит, ход верный.
// Указываем новое положение колышка.
peg._x = hole._x;
peg._у = hole._y;
// Удаляем колышек посередине.
mid.removeMovieClip();
// Запоминаем, что ход верен.
placed = true;
break;
}}
}}

(14)// Проверяем, верный ли ход был сделан, и если нет,
// восстанавливаем исходное положение колышка,

if (placed) {
peg._x = pegx;
peg._y = pegy;
}}

Функция dropPeg использует полезную функцию pegThere, которой передается расположение отверстия и которая возвращает значение true, если именно в этом месте обнаружен клип "peg".

function pegThere(x.у) {
// Выясняем, находится ли в этом месте колышек,
for (i=0;i peg = _root["peg"+i];
if ((peg._x == x) and (peg._y == y)) {
return true;
}}
return false;
}

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

function restartGamef) {
// Удаляем все клипы,
for (i=0;i _root["peg"+i].removeMovieClip();
_root["hole"+i].removeMovieClip();
}
// Начинаем новую игру.
initGame();
}

Код, прикрепленный к кнопке, расположенной внутри клипа "peg» очень прост. Все, что он делает, это передает функциям действия press и release.

on (press) {
_root.dragPeg(this);
}


on (release) {
_root.dropPeg(this);
}

Другие возможности

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


Рекурсивные блоки

Исходный файл: Blocks.fla

Я встречал эту игру в разных вариациях под разными названиями. Основная идея ее в том, что экран заполнен большой решеткой, состоящей из цветных блоков. Игрок может нажать на блок, чтобы удалить его из решетки. Но чтобы удаление блока стало возможным, он должен иметь сверху, снизу или рядом соседний блок того же цвета.
Когда игрок нажимает на доступный для удаления блок, он убирается. К тому же, убирается и соседний блок того же цвета. Все соседи одного цвета с удаленным блоком удаляются тоже. Таким образом, связанная область блоков одного цвета может быть удалена нажатием на любой из блоков этой области.
После удаления группы блоков их верхние соседи спускаются вниз на освободившиеся места. Если какая-нибудь колонка блоков оказывается совершенно пустой, решетка сдвигается влево, чтобы заполнить свободные места.
На рис. 14.8 показано начало игры. В добавление к одному из четырех цветов я поместил на каждый блок маленький рисунок, соответствующий цвету блока. Это облегчает распознавание блоков на черно-белом рисунке. Единственный способ действительно понять игру- это сыграть в нее, поэтому сделайте это прямо сейчас, прежде чем продолжать читать дальше.

Рисунок 14.8 Игра "Рекурсивные блоки" начинается со случайной решетки цветных блоков

Задача проекта

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

Подход

Решетка представляет собой серию клипов, созданных с помощью Action-Script. Когда пользователь щелкает по блоку, он удаляется из решетки после того, как отмечен его цвет. Потом каждый из его четырех соседей подвергается проверке, не того же ли он цвета. Если не того же, удаленный блок восстанавливает свой исходный цвет.
Метод удаления блоков является рекурсивным. Каждый сосед выделенного курсором блока проверяется, какого он цвета. Если того же; проверяется каждый его сосед, и т. д. Этот рекурсивный метод в конце концов находит блок, который не имеет соседей того же цвета, и рекурсия заканчивается.
Если вы не вполне уверены, что понимаете, как работает эта рекурсия, посмотрите пример шаг за шагом. Например, пользователь щелкнул по красному блоку. Из четырех его соседей блок сверху и блок справа тоже красные. Возьмите блок сверху. Среди его соседей нет красных блоков. Возьмите блок справа. Блок снизу от него тоже красный. Возьмите этот третий красный блок. Среди его соседей нет красных блоков. Таким образом, блок, по которому пользователь щелкнул, удаляется. Удаляется также блок сверху, блок справа и блок снизу от блока справа.
Хотя игра не определяет, сделал ли пользователь все возможное, она присуждает очки. Лучший способ определения очков в подобной игре -это экспоненциальная система присуждения очков. Таким образом, если удаляется группа из двух блоков, игрок получает 4 очка: 2 раза по 2. Если удаляется группа из 3 блоков, игрок получает 3 раза по 3, или 9 очков. Если же удаляется группа из 4 блоков, игрок получает 4 раза по 4, или 16 очков.
Эта система подсчета очков поощряет игрока находить большие группы блоков. Например, удаление 10 групп по 2 блока принесет пользователю 40 очков (2 раза по 2 будет 4, 10 раз по 4 будет 40). Удаление же одной группы из 20 блоков приносит пользователю 400 очков (20 раз по 20). Пользователь должен не только искать большие группы блоков, но пытаться сам их создавать, вытаскивая маленькие группы таким образом, чтобы большие группы пришли в соприкосновение и сформировали еще большую группу.

Подготовка ролика

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

Создание кода


Создание блоков происходит в функции startGame. Функция совершает циклы по 20 горизонтальным колонкам и 12 вертикальным рядам и создает 240 блоков. Каждый блок - это новый экземпляр клипа "block", созданного функцией attachMovie. Кроме того, чтобы оказаться в нужном месте рабочего поля, каждый блок обладает свойствами x и у, таким образом, позже он сможет определить свое положение. Выбирается случайное число от 1 до 4, и клип с блоком отправляется к этому кадру.

function startGaine () {
// Переходим к кадру игры.
gotoAndStop("Play");
score = 0;
// Создаем решетку из блоков,
level = 0;
for(var x=0;x<20;x++) {
forlvar y=0;y<12;y++) {
mc = _root.attachMovie("block","block "+x+" "+y,level);
mc._x = 20*x + 85;
mc._y = 20*y + 60;
mс.x = x ;
mс.у = у ;
// Выбираем случайный цвет.
mc.gotoAndStop(Math.ceil(Math.random()*4));
level++;
}}
}

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

on(release) {
_root.clickBlock(x,у);
}

Функция clickBlock определяет цвет блоков и хранит его в переменной Затем блок удаляется (точнее, его клип переходит к пустому кадру). Функция testNeighbor вызывается четыре раза, один раз для каждого соседа. Функция возвращает количество подходящих соседей, найденных в данном направлении. Если, например, сосед сверху того же цвета и три его соседа тоже, возвращается число 4. Добавляя это число к переменной n, вы получаете полное количество блоков в группе.
Если обнаружено, что группа состоит более чем из одного блока, вызываются функции collapseDown и collapseAcross, чтобы удалить все блоки группы. В противном случае выделенный блок возвращается к прежнему цвету, и кажется, что ничего не произошло.

// Произошел щелчок по блоку,
function clickBlock(x,у) {

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

// Определяем цвет этого блока.
var с = _root["block "+x+" "+y]._currentframe;
_root["block "+x+" "+y].gotoAndStop(5);
II Проверяем его соседей по всем направлениям.
var n = 1;
n += testNeighbor(х-1,у,с);
n += testNeighbor(х+1,у,с);
n += testNeighbor(х,у-1,с);
n += testNeighbor(х,у+1,с);
// Если один их них того же цвета,
if (n > 1) {
// Уничтожаем группу блоков.
collapseDown();
collapseAcross();
// Начисляем очки,
score += n*n;
} else {
// Оставляем блок на месте.
_root["block "+x+" "+y].gotoAndStop(с);
}}

Функция testNeighbor проверяет цвет нового блока. Если цвет подходит, блок удаляется. Дальше функция вызывает сама себя и проверяет цвета четырех соседних блоков. Она следит за переменной n, которая определяет количество подходящих соседей.
Если текущий блок не подходит по цвету, вместо n возвращается 0, чтобы показать, что в этом направлении не было найдено ни одного подходящего блока.

function testNeighbor(x,у,с) {
if (_root["block "+x+" "+y]._current frame = = с) {
// Удаляем соседа.
_root [ "block "+x+""+y].gotoAndStop(5);
var n = 1;
// Проверяем всех его соседей,
n += testNeighbor(x-1,y,с);
n += testNeighbor(х+1,у,с);
n += testNeighbor(х,у-1,с);
n += testNeighbor(x,y+l,с);
// Возвращаем количество найденных соседей,
return(n);
} else {
// Не найдено никаких подходящих блоков.
return(0);
}}

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

function collapseDown() {
// Проходим по всем столбцам.
for(var x=0;x<20;x++) {
// Проходим по всем блокам столбца снизу вверх.
for(var y=11;y>0;y--) {
// Смотрим, пустой ли блок.
thisColor = _root["block "+x+'"+y]._currentFrame;
if (thisColor == 5) {
// Если да, просматриваем все блоки над ним.
for(var i=y-1;i> = 0;i —- ) {
// Если блок не пустой.
aboveCoior = _root[ "block "+x+" ,"+i] ._currentframe;
if (aboveCoior != 5) {
// Смещаем его вниз.
_root["block "+x+""+y].gotoAndStop(aboveCoior);
_root["block "+x+" "+i].gotoAndStop(5)
break;
}}}}}}

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

function collapseAcross() {
// Продолжаем, пока есть пустые столбцы,
do {
n = 0;
// Проверяем все столбцы,
for(var x=0;x<19;x++) {
// Если текущий столбец пустой.
if (_root["block "+x+" 11"]._currentframe = = 5) {
// Если следующий - полный, if (_root["block "+(x+1)+" 11"] _currentframe != 5)
{ n++;
// Смещаем все блоки.
for(var у=0,-у<12;у++){
c = _root["block "+(x+1)+" "+y]._currentframe;
_root["block "+x+" "+y].gotoAndStop(c);
_root["block "+(x+1)+" "+y].gotoAndStop(5);
}}}}
// цикол прекращается, если больше не обнаружено пустых столбцов
} while (n > 0);
}

К сведению

В игре имеется поле score, помешенное под игровой областью. Оно отслеживает переменную score, которая увеличивается в процессе исполнения функции clickBlock.

Другие возможности

Один момент в этой игре пропущен - способ узнавать, когда игра закончилась. Вы можете поместить кнопку "I'm Done!" в кадре и дать возможность игроку решать, когда игра закончена.
Однако можно использовать ActionScript, чтобы определить два возможных пути завершения игры. Первый, это когда все блоки удалены. Это редкость; большинство игр оставляют несколько неудаляемых блоков. Но, если это случится, вы можете определить это, выясняя, не пуст ли самый нижний левый блок после того, как функция collapseDown запушена.

if (_root["block 0 11"]._currentFrame == 5) {
gotoAndStop("gameOver");
}

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