Игровой автомат
Исходный файл: Slotmachine.fla
Игровой автомат - игра функционально простая, но с довольно сложным интерфейсом. Игрок просто щелкает по рычагу игрового автомата и ждет результата. Автомат сам выполняет всю оставшуюся работу.На рис. 15.1 показан фрагмент ролика Slotmachine.fla. Рычаг справа единственный элемент, который будет реагировать на действия игрока. Когда игровой автомат останавливается, в трех окошках отображаются картинки.
Задача проекта
В отличие от многих игровых автоматов, в которых используются интересные, но сложные способы для определения ставок и получения Рисунок 15.1 Простой игровой автомат с рычагом и тремя окошкамивыигрыша, этот предельно прост. Игрок щелкает по рычагу, чтобы привести его в действие. Затем барабаны в трех окнах начинают крутиться. Один за другим они будут останавливаться, показывая произвольный элемент (картинку).
Когда все три барабана останавливаются, картинки, оказавшиеся в них, и определяют результат. Выигрыш соответствует тем суммам, которые показаны внизу игрового автомата (см. рис. 15.1).
Подход
Единственной сложной частью кода в игре является вращение. Осуществить это можно следующим образом: сделать так, чтобы различные картинки прокручивались в окошке снизу вверх. Проблема заключается в том, что картинки должны вертеться так же быстро, как крутятся барабаны в реальном игровом автомате. На большинстве компьютеров программа Flash не может проигрывать ролик с такой скоростью. Вместо этого можно воспользоваться размытой анимацией вращения, которая представляет собой клип, состоящий из нескольких "размытых" кадров. На рис. 15.2 показаны несколько подобных кадров. Рисунок 15.2 Эти кадры анимаиии создают эффект крутящегосябарабана при быстром воспроизведении
В каждом из трех окон будет отображаться копия клипа spin. Когда придет время вращения барабана, всем трем клипам будет сообщаться о воспроизведении, а также передаваться точное число вращений. Эти значения будут различными для каждого клипа, так что барабаны будут останавливаться не одновременно.
Просмотрите ролик Slotmachine.fla, чтобы увидеть, как крутятся барабаны и как они последовательно останавливаются.
Подготовка ролика
В этом ролике используются три ключевых библиотечных эталона, все остальное - элементы фона. Первый эталон - рычаг, в его первом кадре находится кнопка, по которой может щелкнуть игрок. Остальная часть клипа - анимация рычага, показывающая, как нажали рычаг.Клип "spin" начинается с пустого кадра, где он "ждет", пока игрок не щелкнет по рычагу. Кадр прозрачный, так что сквозь него виден клип "symbols".
В остальных кадрах клипа "spin" находится размытая анимация. За изображениями, показанными на рис. 15.2, расположен белый непрозрачный фон, закрывающий клип "symbols" во время вращения колес.
В клипе "symbols" находятся семь кадров, во всех содержатся разные символы. В ролике Slotmachine.fla это изображения желудя, яблока, листа, бревна, луны, солнца и лисы.
Создание кода
Большая часть кода для этой игры находится в основной временной шкале. Однако сначала разберем те фрагменты кода, которые относятся к клипам.В ролике Slotmachine.fla под клипом с рычагом размещена кнопка. К ней прикреплен простой сценарий, который вызывает функцию pull, находящуюся в основной временной шкале.
on
(release) {
pull();
}
numTimes--;
if (numTimes <= 0) {
gotoAndStop(l);
_root.spinDone(_name);
} else {
gotoAndPlay(2); }
initGame() ;
stop();
function initGame() {
// Случайным образом выбираем кадры для трех символов,
for (i=l;i<4;i++) {
_root["symbol"+i].gotoAndStop(randomSymbol());
}
// Начинаем со $100.
cash = 100;
showCash();
}
// Отображаем сумму в долларах,
function showCash() {
cashDisplay.= "$"+cash;
}
// Рычаг переходит в нижнее положение,
function pull(); {
// Когда рычаг приводится в действие,
// каждый раз вычитаем один доллар.
cash--;
showCash() ;
// Воспроизводим анимацию рычага.
_root["arm"].gotoAndPlay(2);
// Воспроизводим анимацию вращения,
for (i=l; i<4; i++) {
// Сообщаем, сколько раз нужно вращать барабан.
_root["spin"+i].numTimes = 8-i*2;
_root["spin"+i].gotoAndPlay(2); }
// Выбираем результат для каждого символа случайным образом.
for (i=l; i<4; i++) {
_root["symbol"+i].gotoAndStop(randomSymbol());
}}
У реальных игровых автоматов необычайно сложный метод выбора символов, которые появятся в окошках. В таком методе используются сложные математические формулы, так что казино может точно рассчитать вероятность выигрыша.
Но вероятность появления одного символа должна отличаться от вероятности появления другого символа. Например, символ с бревном появляется в 29% случаев. С другой стороны, символ лисы появляется только в 3% случаев.Это осуществляется с помощью массива, куда записывается вероятность появления того или иного символа. Затем произвольным образом выбирается число из этого массива. Если оно попадает в диапазон между нулем и вероятностью появления первого символа, выбирается первый символ. В противном случае программа переходит к следующему числу в массиве. Так происходит до тех пор, пока какой-нибудь символ не будет выбран. Просмотрите следующий код, чтобы увидеть, как работает эта схема.
// Выбираем произвольный символ в зависимости
//от вероятности его появления.
function randomSymbol() {
// Задаем вероятность появления каждого символа.
chances = [29,21,16,12,9,7,6];
// Определяем сумму вероятностей.
totalChances = 0;
for (j=0; j
// Выбираем случайное число.
г = int(Math.random()*totalChances);
// Определяем, какой символ это число представляет,
for (j=0; j< chances.length; j++) {
if (r < chances[j]) {
return!j+1);
} else {
r -= chances[ j ] ;
}}}
// Вызываем функцию после каждой анимации вращения,
function spinDone(name) {
// Определяем, последний ли это символ,
// остановились ли барабаны.
if (name == "spinl") {
// Подсчитываем сумму выигрыша,
win = calcWin();
cash += win;
showCash() ;
}}
// Определяем сумму выигрыша,
function calcWin() {
// Выясняем, сколько выпало изображений с желудем
numAcorns = 0;
for (i=l; i<4; i++) {
if (_root["symbol"+i]._currentFrame == 2)
numAcorns++;
// Проверяем, совпадают ли три символа.
firstSymbol = _root["symboll"]._currentFrame;
threeOfAkind = true;
for(i=2; i<4; i++) {
if (_root["symbol"+i]._currentFrame != firstSymbol)
threeOfAKind= false;
// Определяем сумму выигрыша в соответствии с типом символа.
if (threeOfAKind) {
if (firstSymbol == 1) {
win = 20;
} else
if (firstSymbol == 2) {
win = 10;
} else if (firstSymbol ==3) {
win = 30;
} else if (firstSymbol == 4) {
win = 50;
} else if (firstSymbol == 5) {
win = 80;
} else if (firstSymbol == 6) {
win = 100;
} else if (firstSymbol == 7) {
win = 1000;
// Два изображения желудя.
} else if (numAcorns ==2) {
win = 2;
// Один желудь.
} else if (numAcorns ==1) {
win = 1;
// Изображений желудя нет.
} else {
win = 0;
return(win);}
К сведению
Если вы посмотрите на ролик, который приводится в качестве примера, то увидите, что фон игрового автомата на самом деле располагается на переднем плане. Три окна - это "дырки" в изображении, сквозь них видно, как проигрывается анимация вращения, а также видны символы на барабанах.Вы можете указать действия, которые будут совершаться, если деньги на счету игрока закончатся. Можно проверять это условие и, если оно оказывается истинным, переходить к другому кадру. Можно сообщить игроку, что игра окончена, либо предоставить еще 100 долларов, чтобы игрок сыграл еще раз.
Другие возможности
В более сложных игровых автоматах в одном окне могут находиться сразу несколько символов. В некоторых автоматах символы отображаются также и по вертикали, так что игрок может выиграть, если совпадут символы по трем горизонтальным линиям и двум диагоналям. Иногда игрок может выбирать, сколько монет (от одной до пяти) "вставить" в автомат, чтобы определить потенциальный выигрыш (он будет зависеть от величины ставки).Так как Flash-ролик - не игра на деньги, а просто развлечение, то более важно предусмотреть возможность изменения графики для соответствия различным темам Web-сайтов. Например, для детского сайта можно сделать картинки с конфетами. Изменяя внешний вид автомата и картинки, одну и ту же программу можно использовать для оформления разных сайтов.
Видеопокер
Исходный файл: Videopoker.fla
В казино автоматы с видеопокером располагаются рядом с игровыми автоматами. По существу, они представляют собой то же самое: вы вставляете монету и можете выиграть некоторую сумму денег. Единственное различие состоит в том, что в течение игры вы должны совершать некоторые действия, чтобы повлиять на результат, а автомат будет на них реагировать.Не ошибитесь: казино всегда выигрывает. Но так как игрок может заменять некоторые карты в течение игры, ему кажется, что у него появляется больше шансов на выигрыш. Такая возможность усложняет написание программы.
Задача проекта
Эта игра состоит из трех шагов. Первый шаг - игра ждет, пока игрок попросит сдать карты. На втором шаге игрок смотрит на пять карт, которые ему раздали, и решает, какие оставить, а какие - поменять. И последний шаг - раздаются новые карты, и подсчитывается сумма выигрыша. После чего осуществляется переход к первому шагу.Игра должна представить игроку набор из пяти карт, выбранных случайным образом из перемешанной колоды (рис. 15.3). Рисунок 15.3 Видеопокер показывает игроку пять карт
Затем игрок может выбрать те карты, которые следует поменять (можно поменять все). После замены программа должна рассмотреть окончательный набор карт и подсчитать, сколько они "стоят".
Подход
Первое, что необходимо программе, - это перетасованная колода карт, которая будет представлять собой массив с символьными данными, например "h7", что означает семерка червей. Четыре масти представлены буквами "с", "d", "h" и "s". Туз обозначен "1", то есть «c1" означает туз треф, а валет, дама и король обозначены цифрами "И", "12" и "13" соответственно.Создать упорядоченную колоду карт просто, совсем другое дело - создание перетасованной колоды. Для этого вы берете упорядоченный массив и, выбирая из него случайным образом элементы, один за другим помешаете их в новый массив.
Затем первые пять карт в массиве отображаются на экране. Под каждой картой располагается кнопка. Один щелчок мыши по ней переворачивает карту, так что будет видна рубашка карты. Второй щелчок возвращает карту в исходное положение на тот случай, если игрок передумал.
Когда игрок будет удовлетворен своим выбором, он щелкает по кнопке Draw (Поменять). Те карты, которые были выбраны длят замены, замешаются следующими картами из перетасованной колоды.
Самый сложный фрагмент программного кода нужен для конечной фазы игры. Окончательный массив из пяти карт должен быль оценен с точки зрения покера. Вот список возможных вариантов:
• младшая пара - пара карт одного достоинства (десятка или ниже);Для того чтобы определить, удовлетворяет ли набор карт вышеуказанным критериям, необходимо проанализировать массив с картами несколькими способами.
• старшая пара - пара валетов, дам, королей или тузов;
• тройка - три карты одного достоинства;
• стрит - пять карт, ранг каждой из которых на единицу превышает ранг предыдущей карты, например восьмерка, девятка, десятка, валет и дама. Туз может располагаться как перед двойкой, так и послекороля;
• флэш - пять карт одной масти;
• фул хаус - пара и три карты одного достоинства;
• каре - четыре карты одного достоинства;
• стрейт флэш - пять карт одной масти, ранг каждой из которых на единицу превышает ранг предыдущей карт;
• роял флэш - стрейт флэш с десяткой, валетом, дамой, королем и тузом.
После того как будет определена ценность карт, останется сделать последний шаг - сопоставить ее с суммой выигрыша и увеличить наличность игрока.
Подготовка ролика
Основной библиотечный элемент в данной игре - колода карт, то есть клип с 54 кадрами. Первый кадр отображает пустой контур карты. Во втором кадре содержится рубашка карты. Кадры 3-54 показывают различные карты колоды. Каждый кадр имеет такое же имя, какое используется в коде для идентификации карт. Например, "c1" - туз треф и "h11" -валет червей.Просмотрите ролик Videopoker.fla и вы увидите, что для клипа "deck" выделена целая папка библиотеки, заполненная графическими изображениями. Это упрощает повторное использование элементов для разных карт.
Ролик составлен из пяти экземпляров клипа "deck" (колода), которые называются "card0", "card1", "card2", "card3" и "card4". В первом кадре
нужна только кнопка "Deal" (Раздать), которая отображается также и в третьем кадре.
Во втором кадре находится кнопка "Draw" (Выигрыш), а под каждой картой - кнопка "Hold/Replace" (Оставить/Поменять).
Создание кода
Большая часть кода содержится в первом кадре основной временной шкалы. Начинается она с того, что игроку предоставляется 100 долларов.startGame();
stop () ;
// "Выдаем" исходную сумму,
function startGame() {
cash = 100;
}
// Отображаем сумму наличных со знаком доллара,
function showCash() {
cashDisplay = "$"+cash;
}
// Сдача карты,
function startDeal() {
// Уменьшаем сумму наличных денег.
cash--;
showCash();
// Перетасовываем карты и снова сдаем их.
createDeck();
f irstDraw();
showCards(); }
Затем программа случайным образом выбирает карты из упорядоченной колоды и помещает их в другой массив. Когда массив заполняется, а предыдущий массив оказывается пустым, у вас получается перетасованная колода карт.
// Создаем перетасованную колоду,
function createDeckO {
// Создаем упорядоченную колоду,
suits = ["с","d","s","h"];
temp = new Array();
for(suit=0; suit<4; suit++) {
for (num=l; 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); }
// Сдаем первые пять карт.
function firstDraw() {
cards = new Array();
for (i=0; i<5; i++) {
cards.push(deck.pop());
}
// Допускаем, что игрок оставляет все карты,
hold = [true, true, true, true, true];
showCards();
}
// Определяем вид клипов карт, сданных игроку.
function showCards() {
for (i=0; i<5; i++) {
_root["card"+i].gotoAndStop(cards[i]) ;
}}
Первый раз, когда щелкают по кнопке, программа изменяет экземпляр клипа так, что отображается рубашка карты. Если игрок щелкает по ней еще раз, карта возвращается в исходное состояние. Игрок может сколько угодно переворачивать карты, прежде чем щелкнуть по кнопке Draw.
В массиве hold будет находиться значение true, если игрок хочет оставить соответствующую карту, и false, если хочет ее заменить.
// Переворачиваем карту, предназначенную для замены,
function holdDraw(cardNum) {
// Переворачиваем карту, которая находится среди тех,
// которые игрок хочет оставить,
if (hold[cardNum]) {
_root["card"+cardNum].gotoAndStop("back");
hold[cardNum] = false;
// Если карта перевернута еще раз, оставляем ее.
} else {
_root["card"+cardNum].gotoAndStop(cards[cardNum]);
hold[cardNum] = true;
}}
Затем программа с помощью функции handvalue определяет, какой расклад имеется у игрока. Ценность расклада передается функции winning, которая рассчитывает, какую сумму следует добавить к величине cash (сумме наличных). Переменная resultsDisplay используется для отображения этих значений на экране.
// Заменяем карты и определяем выигрыш,
function secondDraw() {
// Заменяем карты, for (i=0; i<5; i++) {
if (!hold[i]> {
cards[i] = deck.pop();
showCards();
// Определяем, что на руках у игрока.
handVal = handValue(cards);
// Расчитываем сумму выигрыша.
winAmt = winning(handVal);
resultsDisplay = handVal + ": " + winAmt;
// Добавляем сумму выигрыша к имеющейся сумме наличных,
cash += winAmt;
showCash();
gotoAndPlay("done");
}
Функция compareHands берет две карты и сравнивает их. Для каждой карты из символьной строки она выбирает первый и второй символы, то есть игнорирует нулевой символ. Таким образом, карта "с7" становится "7", а "с13" - "13".
Затем функция возвращает один из трех вариантов ответов: -1 - первая карта меньше по достоинству второй карты, 0 - карты одинакового достоинства, и 1 - ранг первой карты на единицу больше ранга второй.
Эта функция необходима для команды sort, использующейся в функции handvalue. Если для сортировки не будет специальной функции, программа попытается отсортировать массив hand по алфавиту, то есть все трефы будут расположены перед бубнами, так как трефовая масть начинается с буквы "с", а бубновая - с "d". А вам нужно, чтобы карты были отсортированы в соответствии с их рангом.
// Эта функция используется командой сортировки для определения,
// какие карты идут первыми,
function compareHands(a,b) {
// Получаем ранг карты.
numa = Number(a.substr(1,2));
numb = Number (b. subs t r (1,2) ) ;
// Возвращаем -1, 0 или 1 в зависимости
//от результата сравнения,
if (numa < numb) return(-1);
if (numa == numb) return(O);
if (numa > numb) return(1);}
Например, если на руках у игрока имеются карты ["h4", "d5", "c2", "s3", "h6"], после сортировки массив будет выглядеть следующим образом: ["с2", "s3", "h4", "d5", "h6"]. Так гораздо проще узнать, находится ли на руках у игрока "стрит".
"Стрит" определяется путем просмотра каждой карты и выяснением, больше ли ранг этой карты на единицу ранга карты предыдущей (2). Если такое условие выполняется для всего массива, то тогда на руках у игрока "стрит".
Таким образом будет определен не только "стрит": когда "стрит" начинается с десятки и заканчивается тузом, то это "флэш стрит". Произошло ли так или нет, можно определить с помощью простого теста (3).
Затем вы проверяете, одной ли масти карты (4). Для этого все карты, кроме первой, сравниваются с первой. Если масть всех карт совпадает с мастью первой карты, значит, все карты одной масти.
На следующем шаге создается массив counts, в котором будет храниться число карт одинакового достоинства (5). В этом массиве находится 14 элементов, каждый из которых будет отвечать за число карт определенного ранга, имеющихся у ифока. Первый элемент массива не используется, так как нет карт с нулевым рангом.
Некоторые люди думают, что стритом можно считать и такой набор карт, в котором задействован туз. Например, дама, король, туз, двойка и тройка. Это не стрит, а всего лишь его дополнительная вариация, используемая в любительских играх в покер. Туз может быть использован и как первая карта стрита (туз, двойка, тройка, четверка, пятерка), и как последняя (десять, валет, дама, король, туз), но только не в середине.
Например, если на руках туз, две тройки, четверка и валет, массив будет выглялеть следующим образом: [0,1,0,2,1,0,0,0,0,0,0,1,0,0].Теперь, наконец, программа может начать определение расклада на руках у игрока. Просматривается массив counts и отмечаются все значения пары, тройки или четверки (6). Если один раз встречаются две карты одного достоинства, то у игрока пара. Если один раз встречается три карты одного достоинства, то у игрока тройка; если один раз встречается четыре карты одного достоинства, то - каре. Также можно дважды обнаружить две карты одного достоинства или пару и тройку. В первом случае будет две пары, а втором - фул хаус.
Затем проверяется, есть ли на руках пары с валетом или картами высшего достоинства (7). Обычно видеопокер отмечает только такие пары.
Следующий тест проверяет, есть ли в раскладе туз (8). Это будет нужно для определения флэш стрита. Если у ифока флэш стрит, и одна из карт - туз, то у него самый высший тип флэш стрита - флэш роял.
Теперь у функции есть весь набор значений логических переменных: straight, flush, hasAce, fourOfAKind, threeOfAKind, twoPair, pair, fullHouse и jackOrHigher. С их помощью определяется действительная ценность расклада, и возвращается символьная строка (9).
// Определяем расклад,
function handValue() {
// Копируем и сортируем карты игрока.
hand = cards.slice();
(1) hand, sort (compareHands) ;
// Создаем массив мастей и рангов для более легкого доступа
//к ним.
suits = new Array();
nums = new Array();
for (i=0; i<5; i++) {
suits.push(hand[i].substr(0,1));
nums.push(Number(hand[i].substr(1,2)));
(2)// Проверяем, расположены ли они по возрастанию,
straight = true;
for (i=0; i<4; i++) {
if (nums[i]+l != num[i+l]) straight = false;
(3)// Ищем десятку, валета, даму, короля и туза,
if (nums[0] == 1) and (nums[l] == 10) and (nums[2]) == 11)
and (nums[3] == 12) and (nums[4] == 13)) straight = true;
(4)// Выясняем, одной ли масти карты,
flush = true;
for (i=l; i<5;l i++) {
if (suits[i] != suitstO]) flush = false;
// Создаем массив для подсчета, сколько карт одного
(5)// достоинства находится в раскладе,
counts = new Array ();
for (i=0; i<14; counts.push(O) ;
for (i=0; i<5;i++) counts[nums[i]]+ +;
(6)// Используя массив counts, ищем совпадения,
pair = false;
twoPair = false;
threeOfAKind = false;
fourOfAKind = false;
for (i=l; i<14; i++) {
// Найдена пара.
if (counts[i] == 2) {
// Найдена вторая пара.
if (pair) {
twoPair = true;
// Найдена только одна пара.
} else {
pair = true;
// Три карты одного достоинства.
} else if (counts[i] == 3) {
threeOfAKind .= true;
// Четыре карты одного достоинства.
} else if (countsfi] == 4) {
fourOfAKind = true;
// Проверяем, есть ли среди совпадающих карт валеты или
(7)// карты более высокого ранга.
jackOrHigher = false;
for (i=l; i<14; i++) {
if (((i==l) or (i>10) and (counts[i]>=2)) {
jackOtHigher = true;
(8) // Выясняем, является ли карта более высокого ранга тузом.
hasAce = false; if (counts[1] > 0) hasAce = true;
(9)// Делаем вывод, какой расклад на руках у игрока.
if (straight and flush and hasAce) {
return("Royal Flush");
} else if (straight and flush) {
return("Straight Flush");
} else if (fourOfAKind) {
return("Four-Of-A-Kind");
} else if (pair and threeOfAKind) {
return ("Full House");
} else if (flush) {
return("Flush");
} else if (straight) {
return("Straight");
} else if (threeOfAKind) {
return("Three-Of-A-Kind");
} else if (twoPair) {
return("Two Pair");
} else if (pair and jaskOrHigher) {
return!"High Pair");
} else if (pair) {
return("Low Pair");
} else {
return("Nothing");
//Исходя из типа расклада возвращаем сумму выиграша
function winnings(handVal) {
if (handVal == "Royal Flush") return(800);
if (handVal == "Straight Flush") return(50);
if (handVal == "Four-Of-A-Kind") return(25);
if (handVal == "Full House") return(8);
if (handVal == "Flush") return(5);
if (handVal == "Straight") return(4);
if (handVal == "Three-Of-A-Kind") return(3);
if (handVal == "Two Pair") return(2);
if (handVal == "High Pair") return(1);
if (handVal == "Low Pair") return(0);
if (handVal == "Nothing") return(0);
}
К сведению
К каждой кнопке Hold/Draw прикреплен собственный фрагмент кода. Для первой кнопки он выглядит следующим образом:on (press) { holdDraw(0);}
Цифра 0 сообщает функции holdDraw, что действие производится с нулевой картой, для остальных четырех кнопок вместо нуля стоят числа от 1 до 4.Хотя первый кадр ролика сразу же вызывает функцию startGame (см. раздел "Создание кода"), второй кадр должен вызывать функцию startDeal. Просмотрите ролик, приведенный в качестве примера, чтобы самостоятельно изучить, как это реализовано.
Другие возможности
Суммы, указанные в функции winnings, я выбрал, руководствуясь обычными правилами покера. Однако вы можете указать другие числа в зависимости от той суммы, которую хотите переводить на счет виртуального казино или игрока.Можно сделать и так: когда на счету игрока не остается денег, переходить, например, к кадру game over.
Еше одна вариация игры - позволить игроку ставить от одного до пяти долларов за игру. Таким образом, игрок ставит меньшую сумму, когда чувствует, что ему не везет, и большую - в других случаях.
Игра в очко, или двадцать одно
Исходный файл: Blackjack.fla
Двадцать одно - еще одна популярная карточная игра в казино, которую легко можно перенести на компьютер. Раздающий карты следуют определенному набору правил, следовательно, можно написать программу, которая будет имитировать действия раздающего.Задача проекта
Наша цель - создать базисный вариант игры в очко, не стремясь реализовать полный набор функций. Некоторые правила в этой игре редко используются, например удваивание ставки, страхование и разделение, но если вы захотите включить их в свою игру, написание кода окажется очень сложной задачей. Оценить наличие таких правил смогут только избранные, поэтому здесь они опущены, чтобы не перегружать книгу лишней информацией.На рис. 15.4 показан кадр ролика Blackjack.fla. Вы видите, что игрок взял пять карт, которые в сумме дали 18 очков. А раздающий карты взял три карты, их сумма составляет 21.
В этой простой игре игроку и раздающему дается по две карты. Первая карта раздающего остается лежать рубашкой вверх до тех пор, пока игрок не закончит набирать карты. Игрок может брать карты до тех пор, пока у него не окажется двадцать одно очко или более. Затем компьютер "выдает" карты раздающему, пока у того не будет минимум 17 очков. Рисунок 15.4 Расклад, когда раздающий выиграл, так как у него 21, а у игрока только 18 очков
Если с первыми двумя картами у игрока 21 очко, он сразу же выигрывает и получает дополнительно 50% суммы выигрыша. Если у раздающего получается 21, игра сразу же приостанавливается. Если же так не случилось, то выигрывает тот, у кого на руках большее количество очков, не превышающее 21.
Игрок может контролировать свои ставки (от 5 до 25 долларов), каждый раз повышая ставку на пять долларов.
Подход
Как и в видеопокере, здесь есть массив deck, в котором содержится перетасованная колода карт. Разница заключается в том, что в этой игре в массиве находятся шесть колод. В игре в очко такой массив называется shoe.Как для игрока, так и для раздающего создается массив, в котором представлены карты, имеющиеся на руках. Вам нужно будет подумать насчет первой карты раздающего, так как она не должна быть видна до тех пор, пока игрок не закончит набирать карты.
В отличие от видеопокера оценка расклада в этой игре проста. Единственная сложность: туз может стоить как одно, так и 11 очков. Однако, так как два туза дадут 22 очка, второй туз никак не может стоить 11. То есть все, что нужно, - определить, есть ли на руках туз, подсчитать, что он равен единице, а затем добавить 10, если при этом на руках не будет перебора. Например, расклад с тройкой, девяткой и тузом рассматривается как 13 очков, потому что если считать, что туз стоит 11, то на руках окажется 23 очка, то есть перебор.
Подготовка ролика
В отличие от видеопокера на руках может быть от двух до 11 карт. Для каждого расклада создаются 11 экземпляров клипов, имена которых изменяются от "player0" до "player10" и от "dealer0" до "dealer10". Кадры клипа "deck" - пусты. Следовательно, когда вы поместите клип на рабочее поле, вы не увидите ничего, кроме меток, которые устанавливаются программой Flash для клипов по умолчанию. На рис. 15.5 показаны все 22 метки. Рисунок 15.5 Все карты представлены в виде маленьких кружочков, меток клипа, так как на данный момент-карты не видныВ этом ролике сложная основная временная шкала. Каждая метка представляет собой различный этап игры. На рис. 15.6 показана шкала в момент, когда видна большая часть меток. Рисунок 15.6 В сложной основной временной шкале игры в очко для каждого шага существует помеченный кадр
В процессе игры указатель текущего кадра передвигается вдоль основной временной шкалы. Каждый ключевой кадр содержит различные функции. Сам код расположен в первом ключевом кадре.
Обязательно просмотрите ролик Blackjack.fla, чтобы самому увидеть, где расположены ключевые кадры и какие функции они вызывают.
Создание кода
Первый кадр вызывает функцию initGame , но после нее не идет команда stop (), так как указатель должен двигаться и перейти к кадру "shuffle".initGame();
Функция initGame определяет исходную сумму наличных денег игрока.function initGame() {
cash = 100;
showCash();
}
Один из недостатков использования шести колод состоит в том, что программе требуется время для, их перетасовки. Следовательно, кадр "shuffle" появляется перед ключевым кадром, вызывающим функцию createDeck. Поэтому слово "shuffle" (Идет перетасовка колоды) появится на экране прежде, чем код начнет тасовать карты. Следовательно, игрок не должен удивляться, почему его компьютер вдруг "завис".
// Создаем перетасованную колоду карт,
function createDeck() {
// Создаем упорядоченную колоду.
suits = ["с", "d", "s", "h"];
temp = new Array();
for (i=0; i<6;i++){
for (suit=0; suit<4; suit++) {
for (num=1; num<4; 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);
}}
// Инициализируем массивов расклада и определяем сумму ставки,
function initHand() {
playerHand = new Array();
dealerHand = new Array();
showDealerFirstCard = false;
bet = 5;
showBet();
}
// Функция увеличивает ставку игрока вплоть до 25 долларов,
function addToBet() {
bet += 5;
if (bet > 25) bet = 25;
showBet;
}
// Вычитаем сумму ставки из суммы наличных денег игрока.
function makeBet() {
cash -= bet;
showCash();
}
// Раздаем игроку одну карту из колоды.
function dealCard(hand) {
hand.push(deck.pop());
}
// Отображаем сумму наличности со знаком "$".
function showCash() {
cashDisplay = "$" + cash;
}
// Отображаем сумму ставки со знаком "$".
function showBet() {
betDisplay = "$" + bet;
}
// Отображаем карты на руках у игрока и раздающего,
function showCards() {
// Отображаем первую карту раздающего, когда игроку
// все карты розданы.
if (showDealerFirstCard) {
_root["dealerO"].gotoAndStop(dealerHand[0]);
} else {
_root[“dealer0"].gotoAndStop(2);
}
// Показываем остальные карты раздающего,
for (i=1; i
}
// Показываем все карты игрока,
for (i=0; i
}
// Отображаем сумму карт на руках.
playerValue = handValue(playerHand);
dealerValue = handValue(dealerHand);
}
// Проверяем, есть ли 21 очко,
function checkForBlackjack() {
// Если двадцать одно у игрока,
// выигрыш составляет 150% ставки.
if (playerHand.length == 2) and (playerValue == 21)) {
cash += bet*2.5;
showCash();
result = "Blackjack!";
gotoAndPlay("Done");
// Если у раздающего двадцать одно, игрок проиграл.
} else if ((dealeerHand.length == 2) and (dealerHand == 21)) {
result = "Dealer has blackjack!";
gotoAndPlay("Done");
}}
// Игрок берет еще одну карту.
function hit() {
dealCard(playeerHand);
showCards();
playerValue = handValue(playerHand);
// Если у игрока 21 очко или больше, выясняем,
// сколько очков у раздающего.
if (playerValue >= 21) startDealer();
}
// Отображаем первую карту раздающего,
// теперь он может набирать себе карты.
function startDealer() {
showDealerFirstCard = true;
showCards(0);
gotoAndPlay("Dealer");
}
// Раздающий берет еще одну карту до тех пор,
// пока сумма очков меньше 17.
function dealerMove() {
if (handValue(dealerHand) < 17) {
dealCard(dealerHand);
shoCards();
gotoAndPlay("Dealer");
// Раздающий закончил набирать карты.
} else {
decidewinner();
}}
// Подсчитываем очки,
function handValue(hand) {
total = 0;
асе = false;
for (i=0; i
val = Number(hand[i].substr(1,2));
11 За валета, даму и короля начисляем 10 очков,
if (val > 10) val = 10;
total += val;
// Запоминаем, если был найден туз.
if (val == 1) асе = true;
}
// Туз может стоить 11 очков, если у игрока не будет перебора.
if ((асе) 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");
}
// Начинаем следующую раздачи карт.
function newDeaK) { resetCards();
// Если в колоде менее 26 карт,
// Создаем новую перетасованную колоду,
if (deck.length < 26) {
gotoAndPlay("shuffle");
} else {
initHand();
gotoAndPlay("Bet");
}}
// Удаляем карты со стола.
function resetCards() {
for (i=0; i
} for (i=0; i
}}
К сведению
Основная временная шкала этого ролика - самая сложная из всех игр, рассмотренных в этой книге. Поэтому важно просмотреть ролик на Web-сайте, чтобы получить четкое представление о том, что и где расположено.Также необходимо создать текстовые поля, в которых будут отображаться сумма очков игрока и раздающего, ставка, сумма наличных и результат.
Другие возможности
Эта игра очень хороша для изучения языка ActionScript, но она разочарует игроков в двадцать одно, играющих на деньги. Поэтому для хороших ActionScript-профаммистов далее представлено руководство, как добавить некоторые возможности этой игры, которые были опущены.Легче всего добавить возможность раздачи только двух карт. Для этого нужно создать кнопку Double (Удваивание ставки) в кадре с меткой "Player". Когда игрок щелкнет по ней, ему дадут еще одну карту, ставка еще раз будет вычтена из суммы наличных денег, и игра перейдет к раздающему. Однако прежде следует убедиться, что игрок не взял какие-либо дополнительные карты, поскольку такая раздача возможна только тогда, когда у игрока на руках первые две карты.
Возможность страхования создать немного сложнее, так как при этом надо написать еше одну "ветвь" программы. Страхование возникает тогда, когда раздающему показывается туз. В этом случае игрок может застраховаться от того, что у раздающего будет 21, на сумму, обычно равную ставке. Если было взято страхование, и у раздающего 21 очко, игра заканчивается. Игрок теряет исходную ставку, но получает страховую сумму.
Разделение - сложное дополнение к игре. Если у игрока две карты одного достоинства, например две девятки, тогда ему может быть разрешено разделить карты на два расклада, каждый из которых будет начинаться с девятки. Следовательно, чтобы можно было хранить карты игрока в одном массиве playerHand, вы должны создать массив из массивов. В большинстве случаев в таком массиве playerHand содержится один массив, который отражает расклад на одной руке. Если игрок разделит карты, то в массиве будут содержаться два массива. Игроку обычно позволяется разделять карты несколько раз, таким образом, в массиве playerHand может содержаться три, четыре и более массивов. Затем нужно сыграть с каждым раскладом игрока. Вы понимаете, насколько это усложняет каждую часть игры. Игрок может выиграть, проиграть или сыграть в ничью по нескольким или всем своим раскладам.
Пасьянс "Пирамида"
Исходный файл: Pyramicd.fla
Пасьянс "Пирамида" не так популярен, как обычный пасьянс, и не так сложен; однако, ему легко научиться и он очень затягивает. На рис. 15.7 . представлено начало игры. Рис. 15.7 В пасьянс "Пирамида" играют с помощью пирамиды из 28 карт и остальной колодыИграть можно любой полностью открытой картой. Если часть карты закрыта другой картой пирамиды, играть этой картой можно только в том случае, если закрывающую ее карту удалить. Удалить карту игрок может только в том случае, если найдет подходящую ей другую карту, чтобы сумма их значений равнялась бы 13. Например, 10 и 3 или 6 и 7 могут составить пару. Туз имеет значение 1, валет значение 11, дама 12 и король 13. Это значит, что только король может быть выбран сам по себе, без второй карты.
Цель, естественно, в том, чтобы убрать из пирамиды все карты. Оставшиеся 24 карты колоды помешены под пирамидой, и за один ход можно перевернуть одну карту. Любая перевернутая карта может быть выбрана вместе с картой из пирамиды так, чтобы составить в сумме число 13.
Попробуйте поиграть в этот пасьянс. Вам придется отложить книгу, поскольку понадобится потратить какое-то время, чтобы окончить игру.
Задача проекта
Цель этого проекта - создание полной версии игры в пасьянс "Пирамида". Программа должна узнавать даже тот редкий случай, когда игрок выигрывает, удаляя все карты из пирамиды. Если игрок чувствует себя в безвыходном положении или текущая партия представляется неплодотворной, он может нажать кнопку и в любое время пересдать карты.Подход
Мы используем такую же колоду, как и в игре "Двадцать одно". Игра начинается с тасовки карт и выстраивания пирамиды. Остальные карты помешаются стопкой мастью вниз внизу экрана. Игрок может щелкнуть, по верхней карте в стопке, и карта отобразится мастью вверх в соседней стопке карт, которая изначально была пустой. Каждый щелчок по стопке карт, лежащих мастью вниз, добавляет одну карту к стопке карт, лежащих мастью вверх.Игрок может выбрать любую незакрытую карту из пирамиды или из стопки карт с открытой мастью. Выбранная карта выделяется рамкой.
Когда игрок щелкает по следующей карте, она сравнивается с первой, чтобы узнать, составит ли она с ней вместе 13 очков. Если да, обе карты удаляются. Если при этом одна из карт находится в стопке карт мастью вверх, то лежащая под ней карта открывается.
Определить, открыта ли какая-то карта в пирамиде, можно, пройдя циклом по всем картам в пирамиде и выясняя, присутствует ли на месте одна
из двух карт, которые должны закрывать данную. Например, вторая карта в третьем ряду должна быть закрыта второй и третьей картой в четвертом ряду. Если какая-нибудь из них на месте, карта не может быть выбрана. Когда карта удаляется из стопки открытых карт, становится видна предыдущая открытая карта. Это означает, что вам нужно следить за стопкой открытых карт, помещая их в массив, как только они оказываются перевернутыми.
Особым случаем является король. Выбранный король немедленно удаляется как из колоды карт с открытой мастью, так и из пирамиды, если, конечно, выбранный король был открыт.
Подготовка ролика
Ролик содержит в библиотеке такой же клип "deck", как в игре "Двадцать одно". Ему необходимо присвоить имя в панели Linkage Properties,чтобы он экспортировался вместе с роликом. То же относится и к клипу "outline". ' В игре присутствует только два кадра: кадр "Play" и кадр "Game over". Последний будет использоваться только в редком случае выигрыша. Оба кадра должны содержать кнопку New, чтобы пересдавать карты в любой удобный игроку момент.Создание кода
Практически весь код находится в главной временной шкале. Он начинается с функции "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. _у = 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 + +) {
me = _root.attachMovie("Deck","stack"+i,level)
mc._x = i*60+100;
mc._y = 340;
mc._xscale =50;
mc._yscale = 50;
level++;}
// Показываем "рубашку" для закрытой колоды.
_root["stackO"].gotoAndStop("back");
(16) // Задаем значение первой выбранной карты и массив для
// открытой колоды.
firstCard = undefined;
stack = new Array();
(17) // Создаем и размещаем рамку.
outline = _root.attachMovie("outline","outline",1000);
outline._xscale = 50;
outline._yscale = 50;
outline._x = -1000;
}
// Создаем перетасованную колоду.
function createDeck() {
// Создаем упорядоченную колоду.
suits = ["с","d","s","h"];
temp = new Array();
for(suit=0;suit<4;suit++) {
for(num=l;num<14;num++) {
temp.pushfsuits[suit]+num);
}}
// Выбираем случайные карты, пока не создадим перетасованную
// колоду.
deck = new Array();
while (temp.length > 0) {
r = int(Math.random()*temp.length);
deck.push(tempt[r]);
temp.splice(r, 1) ;
}}
Сначала она совершает цикл по всем картам в пирамиде и определяет, не совершен ли щелчок по одной из них. (18). Цикл начинается с 28 и совершает обратный отсчет. Таким образом, карты наверху рассматриваются сначала, а карты внизу - потом.
Далее мы проверяем, если по карте был совершен щелчок, то программа определяет, закрывают ли данную карту другие карты пирамиды (19). Для этого вызывается функция cardPresent вместе со значениями ряда и колонки двух карт, которые могли бы закрывать карту, по которой был совершен щелчок.
Если локальная переменная card все еще не определена, значит, ни одна карта не была выбрана. Нужно еще проверить, не выбрал ли игрок карту из стопки карт с открытой мастью. Эту колоду представляет клип "stack1" (20).
Если карта была выбрана, а глобальная переменная firstcard все еще не определена, значит, не выбрана никакая другая карта. Ссылка на выбранную карту помещается в firstcard (21).
Если другая карта уже выбрана, значения старой и новой карт складываются. Функция cardValue используется для хранения численных значений карт (22). Если сумма равна 13, обе карты удаляются при помощи функции removeCard.
Если, с другой стороны, значение firstcard равно 13, значит, это король, и он может быть удален сам по себе (23).
Если по клипу "stack0" был совершен щелчок, это значит, что игрок решил перенести карту из закрытой колоды в открытую. В этом случае берется последнее значение в массиве 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+l,card.col) or cardPresent(card.row+1,card.col+l)) {
card = undefined;
}}
(20)// Был ли щелчок по стопке карт, лежащих мастью вверх?
if (card == undefined) {
if (stackl.hitTest(_xmouse,_ymouse)) {
card = stack1;
}}
// Проверяем, выбрана ли еще одна карта,
if (card != undefined) {
(21)// Первая выбранная карта,
if (firstCard == undefined) {
firstCard = card;
// Игнорируем второй щелчок по той же карте.
} else if (firstCard == card) {
(22)// Если выбраны две карты и их сумма равна 13.
} else if (cardValueffirstCard) + cardValue(card) == 13) {
// Удаляем обе карты.
removeCard(card);
removeCard(firstCard);
firstCard = undefined;
// В противном случае считаем, что это первая выбранная
// карта.
} else {
firstCard = card;
}}
(23)// Если выбрана одна карта, и это "король"
if (cardValueffirstCard) ==13) {
removeCardffirstcard);
firstCard = undefined;
}}
(24)// Если щелкнули по колоде закрытых карт, переворачиваем
// очередную карту.
if (stackO.hitTest(_xmouse,_ymouse)) {
stackl.value = deck.pop();
stackl.gotoAndStop(stackl.value);
stack.push(stackl.value);
// Когда закрытая колода кончается, удаляем ее.
if (deck.length == 0) {
stackO.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");
}}
function rernoveCard(thisCard) {
if (thisCard == stackl) {
// Удаляем карту из открытой колоды,
stack1.gotoAndStop(1);
stack.pop();
stackl.value = stack[stack.length-l];
stack1.gotoAndStop(stackl.value);
} else {
// Удаляем карту из пирамиды.
thisCard.removeMovieClip();
}}
function cardPresent(row, col) {
// Проверяем, существует ли в пирамиде данная карта.
for(var i=0;i<28;i++) {
thisCard = _root["card"+i] ;
if ((thisCard.row == row) and(thisCard.col == col)) {
return (true);
}}
return(false);
}
function cardValue(card) {
// Удаляем первый символ из значения value.
n = card.value;
n = parselnt(n.substr(1,2));
return(n);
}
function clearGame() {
// Удаляем карты из пирамиды.
for(var i=0;i<28;i++) {
_root["card"+i].removeMovieClip();
}
// Удаляем обе колоды
stack0.removeMovieClip();
stack1.removeMovieClip();
}
К сведению
Кнопка New на экране имеет простой сценарий и сначала вызывает clearGame, а потом startGame. Это перезапускает игру в любой удобный пользователю момент.on (press) {
clearGame();
startGame();
}
Другие возможности
Игру можно сделать значительно проще, если вы разрешите игроку переворачивать колоду уже открытых карт и смотреть карты столько раз, сколько он захочет. Вы можете сделать это, опознавая, когда массив deck пуст, и помещая каждую карту из массива stack обратно в массив deck.Кроме этого пасьянса вы можете создать много других. В моей коллекции более 200 вариантов подобных игр. Большинство из них требует вытаскивания карт и перекладывания из стопки в стопку. Это делает код гораздо более сложным, но не невозможным для опытного программиста.