Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. iOS SDK
Code

Membuat Game Blackjack dengan Swift 3 dan SpriteKit

by
Difficulty:IntermediateLength:LongLanguages:

Indonesian (Bahasa Indonesia) translation by Aditia Dwiperdana (you can also view the original English article)

Final product image
What You'll Be Creating

Pada tutorial ini kamu akan membuat sebuah game blackjack dalam SpriteKit menggunakan Swift 3. Kamu akan belajar tentang mengimplementasi fitur sentuh, membuat animasi visual, dan banyak konsep lain yang akan berguna saat membuat game dengan SpriteKit.

1. Membuat project dan mengimpor resource

Buka XCode dan pilih Create a new Xcode project atau pilih New > Project... dari menu File. Pastikan iOS terpilih dan pilih template Game.

new_project

Lalu, tentukan nama yang kamu inginkan untuk Product Name, Organization Name, dan Organization Identifier. Pastikan Language diset menjadi Swift, Game Technology diset sebagai SpriteKit, dan Devices diset dengan iPad.

project_options

Tentukan lokasi untuk menyimpan file project dan klik Create.

Mengimpor Helper Class

Download Github repo untuk project ini. Di dalamnya kamu akan temukan folder classes. Buka folder ini dan geser semua file ke folder yang sesuai dengan nama project-mu, misalnya blackjack. Pastikan Copy items if needed dan target utama dari daftar target keduanya dicentang.

File options with Copy items if needed box checked

Mengimpor gambar-gambar

Dalam repo GitHub tutorial ini juga ada folder bernama tutorial images. Di dalam project navigator, buka Assets.xcassets dan geser semua gambar ke siderbar. Xcode akan membuat atlas tekstur dari gambar-gambar tersebut secara otomatis.

Tutorial images folder in GitHub

2. Pengaturan project

Dalam project navigator ada dua file yang bisa kamu hapus (Gamescene.sks dan Actions.sks). Hapus kedua file tersebut dan pilih Move To Trash. File-file ini digunakan oleh editor scene bawaan Xcode, yang bisa digunakan untuk menyusun project secara visual. Kita akan membuat semua melalui kode, jadi file-file tersebut tidak dibutuhkan.

Buka GameViewController.swift, hapus isinya, dan ganti dengan kode berikut ini:

Kelas GameViewController diturunkan dari UIViewController dan akan memiliki SKView sebagai view. Di dalam fungsi viewDidLoad, kita melakukan downcast properti view ke instance SKView, menggunakan operator type cast as!, dan mengatur view tersebut.

Jika kamu menjalankan project ini saat pertama kali kamu buat dari awal, kamu mungkin melihat teks di kanan bawah layar. Itu adalah kegunaan properti showsFPS dan showsNodeCount, menampilkan jumlah frame per detik dalam game dan jumlah SKNodes yang terlihat di dalam scene. Kita tidak perlu informasi ini, jadi ubah nilainya menjadi false.

Properti ignoreSiblingOrder digunakan untuk menentukan urutan gambar dari SKNode di dalam game. Kita mengisi properti ini false karena kita perlu SKNodes untuk digambarkan sesuai dengan urutan saat ditambahkan ke scene.

Terakhir, kita atur scale mode menjadi .aspectFill, yang akan membuat konten di dalam scene untuk mengisi seluruh layar. Lalu kita perlu memanggil fungsi presentScene(_:) pada skView yang berfungsi menampilkan scene.

Berikutnya, hapus semua yang ada di dalam GameScene.swift dan ganti dengan kode berikut.

Kamu sekarang bisa menjalankan project ini, akan muncul layar hitam kosong. Di langkah berikutnya kita akan tambahkan konten ke scene.

3. Variabel dan Konstanta

Masukkan kode berikut di awal kelas GameScene, tepat di bawah baris GameScene mewariskan kelas SKScene.

