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



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

         

Викторина во Flash

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

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

Рисунок 12.1 В основном кадре игры показан вопрос и четыре варианта ответа

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

Цель проекта – создать программу, которая будет получать вопросы из внешнего текстового файла, затем один за другим предлагать их игроку. Правильность/неправильность ответа обозначается звуковым сигналом.
После того как будут заданны десять вопросов, игра окончится. На экране должно отобразиться набранное количество очков. Запустите ролик Flashquiz.fla, и сыграйте несколько раундов, чтобы получить представление о работе программы.

Подход

Сначала нужно получить вопросы и ответы из текстового файла. Для этого можно воспользоваться объектом loadVars, который позволяет загружать данные из внешнего файла.
К сожалению, объект loadVars не позволяет обрабатывать массивы или объекты, а такая возможность нужна для рационального хранения набора вопросов и ответов. Однако можно прочесть один фрагмент текста, с помощью команды split разбить его на части и сохранить полученное в массиве. Таким образом вы получите из одного текстового блока десять вопросов, четыре варианта ответа на каждый вопрос и номер правильного ответа.
Как только вопросы будут расположены в массиве, сделать все остальное не составит труда. Текст каждого вопроса и ответов помешаются в соответствующих текстовых полях. Номер правильного ответа присваивается переменной. Затем программа ждет, когда игрок щелкнет по кнопке.
Каждая кнопка вызывает функцию, передавая ей соответствующий ответ. Если игрок щелкнул по правильной кнопке, проигрывается звуковой сигнал, и увеличивается число заработанных очков. В противном случае звучит сигнал неправильного ответа и задается следующий вопрос.
После того как будут заданы десять вопросов, игра переходит к кадру "game over", где отображается число набранных очков.
Чтобы сделать игру интереснее, вы можете использовать специальный эффект, благодаря чему текст вопроса будет "въезжать" на экран справа.


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

Многое нужно определить до того, как начнется выполнение сценария. Первый кадр (рис. 12.2) - это "loading" (загрузка). Так как вопросы загружаются из внешнего текстового файла, прежде чем начать игру, надо убедиться, что все вопросы находятся на месте.
После загрузки вопросов код ActionScript переводит игру ко второму кадру, помеченному "start game". В этом кадре даны указания для игры и показана кнопка (рис. 12.3).
Основной кадр игры (рис. 12.1) - самый сложный. В нем находится текстовое поле для вопроса, четыре текстовых поля для ответов и маленькое текстовое поле для номера вопроса. Слева от ответов расположены четыре кнопки.

Рисунок 12.2 На экране отображается кадр "loading" до тех пор, пока не будут загружены все вопросы

Каждое из пяти основных текстовых полей помечено в клипе словом "text". Один клип называется "question", остальным присвоены имена от "answer0" до "answer3". Так сделано для того, чтобы не создавать простые текстовые поля и иметь возможность перемешать клипы на рабочем поле (об этом эффекте будет рассказано далее).

Рисунок 12.3 Кадр "start game" виден, пока пользователь не щелкнет по кнопке начала игры

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

Код этой игры невелик по объему, но, тем не менее, разделен на несколько фрагментов. В первом кадре находится код, загружающий вопросы из внешнего файла.
Сценарий начинается с создания нового объекта LoadVars. Этот объект с помощью своих свойств позволяет решать набор специфических задач,связанных с загрузкой переменных. Вы можете получать информацию о том, что данные были отправлены на сервер или загружены с сервера.
Поскольку вам нужен ответ от сервера, то изначально необязательно устанавливать какие-либо свойства объекта LoadVars. Подробнее мы рассмотрим эти приемы в главе 17 "Сложные приемы". Метод load объекта LoadVars обращается к серверу и загружает данные.

Метод load объекта LoadVars осуществляет загрузку, обращаясь к указанному URL. Файл данных должен иметь вид "имя переменной = данные". Например, в результате обращения к текстовому файлу myVariable=Hello переменной myvariable будет присвоено значение Hello. Поскольку обращение происходит к удаленному серверу, может пройти некоторое время между вызовом команды load и загрузкой данных.

Итак, в начале сценария создается новый объект loadQuestions. С помощью метода load он обращается к файлу Flashquiz.txt.
Свойство onLoad объекта LoadVars определяет функцию, которая вызывается, когда загрузка завершена. В этом случае будет вызвана функция initQuestions.
После выполнения команды LoadVars. load данные из текстового файла будут доступны к использованию ActionScript. Например, если переменной myProperty присвоено значение myValue, то обращение loadQuestionsmyProperty. вернет значение myValue.

