В предыдущей части этой серии мы соединили наш интерфейс для игры в Блэкджек и создали колоду карт. В этой части руководства мы добавим необходимую игровую логику в блэкджек. Давайте начнем!
17. CreateDataFile ()
Нам нужен способ хранить деньги игрока между игровыми сессиями, и для этого мы будем использовать простой текстовый файл. Добавьте следующий код ниже функции createDeck()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
function createDataFile()
local path = system.pathForFile( «data.txt», system.DocumentsDirectory )
local fh, errStr = io.open( path, «r» ) — r means read mode
if fh then
print(«DataFile Exists Already») — already exists so we just return from this function
return
else
print( «Reason open failed: » .. errStr ) — display failure message in terminal
— create file because it doesn’t exist yet
fh = io.open( path, «w» ) — w means write mode
if fh then
local money = 500
fh:write(money)
else
print( «Create file failed!»..errStr )
end
io.close(fh)
end
end
|
Здесь мы создаем файл с именем « data.txt » и записываем 500 в него. Игрок начнет игру с $ 500,00 . Важно убедиться, что вы всегда вызываете io.close()
когда завершаете свои операции.
Вы можете узнать больше о создании этого файла данных в документации на сайте Corona.
18. ReadFile ()
Теперь, когда у нас есть способ создать наш файл данных, нам нужен метод для чтения его содержимого. Введите следующее ниже функции createDataFile()
вы ввели на шаге выше.
01
02
03
04
05
06
07
08
09
10
11
|
function readMoney()
local path = system.pathForFile( «data.txt», system.DocumentsDirectory )
local fh, errStr = io.open( path, «r» )
if fh then
local theMoney = fh:read( «*n» )
return theMoney
else
print( «Reason open failed: » .. errStr ) — display failure message in terminal
end
io.close(fh)
end
|
Мы открываем файл тем же методом, затем используем read("*n")
чтобы получить значение из текстового файла. « * N » означает читать как число.
19. SaveMoney ()
Для завершения наших операций с файлами нам нужен способ сохранения. Введите следующее под кодом, который вы ввели на шаге выше.
01
02
03
04
05
06
07
08
09
10
|
function saveMoney(money)
local path = system.pathForFile( «data.txt», system.DocumentsDirectory )
local fh, errStr = io.open( path, «w» )
if fh then
fh:write(money)
else
print( «Reason open failed: » .. errStr ) — display failure message in terminal
end
io.close(fh)
end
|
Здесь мы открываем файл для записи, как обозначено » w » в методе open()
. Затем мы записываем money
в файл, который был передан в качестве параметра.
20. Установка начального баланса
Теперь нам нужно создать начальный баланс при первом запуске игры. Добавьте следующее в начало Setup()
.
1
2
3
4
5
6
7
8
|
function Setup()
createDataFile();
setupCoins();
setupButtons();
setupTextFields();
setupGroups();
createDeck();
end
|
Если вы откроете терминал Corona и дважды запустите приложение, вы увидите распечатанный на терминале файл DataFile уже существует . Я оставил сообщения print()
в коде обработки файлов, чтобы вы могли видеть шаги и любые ошибки. Если все работает хорошо, не стесняйтесь удалять их.
21. Показ начального баланса
Итак, теперь, когда мы установили баланс, давайте покажем его в нашем приложении. Измените следующий код в функции setupTextFields()
.
1
2
3
4
5
6
7
8
|
function setupTextFields()
instructionsText = display.newText( «Place Your Bet», 300, 300, native.systemFont, 30 );
instructionsText:setTextColor( 0,0,0)
bankText = display.newText(«Your Bank:$ «..readMoney(),10,905,native.systemFont, 30 );
bankText:setTextColor(0,0,0)
betText = display.newText(«»,650,906,native.systemFont,30);
betText:setTextColor(0,0,0);
end
|
Обратите внимание, что мы добавляем остаток в « Ваш банк: $ », вызывая readMoney()
.
22. Ставки
Теперь, когда у нас есть деньги, мы можем добавить код в нашу betHandler()
. Мы создали эту функцию в предыдущей части руководства, поэтому убедитесь, что вы добавили ее, а не переопределяли!
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
local betHandler = function( event )
local theMoney = readMoney();
if event.phase == «began» then
local t = event.target
if(bet + t.betAmount > theMoney)then
print(«Trying to bet more than have»);
print(«Money is»..theMoney);
return;
else
bet = bet + t.betAmount
local tempImage = display.newImage(«money»..t.betAmount..».png»);
local randomX = (math.random() * 150);
local randomY = (math.random() * 100);
tempImage.x = randomX;
tempImage.y = randomY;
coinContainer:insert(tempImage);
dealBtn.isVisible = true;
instructionsText.text = «»;
betText.text = «Your Bet: $»..bet;
end
end
end
|
Здесь мы сначала читаем, сколько денег игрок имеет. Если они пытаются поставить больше, чем имеют, функция просто возвращается. Я оставил операторы print()
в коде, чтобы помочь с отладкой. Мы устанавливаем динамический ключ betAmount
, когда устанавливаем деньги. Если они не пытаются ставить слишком много, мы добавляем сумму к переменной bet
.
Затем мы создаем tempImage
, генерируем два случайных числа, устанавливаем изображения x
и y
на случайные числа и, наконец, добавляем изображение в контейнер для монет. Вы заметите, что мы используем "money"..t.betAmount..".png"
для URL изображения. Наши изображения для денег называются « money10.png », « money25.png » и « money50.png », поэтому все, что мы здесь делаем, это объединяем их вместе, чтобы сформировать строку изображения.
Наконец, мы устанавливаем dealBtn
instructionsText
и устанавливаем betText
равный bet
.
Теперь нам нужно добавить addListeners()
в наш код Setup()
. Добавьте следующий код внизу.
1
2
3
4
5
6
7
8
9
|
function Setup()
createDataFile()
setupCoins();
setupButtons();
setupTextFields();
setupGroups();
createDeck();
addListeners();
end
|
Если вы протестируете приложение сейчас, вы сможете поставить деньги.
23. Получение ручных ценностей
Нам нужен способ получить ценность руки игрока и руки дилера. Введите следующее ниже функции createDeck()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
|
function getHandValue(theHand)
local handValue = 0;
local hasAceInHand=false;
for i=1,#theHand do
local cardsValue = tonumber(string.sub(theHand[i],2,3));
if (cardsValue > 10) then
cardsValue = 10;
end
handValue = handValue + cardsValue;
if (cardsValue == 1)then
hasAceInHand = true;
end
end
if (hasAceInHand and handValue <= 11)then
handValue = handValue + 10;
end
return handValue;
end
|
Мы устанавливаем переменную hasAceInHand
переменную hasAceInHand
. Затем мы перебираем theHand
который будет либо playerHand
либо dealerHand
. Мы создаем переменную cardsValue
, cardsValue
ее к числу, получая подстроку текущей карты. Если cardsValue
больше 10, мы устанавливаем его cardsValue
10 . Гнезда, королевы и короли представлены 11 , 12 и 13 . Затем мы добавляем значение в handValue
. Если ценность карты равна 1, то мы знаем, что у них в руке туз. Если у них туз и их handValue
меньше или равно 11, мы добавляем к нему 10 .
24. Сделка ()
Теперь у нас есть все для сделки, поэтому теперь мы будем анимировать карты, чтобы сделать игру более интересной. Эта функция довольно большая, потому что именно там происходит вся логика игры. Мы разделим это на несколько шагов. Добавьте следующий код в функцию deal()
вы создали в первой части этой серии.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
money10.isVisible = false;
money25.isVisible = false;
money50.isVisible = false;
dealBtn.isVisible = false;
local randIndex = math.random(#deck)
local tempCard = display.newImage(«card_front.png»,630,55);
table.insert(allCards,tempCard);
local whichPosition;
local whichArray={};
local whichGroup;
if(dealTo == «player») then
whichArray = playerHand;
whichPosition = playerCardsY;
whichGroup = playerGroup;
else
whichArray = dealerHand;
whichPosition = dealerCardsY;
whichGroup = dealerGroup;
end
table.insert(whichArray,deck[randIndex]);
local xPos = 20+#whichArray*35
transition.to(tempCard, {time=1000,x=xPos,y=whichPosition,onComplete=function()
if(dealTo == «dealer» and #dealerHand == 1) then
firstDealerCard = deck[randIndex];
dealerGroup:insert(tempCard);
else
tempCard:removeSelf();
tempCard = display.newImage(deck[randIndex]..».png»,xPos-45,whichPosition-60);
whichGroup:insert(tempCard);
end
table.remove(deck,randIndex);
if(#dealerHand < 2)then
if(dealTo == «player»)then
dealTo = «dealer»
else
dealTo = «player»
end
deal();
end
end
});
|
Здесь мы устанавливаем наши деньги, чтобы быть невидимыми, а наша кнопка сделки видимой. Затем мы генерируем randIndex
из таблицы deck
. Затем мы генерируем новое изображение tempCard
и вставляем tempCard
в таблицу allImages
. Мы устанавливаем три локальные переменные: whichPosition
, whichArray
и whichGroup
. Мы проверяем, кому в настоящее время поручено инициализировать эти переменные соответствующим образом.
Затем мы вставляем deck[randIndex]
в whichArray
, которая является либо playerHand
либо таблицей dealerHand
. Помните, что наша колода состоит из строк, поэтому колода [randIndex] будет выглядеть как « h5 », « d10 ».
Мы устанавливаем локальную переменную xPos
равную 20+#whichArray*35
, которая устанавливает ее равной 20 плюс длина таблицы + 35 . Первый раз в таблице длина будет 1 , так что 20 + 1 * 35 . В следующий раз длина таблицы будет равна 2, поэтому будет 20 + 2 * 35 . Все это позволяет нам равномерно распределять наши карты по оси X.
Мы используем метод coronas transition.to
для перемещения tempCard
. Когда карта завершает свой переход, мы проверяем, имеем ли мы дело с дилером и имеет ли его длина руки 1 . Если это так, мы устанавливаем firstDealerCard
равным deck[randIndex]
и вставляем карту в группу dealerGroup
. Нам нужна ссылка на первую карту дилера, чтобы мы могли показать ее позже.
Если это была не первая карта дилера, то мы удаляем tempCard
, генерируем новое изображение с помощью deck[randIndex]
и вставляем ее в соответствующую группу (игрок или дилер). Причина, по которой мы вычитаем 45 и 60 соответственно, заключается в том, что Corona по умолчанию устанавливает опорную точку изображений в центр, и наши изображения имеют размер 90 x 120 . Следовательно, мы берем половину этого.
Наконец, мы удаляем карту в позиции randIndex
из deck
и проверяем, не dealerHand
ли dealerHand
2 . Если это так, мы меняем dealTo
на его противоположность (игрок или дилер), а затем снова dealTo
сделку.
Наконец, вы можете протестировать приложение, поставить немного денег и получить первые две карты.
25. Сделка () Продолжение …
Добавьте следующий код ниже того места, где мы вызывали deal()
на шаге выше.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
if(#dealerHand < 2)then
if(dealTo == «player»)then
dealTo = «dealer»
else
dealTo = «player»
end
deal();
elseif(#dealerHand == 2 and #playerHand == 2) then
if(getHandValue(playerHand)==21 or getHandValue(dealerHand) == 21)then
doGameOver(true);
else
standBtn.isVisible = true;
hitBtn.isVisible = true;
end
end
|
Здесь мы проверяем, равны ли как dealerHand
и playerHand
длиной 2 . Если они есть, мы проверим, равны ли их руки 21. Если все их руки равны 21, игра окончена. Мы называем doGameOver(true)
который присуждает выигрыши и начинает новую игру. true
параметр верен для блэкджека. Иначе это будет ложно.
26. DoGameOver ()
Функция doGameOver()
присуждает выигрыш и запускает новую игру. Мы также будем кодировать эту функцию в несколько шагов. Сейчас мы можем использовать его для проверки части блэкджека. Введите следующий код под функцией deal
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
function doGameOver(hasBlackJack)
local playerHandValue = getHandValue(playerHand);
local dealerHandValue = getHandValue(dealerHand);
local tempCardX = allCards[2].x;
local tempCardY= allCards[2].y;
allCards[2]:removeSelf();
local tempCard = display.newImage(firstDealerCard..».png»,tempCardX-45,tempCardY-60);
dealerGroup:insert(tempCard);
tempCard:toBack();
if(hasBlackJack)then
if(playerHandValue > dealerHandValue)then
money = money + bet*1.5;
instructionsText.text = «You Got BlackJack!»;
winner = «player»
else
money = money — bet;
instructionsText.text = «Dealer got BlackJack!»;
winner = «dealer»
end
end
end
|
Здесь мы получаем значение руки игрока и дилера. Мы получаем ссылку на allCards[2]
, x
и y
, которая является первой картой дилера, и затем удаляем ее с дисплея. Затем мы генерируем tempCard
с помощью переменной firstDealerCard
мы установили ранее. Еще раз вычитаем 45 и 60 . Затем мы вставляем эту новую карту в группу dealerGroup
. Когда мы делаем это, она находится на второй карточке, поэтому мы отправляем ее обратно, вызывая toBack()
.
Мы проверяем, имеет ли hasBlackJack
true, и если это так, то мы проверяем, больше ли рука игрока, чем рука дилера. Если это так, мы присуждаем немного денег, соответственно устанавливаем instructionsText
и меняем winner
на « игрок ».
27. Инициализация денег
Нам нужно помнить, чтобы инициализировать переменную money
прежде чем что-либо делать с ней. Добавьте следующее в функцию Setup()
.
1
2
3
4
5
6
|
function Setup()
createDataFile();
money = readMoney();
setupCoins();
…..
end
|
28. Тестирование на блэкджек
Мы находимся в точке, где мы можем проверить, есть ли у игрока или дилера блэкджек. Мы временно изменим код для тестирования, но вернем его обратно. Сначала в функции deal
измените следующее.
1
2
3
|
elseif(#dealerHand == 2 and #playerHand == 2) then
if(true)then
doGameOver(true);
|
Затем в функции doGameOver()
измените первые две строки следующим образом.
1
2
|
local playerHandValue = 21—getHandValue(playerHand);
local dealerHandValue = 18—;getHandValue(dealerHand);
|
Теперь попробуйте и протестируйте приложение. Вы должны увидеть, что игрок получает блэкджек.
Теперь измените первые две строки внутри doGameOver
на следующие
1
2
|
local playerHandValue = 18—getHandValue(playerHand);
local dealerHandValue = 21—;getHandValue(dealerHand);
|
Теперь, если вы проверите, вы должны увидеть, что у дилера есть блэкджек.
29. Сброс от тестирования
Теперь, когда мы проверили, мы должны установить наши переменные обратно. В функции deal
измените следующее.
1
2
3
|
elseif(#dealerHand == 2 and #playerHand == 2) then
if(getHandValue(playerHand)==21 or getHandValue(dealerHand) == 21)then
doGameOver(true);
|
Затем в функции doGameOver()
первые две строки в их предыдущее состояние.
1
2
|
local playerHandValue = getHandValue(playerHand);
local dealerHandValue = getHandValue(dealerHand);
|
Если вы проведете тест еще раз, и ни у вас, ни у дилера не появится блэкджек, кнопка раздачи должна стать невидимой, а кнопки удара и подставки должны стать видимыми.
30. Хит ()
Мы должны позволить игроку ударить или встать, как только сдаются первые две карты. Введите следующее в функцию hit()
введенную вами в предыдущей части этой серии.
1
2
3
4
5
6
|
function hit(event)
if(«began» == event.phase)then
dealTo = «player»;
deal();
end
end
|
Если вы проверите сейчас, вы сможете ударить.
После некоторого контроля качества вы, возможно, заметили, что игрок может быстро нажимать кнопку удара снова и снова, раздавая много карт одновременно. Это не то, как игра должна работать. Чтобы исправить это, нам нужно добавить условие, чтобы убедиться, что они могут попасть только в соответствующее время. Добавьте следующее в конец ваших объявлений переменных.
1
|
local canBet=true;
|
Теперь измените функцию hit()
на следующую.
1
2
3
4
5
6
7
8
9
|
function hit(event)
if(«began» == event.phase)then
if(canBet)then
dealTo = «player»;
deal();
canBet = false;
end
end
end
|
В функции deal()
добавьте следующую строку кода.
1
2
|
transition.to(tempCard, {time=1000,x=xPos,y=whichPosition,onComplete=function()
canBet = true;
|
Теперь игрок может нанести удар только один раз, карта была сдана.
31. Стенд ()
Далее нам нужно позволить игроку встать. Добавьте следующее в функцию stand()
введенную вами в предыдущей части этой серии.
01
02
03
04
05
06
07
08
09
10
11
|
function stand()
playerYields = true;
standBtn.isVisible = false;
hitBtn.isVisible = false;
if(getHandValue(dealerHand) < 17)then
dealTo = «dealer»
deal();
else
doGameOver(false);
end
end
|
Здесь мы указываем, что игрок «держит». Установите standBtn
и hitBtn
в невидимый. Мы проверяем, составляет ли рука дилера меньше 17 , и если это так, мы меняем dealTo
на дилера и dealTo
сделку. Если его рука не меньше 17 , то мы вызываем doGameOver()
. Дилер должен стоять на 17 или больше.
Если вы протестируете сейчас, игрок может получить желаемую руку, а затем нажать «Стенд». Однако есть пара проблем. Если игрок обанкротился, он может продолжить вытягивать карты, и раздача останавливается у дилера. Нам нужно, чтобы дилер продолжал вытягивать карты до тех пор, пока ему не исполнится 17 или более, или пока он не перестанет. Мы исправим эти проблемы, когда закончим нашу функцию deal()
в следующие два шага.
32. Сделка () продолжение …
Добавьте следующее в функцию deal()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
if(getHandValue(playerHand)==21 or getHandValue(dealerHand) == 21)then
doGameOver(true);
else
standBtn.isVisible = true;
hitBtn.isVisible = true;
end
end
if( #dealerHand >=3 and(getHandValue(dealerHand) < 17))then
deal();
elseif( playerYields and getHandValue(dealerHand)>=17)then
standBtn.isVisible = false;
hitBtn.isVisible = false;
doGameOver(false);
end
|
Здесь мы проверяем, является ли длина рук дилера больше или равна 3 и что рука дилера меньше 17 . Если его рука меньше 17, он должен взять карту. В противном случае мы проверяем, дал ли игрок сдачу и имеет ли рука дилера больше или равно 17 . Если так, игра окончена. Дилер может иметь 17 или больше с первыми двумя картами.
33. Завершение сделки ()
Введите следующий код в функции deal()
.
01
02
03
04
05
06
07
08
09
10
11
12
|
if( #dealerHand >=3 and(getHandValue(dealerHand) < 17))then
deal();
elseif( playerYields and getHandValue(dealerHand)>=17)then
standBtn.isVisible = false;
hitBtn.isVisible = false;
doGameOver(false);
end
if(getHandValue(playerHand)>21)then
standBtn.isVisible = false;
hitBtn.isVisible = false;
doGameOver(false);
end
|
Если игрок бьет и берет карту, которая ставит его старше 21 года , игра окончена.
34. GameOver () продолжение …
На этом шаге мы продолжим кодирование функции gameOver()
. На данный момент функция раздачи определяет, кто выигрывает, когда у игрока или дилера есть блэкджек. Нам нужно обработать все другие возможные результаты. Введите следующее в функции doGameOver()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
else
money = money — bet;
instructionsText.text = «Dealer got BlackJack!»;
winner = «dealer»
end
else
if (playerHandValue > 21)then
instructionsText.text = «You Busted!»;
money = money — bet;
winner = «dealer»;
elseif (dealerHandValue > 21)then
money = money + bet;
instructionsText.text =»Dealer Busts. You Win!»;
winner = «player»;
elseif (dealerHandValue > playerHandValue)then
money = money — bet;
instructionsText.text =»You Lose!»;
winner = «dealer»
elseif (dealerHandValue == playerHandValue)then
money = money — bet;
instructionsText.text = «Tie — Dealer Wins!»;
winner = «tie»
elseif (dealerHandValue < playerHandValue)then
money = money +bet;
instructionsText.text=»You Win!»;
winner = «player»
end
end
|
Если вы сейчас протестируете код, вы сможете играть в полную игру. Текст инструкции покажет результат. Пройдите несколько раундов и убедитесь, что все выглядит правильно. Если вы действительно хотите тщательно протестировать игру, введя разные значения рук, вы можете использовать ту же технику, которую мы использовали ранее в этом уроке, для проверки блэкджека.
35. GameOver () продолжение …
Введите следующее в нижней части функции doGameOver()
01
02
03
04
05
06
07
08
09
10
|
elseif (dealerHandValue < playerHandValue)then
money = money +bet;
instructionsText.text=»You Win!»;
winner = «player»
end
end
if(money < 10)then
money = 500
end
saveMoney(money)
|
После каждого раунда мы должны экономить деньги игрока. Если их деньги меньше 10, мы считаем их банкротами и обнуляем их до 500 . В качестве упражнения, посмотрите, можете ли вы получить предупреждение, говорящее что-то вроде: « Вы обанкротились, дилер присуждает вам $ 500,00 ».
36. Завершение GameOver ()
После каждого раунда мы перемещаем монеты к победителю, а затем начинаем новую игру. Введите следующее под кодом, который вы ввели на шаге выше.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
saveMoney(money)
local tweenTo;
if(winner == «player»)then
tweenTo = playerCardsY;
else
tweenTo = dealerCardsY
end
transition.to(coinContainer, {time=1000,y=tweenTo,onComplete=function()
for i=coinContainer.numChildren,1,-1 do
local child = coinContainer[i]
child:removeSelf()
child = nil;
end
timer.performWithDelay( 2000, newGame);
coinContainer.y = 600;
end
});
|
Здесь мы видим, кто выиграл раунд, а затем мы оживляем монеты для них. Когда анимация завершится, мы удаляем все монеты из coinContainer
и устанавливаем их coinContainer
nil, так как мы закончили с ними. Наконец, мы вызываем newGame()
через две секунды, мы также сбрасываем нашу позицию coinContainer
.
37. NewGame ()
Введите следующее под doGameOver()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
function newGame()
instructionsText.text = «PLACE YOUR BET»;
betText.text = «»;
money10.isVisible = true;
money25.isVisible = true;
money50.isVisible = true;
bankText.text = «Your Bank: $»..readMoney()
for i=dealerGroup.numChildren,1,-1 do
local child = dealerGroup[i]
child:removeSelf()
child = nil;
end
for i=playerGroup.numChildren,1,-1 do
local child = playerGroup[i]
child:removeSelf()
child = nil;
end
dealTo = «player»;
playerHand = {};
dealerHand = {};
allCards = {};
createDeck();
firstDealerCard=»»;
playerYields = false;
winner = «»;
bet = 0;
canBet = true;
end
|
Здесь мы устанавливаем видимые деньги, удаляем карты из групп игроков и дилеров и сбрасываем все наши переменные.
Вывод
Мы написали забавную и интересную игру в блэкджек, используя Corona SDK. Спасибо за чтение, надеюсь, вы нашли этот урок полезным!