Kita membuat beberapa SKSpriteNode di sini. SKSpriteNode digunakan untuk membuat node yang berwarna, atau biasanya menggunakan sebuah SKTexture, yang biasanya berisi sebuah gambar. Kita menggunakan convenience initializer init(color:size:) untuk membuat sebuah node berwarna transparan bernama moneyContainer. moneyContainer akan digunakan untuk menyimpan nilai uang yang ditaruhkan pemain, dan di akhir masing-masing ronde, kita akan animasikan node ini untuk bergerak menuju pemain yang memenangkan game. Menempatkan semua uang di satu node memudahkan kita untuk menganimasikan semua uang di waktu yang bersamaan.

Berikutnya, kita buat konstanta dealBtn, hitBtn, dan standBtn. Sesuai dengan namanya, tombol-tombol ini digunakan dalam game untuk aksi deal, hit, dan stand. Kita menggunakan convenience initializer init(imageNamed:), yang menerima nama gambar tanpa ekstensi file sebagai parameter.

Laku kita buat tiga konstanta money10, money25, dan money50, yang merupakan jenis Money. Money adalah kelas khusus turunan dari SKSpriteNode dan akan membuat salah satu jenis uang tergantung dari tipe moneyValue yang dilempar sebagai parameter. Parameter moneyValue adalah tipe dari MoneyValue, yang berupa enum. Lihatlah kelas Money di GitHub repo project ini untuk melihat bagaimana semua ini berkerja.

Terakhir kita buat sebuah SKLabelNode menggunakan convenience initializer init(text:) yang menerima parameter teks yang ingin ditampilkan pada label.

Mengimplementasi setupTable

Tambahkan kode barikut di bawah fungsi didMove(to:).

Di sini kita menginisialisasi konstanta table dan menambahkannya ke scene menggunakan addChild(_:) yang menerima parameter node yang akan ditambahkan ke scene. Kita atur nilai position dari table di dalam scene dan mengubah nilai zPosition menjadi -1. Properti zPosition mengatur urutan node digambar. Benda dengan nilai terkecil akan digambar pertama, dan benda lain akan digambarkan berurutan sesuai nilainya. Karena kita perlu table ada di bawah semua benda lain, kita atur nilai zPosition ke -1. Hal ini memastikan benda itu digambar sebelum node apapun.

Kita juga perlu tambahkan moneyContainer dan instructionText ke scene. Kita atur nilai fontColor dari instructionText menjadi hitam (awalnya putih).

Update didMove(to:) menjadi berikut ini.

Fungsi didMove(to:) dipanggil tepat setelah scene ditampilkan oleh view. Umumnya, disinilah kamu melakukan pengaturan scene dan membuat asset-asset yang dibutuhkan. Jika kamu coba mainkan sekarang, kamu bisa melihat table dan instructionText sudah ditambahkan ke scene. moneyContainer juga ada di sana tapi tidak bisa kamu lihat karena dibuat transparan.

5. Mengimplementasi setupMoney

Tambahkan kode berikut di bawah fungsi setupTable.

Kita menambahkan instance dari uang dan mengatur posisinya. Panggil fungsi ini di dalam didMove(to:).

6. Mengimplementasi setupButtons

Tambahkan kdoe berikut di bawah fungsi setupMoney yang sudah dibuat di langkah sebelumnya.

Seperti yang kita lakukan dengan objek uang di langkah sebelumnya, kita menambahkan tombol dan mengatur posisinya. Di sini kita menggunakan properti name agar bisa membedakan setiap tombol melalui kode. Kita juga mengatur hitBtn dan standBtn menjadi tersembunyi atau tidak terlihat, dengan mengatur properti isHidden menjadi true.

Sekarang panggil fungsi ini di dalam didMove(to:).

Jika kamu coba jalankan game ini, kamu akan melihat objek uang dan tombol sudah ditambahkan ke dalam scene.

7. Mengimplementasi touchesBegan