stop();
// Загружаем вопросы.
loadQuestions = new LoadVars();
loadQuestions.load("flashquiz.txt");
// Вызываем initQuestions, когда загрузка окончена.
loadQuestions.onLoad = initQuestions;

Функция initQuestions преобразовывает текстовую строку в массив, состоящий из вопросов, ответов и номера правильного ответа для каждого вопроса.
Вот как выглядит первая часть файла Flashquiz.txt. Первая строчка присваивает свойству topic текст "The Planets". С помощью обращения loadQuestions.topic сценарий получит доступ к этому значению и присвоит его переменной topic. Результат отобразится в динамическом текстовом поле.

topic=The Planet&questions=Which planet is closest to the Sun?:
Jupiter;Saturn;Mercury,-Mars:2:

Обратите внимание, в текстовом файле переменные необходимо разделять знаком "&". Переменная questions состоит из нескольких строчек; в каждой содержится отдельный вопрос. Каждый вопрос состоит из трех частей: текст вопроса, ответы и номер правильного ответа. Части отделяются друг от друга двоеточием, а в качестве разделителя ответов мы используем точку с запятой.

Which planet is titled on its axis the most?:
Earth;Venus;Mars;Uranus:3:
Which planet is the largest?:Jupiter;Earth;Neptune;Pluto:0:
Which planet has exactly two moons?:Venus;Mars,-Saturn;Uranus:1:

тема=планеты&вопросы=Какая планета ближайшая к солнцу?:
Юпитер;Сатурн;Меркурий;Марс:2:
У какой планеты ось имеет наибольший наклон?:
3емля;Венера;арс; Уран :3 :
Какая планета самая большая?:Юпитер;3емля;Нептун;Плутон:0:
Какая планета имеет две луны?:Венера;Марс;Сатурн,-Уран:1:

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

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

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

function initQuestions(questions) {
// Задаем значение переменной topic,
topic = loadQuestions.topic;
// Разбиваем на отдельные вопросы.
// Внимание: в некоторых случаях лучше использовать
// значение 13, а не 10.
qArray = loadQuestions.questions.split(String.fromCharCode(10));
// Разбиваем строчку вопроса на элементы,
for(i=0;i qArray[i] = qArray[i].split(":");
// Отделяем ответы друг от друга.
qArray[i][1] = qArray[i][1].split(";");}
// Начинаем игру. _root.gotoAndPlay("start game");
}

Я использовал выражение String. fromCharCode (13), чтобы получить символ возврата каретки, что нужно для отделения строк в текстовом файле. Почему я не применил константу newline? Дело в том, что newline в программе Flash отличается для систем Macintosh и Windows. В Macintosh возвращается значение 13, а в Windows - 10. Более того, некоторые текстовые редакторы предпочитают значение 10, а некоторые оба! Так что, если игра не движется далее первого вопроса, попробуйте поменять 10 на 13, чтобы проверить, не в этом ли проблема.

Когда игра переходит к кадру "play", код ActionScript в основной временной шкале сразу же вызывает функцию initGame, которая обнуляет переменные questionNum и numRight и вызывает функцию displayQuestion, отображающую первый вопрос.

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

function initGameO {
// Устанавливаем значения переменных.
questionName = 0;
numRight = 0;
// Выводим первый вопрос.
displayQuestion();
}

Функция displayQuestion определяет, закончена ли игра или нет, и в случае положительного ответа отображает окончательное количество набранных очков и переходит к кадру "game over". В противном случае она берет вопрос и каждый ответ и помешает их в текстовые поля внутри соответствующих клипов. Номер правильного ответа присваивается переменной correctAnswer.

