Adobe Flash. Создание аркад, головоломок и других игр с помощью ActionScript
Шрифт:
Кадр «Dealer» проигрывается снова и снова, каждый раз вызывается функция dealerMove, проверяется сумма очков раздающего, больше ли она 17 или нет. Правилами казино определено, что раздающий берет еще одну карту до тех пор, пока сумма очков не превысила 16. Когда раздающий закончил набирать карты, вызывается функция decideWinner.
// Раздающий берет еще одну карту до тех пор,
// пока сумма очков меньше 17.
function dealerMove {
if (handValue(dealerHand) < 17) {
dealCard(dealerHand);
shoCards;
gotoAndPlay("Dealer");
// Раздающий закончил набирать карты.
} else {
decideWinner;
}
}Функция handValue используется во многих ранее рассмотренных функциях для того, чтобы определить сумму очков на руках. Ранг каждой карты добавляется к сумме очков, при этом туз равен одному очку. Если на руках находится туз и добавление 10 очков не приведет к перебору, тогда к общей сумме прибавляется 10 очков.
// Подсчитываем очки.
function handValue(hand) {
total = 0;
ace = false;
for (i=0; i<hand.length; i++) {
// Добавляем ранг карты.
val = Number(hand[i].substr(1,2));
// За валета, даму и короля начисляем 10 очков.
if (val > 10) val = 10;
total += val;
// Запоминаем, если был найден туз.
if (val == 1) ace = true;
}
// Туз может стоить 11 очков, если у игрока не будет перебора.
if ((ace) and (total <= 11)) total += 10;
return(total);
}С помощью набора правил следующая функция определяет победителя. В случае выигрыша игрока не только корректируется
// Определяем победителя или случай игры в ничью.
function decideWinner {
showCash;
if (playerValue > 21) {
result = "You Busted!";
} else if (dealerValue > 21) {
cash += bet*2;
result = "Dealer Busts. You Win!";
} else if (dealerValue > playerValue) {
result = "You Lose!";
} else if (dealerValue == playerValue) {
cash += bet;
result = "Tie!";
} else if (dealerValue < playerValue) {
cash += bet*2;
result = "You Win!";
}
showCash;
gotoAndPlay("Done");
}В кадре Done находится кнопка Next Hand (Сыграть еще раз), которая вызывает следующую функцию, проверяющую, осталось ли в колоде 26 карт. Если в колоде карт меньше, заново создается перетасованная колода. Если осталось достаточное количество карт, вызывается функция initHand, и игра возвращается к кадру «Bet». В любом случае вызывается функция resetCards, которая устанавливает все находящиеся на рабочем поле клипы «deck» в первый кадр, благодаря чему карты не остаются на экране.
// Начинаем следующую раздачи карт.
function newDeal {
resetCards;
// Если в колоде менее 26 карт,
// Создаем новую перетасованную колоду.
if (deck.length < 26) {
gotoAndPlay("shuffle");
} else {
initHand;
gotoAndPlay("Bet");
}
}
// Удаляем карты со стола.
function resetCards {
for (i=0; i<dealerHand.length; i++) {
_root["dealer"+i.gotoAndStop(1);
}
for (i=0; i<playerHand.length; i++) {
_root["player"+i].gotoAndStop(1);
}
}
К сведению
Основная временная шкала этого ролика – самая сложная из всех игр, рассмотренных в этой книге. Поэтому важно просмотреть ролик на Web-сайте, чтобы получить четкое представление о том, что и где расположено.
Также необходимо создать текстовые поля, в которых будут отображаться сумма очков игрока и раздающего, ставка, сумма наличных и результат.
Другие возможности
Эта игра очень хороша для изучения языка ActionScript, но она разочарует игроков в двадцать одно, играющих на деньги. Поэтому для хороших ActionScript-программистов далее представлено руководство, как добавить некоторые возможности этой игры, которые были опущены.
Легче всего добавить возможность раздачи только двух карт. Для этого нужно создать кнопку Double (Удваивание ставки) в кадре с меткой "Player". Когда игрок щелкнет по ней, ему дадут еще одну карту, ставка еще раз будет вычтена из суммы наличных денег, и игра перейдет к раздающему. Однако прежде следует убедиться, что игрок не взял какие-либо дополнительные карты, поскольку такая раздача возможна только тогда, когда у игрока на руках первые две карты.
Возможность страхования создать немного сложнее, так как при этом надо написать еще одну ветвь программы. Страхование возникает тогда, когда раздающему показывается туз. В этом случае игрок может застраховаться от того, что у раздающего будет 21, на сумму, обычно равную ставке. Если было взято страхование, и у раздающего 21 очко, игра заканчивается. Игрок теряет исходную ставку, но получает страховую сумму.
Разделение – сложное дополнение к игре. Если у игрока две карты одного достоинства, например две девятки, тогда ему может быть разрешено разделить карты на два расклада, каждый из которых будет начинаться с девятки. Следовательно, чтобы можно было хранить карты игрока в одном массиве playerHand, вы должны создать массив из массивов. В большинстве случаев в таком массиве playerHand содержится один массив, который отражает расклад на одной руке. Если игрок разделит карты, то в массиве будут содержаться два массива. Игроку обычно позволяется разделять карты несколько раз, таким образом, в массиве playerHand может содержаться три, четыре и более массивов. Затем нужно сыграть с каждым раскладом игрока. Вы понимаете, насколько это усложняет каждую часть игры. Игрок может выиграть, проиграть или сыграть в ничью по нескольким или всем своим раскладам.Пасьянс «Пирамида»
Исходный файл: Pyramidfla
Пасьянс "Пирамида" не так популярен, как обычный пасьянс, и не так сложен; однако, ему легко научиться и он очень затягивает. На рис. 15.7 представлено начало игры.
Рисунок 15.7. В пасьянс «Пирамида» играют с помощью пирамиды из 28 карт и остальной колоды
Играть можно любой полностью открытой картой. Если часть карты закрыта другой картой пирамиды, играть этой картой можно только в том случае, если закрывающую ее карту удалить. Удалить карту игрок может только в том случае, если найдет подходящую ей другую карту, чтобы сумма их значений равнялась бы 13. Например, 10 и 3 или 6 и 7 могут составить пару. Туз имеет значение 1, валет значение 11, дама 12 и король 13. Это значит, что только король может быть выбран сам по себе, без второй карты.
Цель, естественно, в том, чтобы убрать из пирамиды все карты. Оставшиеся 24 карты колоды помещены под пирамидой, и за один ход можно перевернуть одну карту. Любая перевернутая карта может быть выбрана вместе с картой из пирамиды так, чтобы составить в сумме число 13.
Попробуйте поиграть в этот пасьянс. Вам придется отложить книгу, поскольку понадобится потратить какое-то время, чтобы окончить игру.
Задача проекта
Цель этого проекта – создание полной версии игры в пасьянс «Пирамида». Программа должна узнавать даже тот редкий случай, когда игрок выигрывает, удаляя все карты из пирамиды. Если игрок чувствует себя в безвыходном положении или текущая партия представляется неплодотворной, он может нажать кнопку и в любое время пересдать карты.
Подход
Мы используем такую же колоду, как и в игре «Двадцать одно». Игра начинается с тасовки карт и выстраивания пирамиды. Остальные карты помещаются стопкой мастью вниз внизу экрана. Игрок может щелкнуть по верхней карте в стопке, и карта отобразится мастью вверх в соседней стопке карт, которая изначально была пустой. Каждый щелчок по стопке карт, лежащих мастью вниз, добавляет одну карту к стопке карт, лежащих мастью вверх.
Игрок может выбрать любую незакрытую карту из пирамиды или из стопки карт с открытой мастью. Выбранная карта выделяется рамкой.
Когда игрок щелкает по следующей карте, она сравнивается с первой, чтобы узнать, составит ли она с ней вместе 13 очков. Если да, обе карты удаляются. Если при этом одна из карт находится в стопке карт мастью вверх, то лежащая под ней карта открывается.
Определить, открыта ли какая-то карта в пирамиде, можно, пройдя циклом по всем картам в пирамиде и выясняя, присутствует ли на месте одна из двух карт, которые должны закрывать данную. Например, вторая карта в третьем ряду должна быть закрыта второй и третьей картой в четвертом ряду. Если какая-нибудь из них на месте, карта не может быть выбрана.
Когда карта удаляется из стопки открытых карт, становится видна предыдущая открытая карта. Это означает, что вам нужно следить за стопкой открытых карт, помещая их в массив, как только они оказываются перевернутыми.
Особым случаем является король. Выбранный король немедленно удаляется как из колоды карт с открытой мастью, так и из пирамиды, если, конечно, выбранный король был открыт.
Подготовка ролика
Ролик содержит в библиотеке такой же клип «deck», как в игре «Двадцать одно». Ему необходимо присвоить имя в панели Linkage Properties, чтобы он экспортировался вместе с роликом. То же относится и к клипу «outline».
В игре присутствует только два кадра: кадр "Play" и кадр "Game over". Последний будет использоваться
Создание кода
Практически весь код находится в главной временной шкале. Он начинается с функции «startGame». После того как создана новая, перетасованная, колода, создается семь рядов карт (10) . Первый ряд содержит одну карту, второй – две и т. д.
Каждая карта помещается на свое место в соответствии с рядом и местом в ряду (11). К тому же масштаб каждой карты уменьшен на 50 %, поскольку колода, использованная в игре «Двадцать одно», в два раза больше по размеру той, что необходима для этой игры (12) .
Значение карты берется из массива deck (13) . Оно соответствует метке кадра внутри клипа «deck». Это значение сохраняется в свойстве value клипа, после чего клип отправляется в соответствующий кадр. В свойствах клипа row и col хранится позиция клипа в пирамиде (14) .
Затем вы создаете клипы для стопок карт мастью вниз и мастью вверх (15) . Клип для карт мастью вниз отправляется в кадр «back», показывающий изображение рубашки карты. Другая стопка остается в первом кадре, который пуст.
Переменная firstcard установлена как undefined (16) . Эта переменная содержит значение первой карты в паре, выбираемой самим игроком. Массив stack используется для слежения за судьбой карт из стопки мастью вверх. В случае, когда карта из этой стопки используется, должно быть отыскано значение предыдущей выбранной карты.
В заключение должен быть создан экземпляр клипа рамки (17). В начальный момент он помещается за пределами видимости.startGame;
stop;
function startGame {
// Тасуем колоду.
createDeck;
(10) → // Выстраиваем карты в пирамиду.
level = 0;
for(row=0;row<7;row++) {
for(i=0;i<=row;i++) {
// Создаем новый клип.
mc = _root.attachMovie("Deck","card"+level,level);
(11) → // Задаем его расположение.
mc._x = i*60-row*30 + 275;
mc._y = row*30 + 50;
(12) → // Задаем масштаб.
mc._xscale = 50;
mc._yscale = 50;
(13) → // Устанавливаем знчение карты.
mc.value = deck.pop;
mc.gotoAndStop(mc.value);
(14) → // Запоминаем позицию карты.
mc.row = row;
mc.col = i;
level++;
}
}
(15) → // Размещаем клипы открытой и закрытой колод.
for(i=0;i<2;i++) {
mc = _root.attachMovie("Deck","stack"+i,level);
mc._x = i*60 + 100;
mc._y = 340;
mc._xscale = 50;
mc._yscale = 50;
level++;
}
// Показываем "рубашку" для закрытой колоды.
_root["stack0"].gotoAndStop("back");
(16) → // Задаем значение первой выбранной карты и массив для открытой колоды.
firstCard = undefined;
stack = new Array;
(17) → // Создаем и размещаем рамку.
outline = _root.attachMovie("outline","outline",1000);
outline._xscale = 50;
outline._yscale = 50;
outline._x = -1000;
}Функция createDeck такая же, как в игре «Двадцать одно». Однако теперь вы сортируете только одну колоду. Результат представляется в виде глобальной переменной deck.
// Создаем перетасованную колоду.
function createDeck {
// Создаем упорядоченную колоду.
suits = ["c","d","s","h"];
temp = new Array;
for(suit=0;suit<4;suit++) {
for(num=1;num<14;num++) {
temp.push(suits[suit]+num);
}
}
// Выбираем случайные карты, пока не создадим перетасованную колоду.
deck = new Array;
while (temp.length > 0) {
r = int(Math.random*temp.length);
deck.push(temp[r]);
temp.splice(r,1);
}
}Вместо того, чтобы использовать сценарий клипа или кнопку для обнаружения щелчков мыши, я определю функцию для обработки события onMouseDown.
Сначала она совершает цикл по всем картам в пирамиде и определяет, не совершен ли щелчок по одной из них (18) . Цикл начинается с 28 и совершает обратный отсчет. Таким образом, карты наверху рассматриваются сначала, а карты внизу – потом.
Далее мы проверяем, если по карте был совершен щелчок, то программа определяет, закрывают ли данную карту другие карты пирамиды (19) . Для этого вызывается функция cardPresent вместе со значениями ряда и колонки двух карт, которые могли бы закрывать карту, по которой был совершен щелчок.
Если локальная переменная card все еще не определена, значит, ни одна карта не была выбрана. Нужно еще проверить, не выбрал ли игрок карту из стопки карт с открытой мастью. Эту колоду представляет клип «stack1» (20) .
Если карта была выбрана, а глобальная переменная firstcard все еще не определена, значит, не выбрана никакая другая карта. Ссылка на выбранную карту помещается в firstcard (21).
Если другая карта уже выбрана, значения старой и новой карт складываются. Функция cardValue используется для хранения численных значений карт (22) . Если сумма равна 13, обе карты удаляются при помощи функции removeCard.
Если, с другой стороны, значение firstcard равно 13, значит, это король, и он может быть удален сам по себе (23) .
Если по клипу "stackO" был совершен щелчок, это значит, что игрок решил перенести карту из закрытой колоды в открытую. В этом случае берется последнее значение в массиве deck и используется для изменения кадра клипа «stack1» (24) . Массив stack используется для отслеживания карт, которые перемещаются между стопками.
Чтобы выделить выбранную карту, клип "outline" перемещается в то же положение, что и выбранная карта (25) .
И наконец, проверяется первая карта пирамиды (26) . Если она отсутствует, значит, игрок ее удалил и выиграл игру._root.onMouseDown = function {
var card = undefined;
(18) → // Смотрим, был ли щелчок по одной из карт пирамиды.
for(var i=27;i>=0;i–) {
if (_root["card"+i].hitTest(_xmouse,_ymouse)) {
var card = _root["card"+i];
break;
}
}
(19) → // Если был, закрывают ли эту карту другие карты?
if (card != undefined) {
if (cardPresent(card.row+1,card.col) or cardPresent(card.row+1,card.col+1)) {
card = undefined;
}
}
(20) → // Был ли щелчок по стопке карт, лежащих мастью вверх?
if (card == undefined) {
if (stack1.hitTest(_xmouse,_ymouse)) {
card = stack1;
}
}
// Проверяем, выбрана ли еще одна карта.
if (card != undefined) {
(21) → // Первая выбранная карта.
if (firstCard == undefined) {
firstCard = card;
// Игнорируем второй щелчок по той же карте.
} else if (firstCard == card) {
(22) → // Если выбраны две карты и их сумма равна 13.
} else if (cardValue(firstCard) + cardValue(card) == 13) {
// Удаляем обе карты.
removeCard(card);
removeCard(firstCard);
firstCard = undefined;
// В противном случае считаем, что это первая выбранная карта.
} else {
firstCard = card;
}
}
(23) → // Если выбрана одна карта, и это «король».
if (cardValue(firstCard) == 13) {
removeCard(firstcard);
firstCard = undefined;
}
(24) → // Если щелкнули по колоде закрытых карт, переворачиваем очередную карту.
if (stack0.hitTest(_xmouse,_ymouse)) {
stack1.value = deck.pop;
stack1.gotoAndStop(stack1.value);
stack.push(stack1.value);
// Когда закрытая колода кончается, удаляем ее.
if (deck.length == 0) {
stack0.removeMovieClip;
}
}
(25) → // Помещаем рамку около выделенной карты.
if (firstCard != undefined) {
outline._x = firstCard._x;
outline._y = firstCard._y;
} else {
outline._x = -1000;
}
(26) → // Если удалена первая карта в пирамиде, значит игрок выиграл.
if (_root["card0"] == undefined) {
gotoAndStop("game over");
}
}