Kita perlu mengimplementasi fungsi touchesBegan(_:with:) untuk mengetahui saat sebuah objek dalam scene disentuh. Fungsi ini dipanggil saat satu atau lebih jari menyentuh layar. Tambahkan kode berikut di dalam touchesBegan.

Properti multiTouchEnabled dari view scene kita awalnya di set sebagai false, artinya vire hanya bisa menerima sentuhan pertama dari rangkaian sentuhan. Dengan properti ini dinonaktifkan, kita bisa mendapat sentuhan dengan menggunakan properti first dari set touch karena hanya ada satu objek di set tersebut.

Kita bisa mendapat touchLocation dalam scene dengan menggunakan properti location dari sentuhan. Lalu kita bisa menentukan node mana yang disentuh dengan memanggil atPoint(_:) dan melempar touchLocation sebagai parameter. 

Kita periksa jika nama properti touchNode adalah "money", dan jika iya maka kita tahu pemain menyentuh salah satu dari tiga objek uang. Kita menginisialisasi konstanta money dengan men-downcast touchedNode ke Money, lalu kita panggil fungsi bet yang memanggil fungsi getValue() di konstanta money.

8. Mengimplementasi bet

Masukkan kode berikut di bawah fungsi setupButtons yang kamu buat di langkah sebelumnya.

Pertama kita pastikan pemain tidak mencoba untuk menaruhkan uang lebih banyak dari yang mereka punya, dan jika mereka melakukannya, kita langsung keluar dari fungsi. Jika tidak, kita tambahkan betAmount ke pot, buat konstanta tempMoney, atur anchorPoint ke (0,0), dan tambahkan ke moneyContainer. Lalu kita bisa atur position dan sembunyikan dealBtn dengan mengatur properti isHidden ke false.

SKSpriteNode memiliki properti anchorPoint yang awalnya bernilai (0.5,0.5). Sistem koordinat SpriteKit menyimpan (0,0) di kiri bawah dan (1,1) di kanan atas. Kamu bisa mengubah properti ini jika kamu mau memutar SKSpriteNode dan ingin pusat rotasinya di titik yang berbeda. Contohnya, jika kamu mengubah properti anchorPoint ke (0,0) maka SKSpriteNode akan berputar di pojok kiri bawah. Kamu akan mengubah properti ini untuk membantu mengatur posisi objek, seperti kode di bawah ini.

Kita perlu membuat instance dari kelas Pot dan Player agar kode ini bekerja. Tambahkan kode berikut bersama dengan konstanta dan variabel lain.

Jika kamu menjalankan game ini sekarang kamu sudah bisa menyentuh objek uang manapun dan menambahkannya ke moneyContainer.

9. Mengimplementasi deal

Tambahkan kode berikut bersama kontanta dan variabel lain.

Array allCards akan digunakan untuk menyimpan semua kartu dalam game. Ini akan memudahkan kita memproses mereka dan menghilangkan mereka dari scene sekaligus. Konstanta dealerCardsY dan playerCardsY adalah posisi kartu di sumbu y. Ini akan membantu kita saat menempatkan kartu baru. currentPlayerType digunakan untuk menunjukkan siapa yang akan mengambil kartu berikutnya. Nilainya antara dealer atau player1.

Tambahkan kode berikut di dalam didMove(to:).

Pada kode sebelumnya, kita menginisialisasi currentPlayerType ke instance dari kelas Player tanpa nama. Di sini kita memberinya nama player1.

Kita perlu membuat satu deck kartu baru sebelum kita implementasi fungsi deal. Masukkan kode berikut dalam setupTable.

Sekarang kita bisa mengimplementasi fungsi deal. Tambahkan kode berikut di bawah fungsi bet.