function displayQuestion() {
// Проверяем, все ли вопросы уже заданы,
if (questionNum >= qArray.length) {
// Отображаем окончательное число очков и завершаем игру
finalScore = numRight + "out of" + qArray.length;
gotoAndPlay("game over");
} else {
// Отображаем вопрос и ответы на экране.
question.text = qArray[questionNum][0];
answer0.text = qArray[questionNum][1][0];
answer1.text = qArray[questionNum][1][1];
answer2.text = qArray[questionNum][1][2];
answer3.text =qArray[questionNum][1][3];
// Выводим номер ответа.
questionNumDisplay = questionNum+1;
// Запоминаем, какой ответ верный.
correctAnswer = int(qArray[questionNum][2]
// Делаем так, чтобы текст "въезжал" на экран
animatein();
}
}

Когда у вас массив содержится в другом массиве (двумерный массив), к элементу вложенного массива можно обратиться с помощью нескольких скобок. Например, выражение myArray[3] [8] обращается в восьмому значению третьего элемента массива myArray. Массив ту Array СОСТОИТ ИЗ четырех или более элементов, в третьем элементе содержится, в свою очередь, массив по меньшей мере из девяти элементов.

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

function animatein() {
// Определяем положение каждого элемента текста,
//а также указываем место, где клип должен остановиться.
question.xstop = 300;
question._x = 800;
answerO.xstop = 400;
answer0._x = 1000;
answerl.xstop = 400;
answerl._x = 1200;
answer2.xstop = 400;
answer2._x = 1400;
answer3.xstop = 400;
answer3._x = 1600;
}

Когда пользователь щелкает по одной из четырех кнопок, вызывается функция selectAnswer, которой передается номер выбранного ответа (от 0 до 3). Если эта величина равна correctAnswer, звучит сигнал правильного ответа и увеличивается значение numRight. В противном случае воспроизводится сигнал неверного ответа. В любом случае увеличивается значение переменной guestionNum и отображается следующий вопрос.

function selectAnswer(n) {
// Добавляем очко, если ответ правильный,
if (n == correctAnswer) {
triggerSoundf"right") ; numRight++;
} else {
triggerSound("wrong") ;
}
// Отображаем следующий вопрос.
questionNum++;
displayQuestion();
}

Функция triggersound проста, но очень полезна во многих игровых ситуациях. Ее назначение - проигрывать звук, сопровождающий правильный ответ.

function triggerSoundfsoundName) {
// Проигрываем звук,
soundfx.stop();
soundfx = new Sound();
soundfx.attachSoundfsoundName);
soundfx.start();
}

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

onClipEvent(enterFrame) { if (_x != xstop) _x -= 20;
}

К каждой кнопке также прикреплен короткий сценарий, который при щелчке по ней вызывает функцию selectAnswer и передает ей значение от 0 до 3. Сценарий следующий:

on (release) {
selectAnswer(0); }

Для других кнопок вместо 0 будет указано либо 1, либо 2, либо 3.

К сведению

Вам понадобятся два звука, один с именем "right", а другой - "wrong". Также потребуется кнопка "continue", похожая на изображенную на рис. 12.3. Если у вас есть вопросы по работе программы, просмотрите ролик Flashquiz.fla.

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

Хотя цель игры заключается в отображении только 10 вопросов, ни одна строчка кода не ограничивает их число. Можно запросить большее или меньшее количество вопросов из файла Flashquiz.txt.
Вместе с выводом строки пользователю можно показывать некое сообщение. Например, при отображении строчки "8 out of 10" можно подбодрить пользователя следующим образом: "You know your planets!" (Вы знаете планеты!), а при двух не правильных ответах из 10 будет выводиться сообщение "Go back to school" (Снова идите в школу).

Викторина с учетом времени

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

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

Рисунок 12.4 В этой игре при начислении очков принимается во внимание быстрота ответа

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

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

Подход

Как и в предыдущем ролике, вопросы и ответы будут загружены из внешнего текстового файла. Однако текстовый файл будет немного отличаться. В предыдущей игре ответы были представлены в определенном порядке, и дополнительный элемент указывал, какой ответ верный. Сейчас же правильный ответ всегда будет располагаться первым, а далее будут следовать три неправильных ответа. Такое допустимо, так как ответы все равно будут перемешаны. Вот несколько строк из текстового файла flashtrivia.txt:

questions=The world's first computer bug was actually a real bug
stuck in an early computer. What type of bug was it?:
Moth;Beetle,-Fly;Worm:
Which is the world's largest Island?:
Greenland;Iceland;Australia;New Zealand:
Besides humans, what other animal also has individual
fingerprints?:Koala Bears;Apes;Snakes;Frogs:

Вопросы=Какого типа был первый компьютерный вирус?
:Моль;Жук;Муха;Червь:
Как назывется самый большой остров в мире?
:Гренландия;Исландия;Австралия;Новая Зеландия:
Кроме людей, какие еще животные имеют уникальные отпечатки
пальцев?:Коалы;Обезьяны;Змеи;Лягушки.

Так же, как и при работе над предыдущим проектом, будьте внимательны: не вставьте нечаянно пустую строчку в конце текстового файла. Она появится, если вы нажмете клавишу Return или Enter после ввода последнего вопроса. Если в конце текстового файла будет вставлена пустая строка, она будет рассматриваться как одиннадцатый вопрос.

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

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

В этом ролике четыре кадра. Первый загружает вопросы и ответы и помещает их в массив. Второй кадр содержит информацию о правилах игры.
В третьем кадре начинается само действие, отображается вопрос, четыре ответа, кнопка рядом с каждым ответом, количество возможных очков и счет, оба последних текстовых поля - динамические, первое связано с переменной potentialPoints, а второе - с переменной score.
Помните, что на самом деле четыре ответа - это клипы, в которых находятся текстовые поля, отображающие содержимое переменной text. Однако имена четырех клипов отличаются цифрой: от "answer0" до "answer3".
И последний кадр игры - "game over". В нем показывается окончательный счет, и пользователь может щелкнуть по кнопке, чтобы сыграть заново.

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

Первый фрагмент кода находится в первом кадре главной временной шкалы. По существу это тот же самый код, который применялся в предыдущей игре для загрузки вопросов из текстового файла. Когда вопросы загружены, вызывается функция initQuestions, расположенная в основной временной шкале:

stop () ;
// Загружаем список вопросов.
loadQuestions = new LoadVars();
loadQuestions.load("flashtrivia.txt") ;
loadQuestions.onLoad = initQuestions;

Функция initQuestions разбивает строчку на две части, первая часть- вопрос, вторая - ответы. Затем она отделяет ответы друг от друга.Вся информация хранится в массиве qArray.

function initQuestions(quesions) {
// Выделяем вопросы,
qarray = questions.split(String.fromCharCode(13));
// Отделяем вопрос от ответов,
for (i=0;i qArray[i] = qArray[i].split(":");
// Отделяем ответы друг от друга.
qArray[i][1] = qArray[i][1].split(";");
}}

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

function initGame() {
// Определяем переменные.
questionNum = 0;
score = 0;
// Выводим первый вопрос.
displayQuestion();
}

Функция displayQuestion берет следующий вопрос и помещает вопрос и ответы в соответствующие текстовые поля. Она также устанавливает количество возможных очков за правильный ответ на данный вопрос равным 1000.

function displayQuestion() {
// Проверяем, все ли вопросы заданы,
if (questionNum >= qArray.length) {
// Отображаем окончательный счет, завершаем игру.
gotoAndPlay("game over");
} else {
// Перемешиваем ответы.
answers = shuffleArray(qArray[questionNum][1].slice(O) ) ;
// Выводим вопрос и ответы на экран,
question.text = qArray[questionNum][0];
answerO.text = answers[0];
answerl.text = answers[1];
answer2.text = answers[2];
answer3.text = answers[3];
// Отображаем номер вопроса.
questionNumDisplay = questionNum+1;
// Запоминаем, какой ответ правильный.
correctAnswer = qArray[questionNum] [1] [0] ;
// Воспроизводим анимацию текста.
animateln();
// Присваиваем начальное количество возможных очков - 1000.
potentialPoints = 1000;
}
}

При каждом обращении к кадру "play" клипом "actions" вызывается функция scoreCount. Она вычитает единицу из максимального возможного числа очков, проверяя, чтобы это значение не оказалось менее 0.

//В каждом кадре из максимального возможного числа очков
// вычитаем единицу, function scoreCount() { // Проверяем, на месте ли последний ответ,
if (answers3._x == 400) {
// Вычитаем единицу.
potenrialPoints -= 1;
if (potentialPoints < 0) potentialPoints = 0;
}
}

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

// Берем массив array1 и перемешиваем его элементы
// для массива аггау2.
function shuffleArray(arrayl) {
// Создаем новый, пустой массив.
array2 = new Array();
// Просматриваем массив с помощью цикла,
do {
// Выбираем случайную величину.
г = int(Math.random()*array1.length) ;
// Добавляем элемент в новый массив.
array2.push(array1[r]);
// Удаляем элемент из старого массива,
arrayl.splice(г, 1);
} while (array1.length > 0);
// Возвращаем новый массив,
return(array2);
}
}

Функция animateIn определяет положение четырех ответов с правой стороны рабочего поля. Она указывает, что каждый из этих четырех клипов должен остановиться при перемещении влево, когда достигнет нужного горизонтального положения (400 пикселов от правой границы игрового поля). Сценарий, прикрепленный к каждому клипу, перемещает клип влево до тех пор, пока не будет выполнено вышеуказанное условие.

function animateln() { // Определяем положение каждого ответа
//и указываем место, где каждый клип должен остановиться.
answerO.xstop = 400;
answer0._x = 800;
answer1.xstop = 400;
answer1._x = 1000;
answer2.xstop = 400;
answer2._x = 1200;
answer3.xstop = 400;
answer3._x = 1400;
}

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