Fungsi ini cukup besar, tapi hal itu diperlukan untuk mengimplementasi logika membagi kartu. Kita periksa langkah per langkah. Kita menginisialisasi konstanta tempCard sebagai instance dari Card, atur posisinya, dan menambahkannya ke scene. Kita ingin kartu ini digambar dengan zPosition lebih besar dari 0, karena kartu pertama dealer perlu ada pada 0. Kita isi dengan suatu nilai, misalnya 100. Kita juga perlu membuat konstanta newCard dengan memanggil fungsi getTopCard() pada deck.

Berikutnya, kita membuat dua variabel, whichPosition dan whichHand, lalu menjalankan beberapa logika untuk menentukan nilai akhirnya. Lalu tambahkan newCard ke tangan yang sesuai (antara tangan pemain atau dealer). Konstanta xPos menentukan posisi akhir kartu saat selesai beranimasi.

Kelas SKAction memiliki beberapa fungsi yang bisa dipanggil untuk mengubah properti node seperti posisi, skala, dan rotasinya. Di sini kita panggil fungsi move(to:duration:), yang akan menggerakkan node dari satu posisi ke posisi lain. Tapi, untuk menjalankan SKAction, kamu perlu memanggil fungsi run(_:) dari node dan melempar SKAction sebagai parameter. Di sini, kita memanggil fungsi run(_:completion:), yang menyebabkan kode pada bagian closure dijalankan setelah aksi selesai dijalankan.

Setelah aksi tersebut dijalankan, kita akan membolehkan pemain untuk bertaruh dengan memanggil fungsi setCanBet(canBet:) pada instance player1. Lalu kita perlu periksa apakah currentPlayerType adalah instance dari Dealer, dan periksa bahwa dealer hanya punya satu kartu dengan memanggil hand.getLength(). Jika benar, kita atur kartu pertama dealer, yang akan kita butuhkan di akhir game.

Karena kartu pertama dealer akan selalu tertutup sampai akhir permainan, kita perlu referensi ke kartu tersebut agar di akhir kita bisa menampilkannya. Tambahkan kartu ini ke array allCards agar nanti kita bisa menghapusnya, lalu atur propert zPosition menjadi 0 karena kita perlu kartu ini di bawah semua kartu lain. (Ingat kartu lain memiliki z-position 100).

Jika currentPlayerType bukan instance dari Dealer, dan jumlah kartu di tangan bukan 1, kita hilangkan tempCard dan simpan newCard di posisi yang sama, pastikan zPosition bernilai 100.

Menurut aturan blackjack, dealer dan pemain mendapat dua kartu untuk memulai game. Di sini kita memeriksa apa tipe currentPlayerType dan mengubahnya jadi lawannya. Karena dealer memiliki kartu kurang dari dua, kita panggil fungsi deal lagi. Jika tidak, kita periksa apakah dealer dan player1 memiliki dua kartu, jika iya, kita periksa lagi apakah kartu memiliki nilai total 21, yaitu kondisi untuk menang. Jika salah satu tangan mendapat 21 maka game akan berakhir karena salah satu sudah mendapatkan blackjack. Jika tidak ada yang mendapat 21, maka kita menampilkan standBtn dan hitBtn dan game akan dilanjutkan.

Aturan blackjack menyebutkan bahwa dealer harus memilih stand jika mendapat 17 atau lebih. Beberapa baris kode berikut memeriksa apakah nilai tangan dealer lebih kecil dari 17 dan memanggil fungsi deal. Jika nilainya 17 atau lebih, maka game akan berakhir. Terakhir, jika nilai tangan player1 lebih dari 21 maka game akan berakhir karena mereka kalah.

Banyak sekali logika yang harus dipahami. Jika ada yang tidak jelas, baca kembali perlahan sampai kamu mengerti.

Berikutnya, kita perlu mengimplementasi fungsi gameover.

Kita perlu tahu saat pemain menekan tombol deal. Tambahkan kode berikut pada fungsi touchesBegan(_:with:).

10. Mengimplementasi doGameOver

Berikutnya, tambahkan kode berikut di bawah fungsi deal yang sudah dibuat di langkah sebelumnya.