function selectAnswer(n) {
// Правильный ответ,
if (answer[n] == correctAnswer) {
triggerSound("right");
// Увеличиваем счет,
score += potentialPoints;
// Выводим следующий вопрос,
questionNum++;
displayQuestion() ;
} else {
// Неправильный ответ.
triggerSound("wrong");
// Уменьшаем количество возможных очков.
potentialPoints -= 200;
if (potentialPoints < 0) potentialPoints = 0;
// Удаляем ответ.
_root["answer"+n].text = "";
}
}

Функция triggerSound работает точно так же, как и в предыдущей игре. Она просто воспроизводит короткий звуковой сигнал.

function triggerSound(soundName) {
// Воспроизводим звук,
soundfx.stop();
soundfx = new Sound();
soundfx.attachSoundtsoundName();
soundfx.start();
}

Другие фрагменты кода кадра "play" включают небольшую часть для клипа "actions", который вызывает метод scoreCount.

onClipEvent(enterFrame) {
root.scoreCount() ;
}

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

onClipEvent(enterFrame) {
if (_x != xstop) _x -= 40;
}

В каждой из четырех кнопок содержится сценарий, инициирующий при ее нажатии функцию selectAnswer. Кнопки реагируют не только на щелчок мыши, для каждой кнопки определена клавиша на клавиатуре. Например, первая кнопка, которую вы видите, помечена "А" (рис. 12.4), она реагирует на нажатие клавиши "А".

on (release, keyPress "A") {
selectAnswer(0);
}

К сведению

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

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

Как и в предыдущей игре, в текстовый файл можно поместить столько вопросов, сколько вы хотите. Если вы знакомы с программированием CGI, вы даже можете написать программу для сервера, которая будет генерировать файл Flashtrivia.txt на основе базы данных вопросов.
Вы также можете изменить начальное количество очков для вопросов, а также число очков, вычитаемых за неправильный ответ.


Игра "Виселица"

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

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

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

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

Рисунок 12.5 Игра "Виселица" проиграна

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

Подход

В игре производится множество действий с символами. Фраза, которую нужно угадать, представляет собой строку символов. Из нее вы создаете строку, в которой вместо букв находятся знаки подчеркивания. Это как раз то, что увидит пользователь.
Когда игрок угадывает букву, она сравнивается с каждой буквой исходной фразы. Если буква совпадает с какой-либо буквой фразы, она отображается на экране на своем месте (или местах).
Если игрок не угадывает, клип с лисой переходит к следующему кадру, в котором добавляется новый фрагмент изображения лисы. Если это последний кадр клипа с лисой, игра заканчивается.

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

Основной элемент - текстовое поле на экране. Сначала в нем находятся только пробелы и знаки подчеркивания, которые постепенно меняются на буквы, угадываемые игроком.
Текстовое поле должно быть динамическим и связано с переменной display. В панели Properties необходимо также выставить свойство Miltiline для текстового поля.
Текст отображается моноширинным шрифтом Monaco, который имеется в стандартной поставке системы Macintosh. Если вы создаете ролик в Windows, возможно, вам придется использовать другой моноширинный шрифт, например Courier New.

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

Игре также необходим клип "actions", который реагирует на нажатие клавиш и передает информацию о нажатой клавише сценарию основной временной шкалы.

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

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

function initGame() { //
Задаем фразу,
phrase = "Imagination is more important than knowledge";
// Создаем отображаемую строку.
display = "" ;
for (i = 0; i // Рассавляем пробелы там, где нужно.
if (phrase.charAt(i) == " ") {
display = idsplay + " ";
} else {
// Заменяем буквы знаками подчеркивания,
display = display + "_";}
}}

Функция charAt возвращает символ, расположенный на определенном месте в строке. Как во многих функциях языка ActionScript, первый символ располагается в позиции 0.

Каждый раз, когда пользователь нажимает клавишу, клип "actions" передает код символа в функцию makeGuess. Первое, что делает эта функция, - преобразовывает код в букву.
Переменная letter проверяется функцией isAlpha на соответствие какой-либо букве, то есть такие клавиши, как пробел иди клавиша с цифрой или другие, просто игнорируются. Более подробно мы рассмотрим функцию isAlpha позднее.
Затем функция makeGuess просматривает каждую букву, чтобы выяснить, совпадает ли она с выбранным символом, во время этого процесса заново формируется переменная display. Каждое найденное совпадение помешается в данную переменную, в которой уже содержатся те буквы, которые совпали ранее.

Функция fromCharCode получает число, например 65, и преобразует его в символ, такой как "А". У всех символов есть соответствующий код. Числа от 65 до 90 относятся к заглавным буквам. Числа от 97 до 122 - к прописным (имеется в виду английский алфавит); 32 обозначает пробел. Полный список символов и их кодов можно найти в документации по Flash.