Kita ambil posisi x dan y dari kartu pertama di array allCards, yang merupakan kartu pertama dealer. Lalu kita buat konstanta tempCard dengan memanggil getFirstCard pada dealer. Ingatkah saat kita mengatur Card di fungsi deal sebelumnya? Di sini kita menambahkannya ke scene, mengatur posisinya menggunakan konstanta tempCardX dan tempCardY, dan mengatur zPosition menjadi 0 agar ada di bawah semua kartu lain.

Kita perlu tahu siapa yang memenangkan game, jadi kita menginisialisasi variabel winner dan mengisi nilainya menjadi player1, walau hal ini akan berubah jika dealer menjadi pemenang game ini.

Lalu kita menjalankan beberapa logika untuk menentukan siapa yang mememangkan game. Jika parameter hasBlackjack bernilai true maka kita bisa tahu siapa yang m enang dan keluar dari fungsi tersebut. Jika tidak, kita melanjutkan logika yang ada untuk menentukan siapa yang memenangkan game. Saya tidak akan membahas tiap langkah logika ini karena akan cukup mudah dimengerti. Tidak peduli siapa yang menang, kita panggil fungsi moveMoneyContainer(position:), yang menerima parameter berisi  posisi container tersebut perlu digeser. Ini akan berisi nilai posisi y kartu dealer atau player1.

11. Mengimplementasi moveMoneyContainer

Tambahkan kode berikut di bawah fungsi doGameOver.

Fungsi moveMoneyContainer(position:) menggerakkan moneyContainer ke pihak yang memenangkan game, antara pemain atau dealer. Saat SKAction selesai, kita panggil resetMoneyContainer.

12. Mengimplementasi resetMoneyContainer

Fungsi resetMoneyContainer menghapus semua uang dengan memanggil fungsi removeAllChildren(), mengembalikan moneyContainer ke posisi aslinya, dan memanggil newGame.

13. Mengimplementasi newGame

Tambahkan kode berikut di bawah fungsi resetMoneyContainer yang sudah dibuat di langkah sebelumnya.

Di sini kita mengembalikan nilai semua variabel yang dibutuhkan dan menghapus semua kartu dari scene dengan memproses array allCards dan memanggil removeFromParent() pada setiap elemen.

14. Mengimplementasi htiBtn dan standBtn

Yang tersisa untuk menyelesaikan game kita adalah mengimplementasi fitur sentuh pada hitBtn dan standBtn. Masukkan kode berikut di dalam fungsi touchesBegan(_:with:).

Sekarang kita implementasi fungsi yang dipanggil di event handler. Tambahkan dua fungsi di bawah ini di bawah fungsi newGame.

Di dalam fungsi hit, kita pastikan pemain bisa bertaruh, dan jika pemain melakukannya, kita mengubah currentPlayerType menjadi player1, lalu memanggil fungsi deal dan mencegah pemain bertaruh lagi.

Di dalam fungsi stand kita panggil setYielding pada player1, dengan parameter true. Lalu kita periksa apakah dealer punya nilai lebih kecil dari 17, dan jika iya kita panggil deal, tapi jika tangan dealer bernilai 17 atau lebih maka game akan berakhir.

Sekarang kamu bisa menjalankan game yang sudah selesai.

Kesimpulan

Ini adalah tutorial yang cukup panjang dengan banyak logika pada fungsi deal. Kita tidak mengimplementasi penggunakan Pot dan penambahan atau pengurangan uang yang dimiliki pemain. Kenapa kamu tidak coba melengkapinya sebagai latihan untuk menyelesaikan game ini?

Sekarang kamu punya game blackjack yang bisa kamu banggakan. Terima kasih sudah membaca, dan saya harap tutorial ini bisa berguna. Selagi kamu di sini, lihatkan beberapa course lain dan tutorial tentang membuat aplikasi dengan Swift dan SpriteKit!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.