Изначально переменной gotOne присваивается значение false. Если найдено хотя бы одно совпадение, оно изменяется на true. Если в конце цикла значение переменной все еще равно false, значит, игрок не угадал букву, и клип с изображением лисы переходит к следующему кадру.

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

function makeGuess(code) {
// Получаем символ, соответствующий нажатой клавише,
letter = String.fromCharCode(code);
// Проверяем, является ли символ буквой,
if (isAlpha(letter)) {
// Предполагаем, что буква не будет найдена.
gotOne = false;
// Начинаем заново отображать строку.
newDisplay = "";
for (i=0;i // Проверяем,( совпадают ли буквы.
if (phrase.charAt(i).toUpperCase() == letter.toUpperCase()) {
// Помещаем букву в отображаемый текст.
newDisplay = newDisplay +
letter.toUpperCase();
// Отмечаем найденное совпадение.
gotOne = true;
} else {
// ЕСЛИ совпадения не найдены,
// отображаем те же буквы.
newDisplay = newDisplay + display.charAt(i)}
} // Обновляем строку,
display = newDisplay;
// Если совпадения не найдены, добавляем
// еще один фрагмент в рисунок с лисой,
if (!gotOne) {
fox.mextFrame();
// Проверяем, вся ли лиса изображена,
if (fox._currentFrame ==8) {
gotoAndPlay("lose");
}
} else if (display == phrase.toUpperCase()) {
// Отображаемая строка совпадает с исходной,
// завершаем игру. gotoAndPlay("win");}
}
}

Функция isAlpha берет строчку и проверяет, является ли первый символ буквой или нет.
С помощью функции charCodeAt она получает код первой буквы. Так код для прописных букв на 32 больше, чем для заглавных, для любого кода, который больше 90, мы вычтем 32, чтобы проверять сразу же и прописные, и заглавные буквы.

Функция charCodeAt возвращает код любого символа строки. Единственный аргумент, который ей передается, - это местоположение символа То есть для первого символа следует записать charCodeAt (0).

// Запускаем утилиту для проверки,
// расположен ли символ в пределах от А до Z.
function isAlpha(letter) {
// Определяем код символа.
n = letter.charCodeAt(0) ;
// Преобразуем прописную буквы в заглавную.
if (n > 90) n -= 32;
// Проверяем, расположен ли символ в пределах от А до Z.
return ((n >= 65) and (n<=90));
}

Другой необходимый здесь фрагмент кода расположен в клипе "actions". Он воспринимает любое нажатие клавиши и передает его функции makeGuess

Функция Key.getAscii() возвращает код нажатой клавиши, Она может использоваться внутри функции onClipEvent (keyUp), примененной к клипу.

onClipEvent (keyUp) {
_root.makeGuess(Key.getAscii()));
}

К сведению

В конце ролика нужно вставить кадры "win" и "lose", к которым игра будет переходить при ее завершении. В ролике Hangman.fla эти кадры статичные, но вы можете добавить какую-либо анимацию в любой из них. Например, анимация "win" может показывать, что лису отпускают, в то время как анимация "lose" может демонстрировать что-нибудь устрашающее.

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

В этом примере фраза жестко запрограммирована в функции initGame. Однако можно загружать текст из внешних источников (как это сделать. вы узнали из предыдущих разделов этой главы), так будет проще изменять фразу. Вы даже можете использовать список фраз, которые будут отображаться одна за другой или в случайном порядке.
Если вы хотите включить в игру знаки пунктуации, следует изменить код, чтобы в начале игры кроме пробелов программа автоматически отображала и эти знаки. С помощью функции isAlpha можно проверить, является ли символ буквой, и если нет, то сразу его показать.


Криптограмма

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

Криптограмма - это довольно распространенный вариант головоломки из слов, которая зачастую бывает труднее, чем игра в виселицу. Если вы никогда не видели ничего подобного, загляните в раздел кроссвордов в вашей местной газете. Скорее всего, рядом с ежедневным кроссвордом вы найдете и криптограмму.
В криптограмме предложение или высказывание зашифровано с помощью самой простой технологии: каждая буква алфавита заменена какой-нибудь другой буквой. Например, "Привет" может быть "Бнефид", где Б заменяет П, Н заменяет Р, Е заменяет И, Ф заменяет В, И заменяет Е и Д заменяет Т.

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

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

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

Подход

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

ОПФКТИЭШСЕЙГРМЛАБНЗДЯВЩЧЦЖХЪЮЬЁЫУ.

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

АБВГЛЕЁЖЗИЙКЛМНОПРСТУФХЦЧШШЪЫЬЭЮЯ.

Когда игрок расшифровывает одну из букв, его карта букв изменяется. Например, он решает, что Г соответствует К, тогда карта играющего примет такой вид:

АБВКДЕЙЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ.

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

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

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

На экране только два активных элемента, и то это два почти идентичных динамических текстовых поля. Первое, называющееся decryptedText, связано с переменной decrypted, оно чуть повыше чем второе, названное encryptedText и связанное с переменной encrypted. Шрифт второго поля также чуть светлее.
Оба текстовых поля используют шрифт Courier New, поэтому все буквы занимают одинаковое место, как в игре "Виселица".

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

Необычность этого ролика в том, что весь код помешается в сценарии одного кадра. Весь целиком. Нет ни единой кнопки или клипа. Библиотека этого ролика совершенно пуста.
Сценарий кадра начинается с вызова функции initGame. Она задает фразу и создает карту букв. Карта букв игрока вся состоит из звездочек, обозначающих каждую букву. Результатом должны стать звездочки вместо каждой буквы в расшифрованном текстовом поле. Карта расшифровки, названная letterMap, задается вызовом функции createLetterMap. Вы также можете видеть еще не написанные функции showPhase и showCursor. Первая обновляет текстовое поле на экране, используя последнюю версию карт букв. Вторая выделяет только что выбранную букву полужирным шрифтом. Переменная charpos представляет, какая буква выбрана.

Листенеры - это новое добавление версии Flash MX. Листенер сообщает Flash, что событие произошло, и пора включать набор команд или функцию. Код может создать листенер, определив сначала стандартный объект. Событие, за которым должен следить листенер, в данном случае onKeyUp, задано так, что связано с функцией. Потом команда addListener присоединяет этот объект к объекту Flash, в данном случае объекту Key. Только определенные Flash объекты могут иметь листенеры, и эти листенеры могут быть использованы только для определенных событий, связанных с этими объектами. Например, листенер Key может следить только за событиями onKeyUp и onKeyDown.

В конце функции initGame создается листенер (прослушиватель) клавиатуры, который удостоверяется, что функция getLetter вызывается всякий раз, как игрок нажал клавишу.

initGame() ;
stop() ;
function initGame () {
// Используемая фраза.
phrase = "Imagination is more important than knowledge.Albert Einstein";
// Определяем переменные. createLetterMap();
userMap = "***************";
charpos = 0;
// Показываем курсор и фразу.
showPhrase();
showCursor(};
// Отслеживаем нажатие клавиши.
keyListener = new Object ();
keyListener.onKeyUp = getLetter;
Key.addListener(keyListener);
}

Чтобы создать случайную карту букв, нужно просто перебрать все буквы и приписать новую, случайную букву к каждой букве алфавита. Однако это не так просто. Вам нужно быть уверенным не только в том, что вы взяли какую-нибудь букву, но также и в том, что раньше вы ее не брали. Например, вы не хотите приписать Р как к А, так и к Б.
Следующая сложность появляется, когда вы осознаете, что не хотели бы обозначить букву как саму себя. Таким образом, например, если Г обозначает Г, вы должны выкинуть эту карту и сделать новую.
Функция createLetterMap отрабатывает цикл, пока не найдет пригодную карту букв. Обычно это происходит с первой или со второй попытки.

// Создаем случайную строку,
function createLetterMap() {
do {
// Повторяем, пока не будет найдена корректная карта.
letterMap ="";
for (var i=0;i<26;i++) {
do {
// Повторяем пока не выбрана буква
r = Math.floor(Math.random()*26);
//Случайное число,
с = String.fromCharCode(r+65);
//Конвертируем в букву.
} while (letterMap.indexOf(с) > -1);
letterMap += с;
// Проверяем верность карты,
bad = false; forfvar i=0;i<26;i++) {
if (letterMap.charCodeAt(i) == i+65) {
bad = true;
// Буква в разрешенной позиции.
break;}
} } while (bad);
}

Функция showPhrase просматривает фразу. Она прогоняет каждую букву через letterMap, чтобы получить зашифрованное значение. Затем она прогоняет каждую зашифрованную букву через userMap, чтобы придать текущее, определенное пользователем, значение. Если знак является не буквой, а пробелом или знаком препинания, он показывается без зашифровки.

function showPhrase() {
encrypted = "";
decrypted = "";
for (var i = 0; i < phrase.length; i++) {
// Значение буквы в этой позиции,
с = phrase.toUpperCase().charAt(i);
if ((" .-,'").indexOf(c)>-1) {
// Задаем пустое место.
encrypted += с;
decrypted += с;
} else {
// Используем карту для поиска зашифрованной буквы.
encryptedChar = letterMap.charAt(с.charCodeAt(0)-65);
encrypted += encryptedChar;
// Используем вТОрую карту для поиска расшифрованной
decryptedCharacter = userMap charAt(encryptedChar.charCodeAt(0)-65);
decrypted += decryptedCharacter;
}}
}

Когда пользователь нажимает клавишу, листенер объекта Key вызывает функцию getLetter. Нажатая клавиша помещается в две переменные ascii для ASCII-кода и code для кода клавиатуры. Значения ascii используются для идентификации букв, а значения code - для идентификации клавишей со стрелками.
Если клавиши со стрелками нажаты, происходит обновление переменной charpos. В конце этой функции вызывается функция showCursor, и правильная буква выделяется полужирным шрифтом.
Если нажата буква, происходит обновление userMap, чтобы показать, что пользователь хочет поставить нажатую клавишу в соответствие с текущей закодированной буквой. Текстовое поле обновляется с помощью showPhrase. После этого расшифрованная фраза сравнивается с исходной, чтобы выяснить, насколько она ей соответствует.

function getLetter() {
// Считываем ascii код и код клавиатуры.
var ascii = Key.getAscii();
var code = Key.getCode() ;
// Передвигаем курсор,
if (code == Key.LEFT) {
charpos--;
if (charpos < 0) charpos = 0;
} else if (code == Key.RIGHT) {
charpos++;
if (charpos > phrase.length-1) charpos = phrase.length-1;
} else {
// Считываем клавиши.
var keyChar = String.fromCharCode(ascii);
keyChar = keyChar.toUpperCase();
// Убеждаемся, что была нажата буква.
if ((keyChar >= "A") and (keyChar <= "Z")) {
// Считываем символ из фразы.
phraseChar = phrase.toUpperCase().charCodeAt(charpos)- 65;
// Если это буква.
if ((phraseChar >= 0) and (phraseChar < 26)) {
// Получаем ее значение в карте
letterNum = letterMap.charCodeAt(phraseChar)-65;
// Заменяем букву во второй карте.
userMap = replaceChar (userMap, letterNum,keyChar) ,
// Обновляем фразу showPhrase();
//Проверяем, не окончена ли игра,
if (phrase.toUpperCase() == decrypted) {
gotoAndStop("game over");
}}
}}
// Обновляем курсор.
showCursor();
}

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

// Заменяем букву в строке.
function replaceChar(mainString, num, newchar) {
newString = mainString.substring(0,num)+ newchar +mainString.substring(num+1,mainString.length) ;
return(newString);
}

Чтобы показать пользователю, к какой букве относится переменная charpos, эта буква выделяется полужирным и в зашифрованном, и в расшифрованном поле. Сделать это можно с помощью объекта типа TextFormat:, появившегося в версии Flash MX. Объекты TextFormat имеют множество свойств. Когда вы применяете формат текста к текстовому полю, в поле меняются только те свойства, которые были специаль заданы в объекте.
Объект plainFormat типа TextFormat обозначает только то, что полужирное выделение ошибочно. Таким образом, если он применен к текстовым полям decryptedText и encryptedText все полужирные буквы заменяются на обычные. Объект cursorFormat имеет противоположное действие. Все буквы, к которым он применен, становятся полужирными. Код устанавливает формат текста только одной буквы в поле, которая соответствует charpos.

function showCursorf) {
// Оба поля устанавливаем невыделенным шрифтом.
plainFormat = new TextFormat();
plainFormat.bold = false;
decryptedText.setTextFormat(plainFormat);
encryptedText.setTextFormat(plainFormat);
// Одну букву выделяем полужирным.
cursorFormat = new TextFormat();
cursorFormat.bold = true;
decryptedText.setTextFormat(charpos,cursorFormat);
encryptedText.setTextFormat(charpos,cursorFormat);

К сведению

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

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

По мере того, как игрок движется вдоль фразы с помощью клавиш со стрелками, курсор иногда оказывается над пробелом или другим неактивным знаком. Вы можете расширить код, чтобы следить за движением курсора и, когда он находится на пустым пространством, заставить его продолжать движение вперед или назад, пока он не коснется буквы.
Хотя исходный ролик содержит фразу, встроенную в код, вы можете считывать ее с помощью команд LoadVariables или LoadVars. Это дает вам возможность изменять фразу без перекомпилирования swf-файла.