はじめに
SwiftUIの勉強のためにじゃんけんアプリを作成しました。
SwiftUIについては、1年以上前に少し触った程度で書き方もあまり詳しくないため、勉強がてらじゃんけんアプリを作成してみました。
もし、手探りで制作したため、誤用などがあればご指摘いただけると幸いです。
ゴール
以下のようなじゃんけんアプリの作成をゴールとします。
プレイヤーがグー、チョキ、パーいずれかの手のボタンをタップすると、CPU😎の手もグー、チョキ、パーのいずれかでランダム生成され、プレイヤーとCPUの手の組み合わせに応じて結果が表示されます。
じゃんけんアプリの作成
列挙型Handの定義
まず、じゃんけんで使用するグー、チョキ、パーの手を定義した列挙型Handを定義します。
Handにはextensionを用いてtextプロパティとemojiプロパティも定義します。
例えば、Hand.rock.text
はグー
として扱われます。
import Foundation
enum Hand {
case rock
case scissors
case paper
}
extension Hand {
var text: String {
switch self {
case .rock:
return "グー"
case .scissors:
return "チョキ"
case .paper:
return "パー"
}
}
var emoji: String {
switch self {
case .rock:
return "✊"
case .scissors:
return "✌️"
case .paper:
return "✋"
}
}
}
列挙型Resultの定義
次に、引き分け、勝ち、負けの結果を表す列挙型Resultを定義します。
Resultにはextensionを用いてtextプロパティも定義します。
例えば、Result.draw.text
は引き分け
として扱われます。
import Foundation
enum Result {
case draw
case win
case lose
}
extension Result {
var text: String {
switch self {
case .draw:
return "引き分け"
case .win:
return "勝ち"
case .lose:
return "負け"
}
}
}
Utilクラスの定義
ロジック(状態管理を行わない部分)を定義したUtilクラスを定義します。
CPUの手をランダムで生成するgenerateCPUHand関数とじゃんけんの勝敗を判定するjudgeResult関数を定義します。
import Foundation
class Util {
static func generateCPUHand() -> Hand {
let hands = [Hand.rock, Hand.scissors, Hand.paper]
let hand = hands.randomElement()
return hand!
}
static func judgeResult(playerHand: Hand, cpuHand: Hand) -> Result {
let isDraw = playerHand == cpuHand
let isWin = (playerHand == .rock && playerHand == .scissors) || (playerHand == .scissors && cpuHand == .paper) || (playerHand == .paper && cpuHand == .rock)
if isDraw {
return .draw
} else if isWin {
return .win
} else {
return .lose
}
}
}
Stateクラスの定義
続いて、状態管理を行うために、ObservableObjectを用いてStateクラスを定義します。
@Published
で状態管理をする変数を定義します。
ボタンをタップした際に状態管理を行う関数onTapHandも定義します。
import Foundation
final class State: ObservableObject {
@Published var message = "じゃんけん…"
@Published var result = Result.draw
@Published var cpuHand = Hand.rock
func onTapHand(hand: Hand) -> Void {
let playerHand = hand
cpuHand = Util.generateCPUHand()
result = Util.judgeResult(playerHand: playerHand, cpuHand: cpuHand)
message = result.text
}
}
構造体HandButtonの定義
グー、チョキ、パーのボタンのUIコンポーネントを定義したクラスを定義します。
引数として() -> Void
型のonTapとHand
型のhandを定義します。
import SwiftUI
struct HandButton: View {
let onTap: () -> Void
let hand: Hand
var body: some View {
Button(action: {
onTap()
}, label: {
VStack {
Text(hand.emoji).font(.title)
Text(hand.text).font(.title)
}
})
}
}
struct HandButton_Previews: PreviewProvider {
static var previews: some View {
HandButton(onTap: {
print("Rock button tapped")
} ,hand: .rock)
}
}
ContentViewの編集
最後に、ContentViewを編集し、じゃんけんアプリのUIを表示します。
@ObservedObject
で状態を監視し、UIに反映させます。
ここまでできたらじゃんけんアプリの完成です!
import SwiftUI
struct ContentView: View {
@ObservedObject private var state = State()
var body: some View {
VStack {
Spacer()
Text(state.message).font(.title)
Text("😎" + state.cpuHand.emoji)
Spacer()
HStack {
Spacer()
HandButton(onTap: {
state.onTapHand(hand: .rock)
}, hand: .rock)
Spacer()
HandButton(onTap: {
state.onTapHand(hand: .scissors)
}, hand: .scissors)
Spacer()
HandButton(onTap: {
state.onTapHand(hand: .paper)
}, hand: .paper)
Spacer()
}
.padding()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
最後に
enumで列挙型を定義し、ObservableObjectで状態管理を行い、SwiftUIでUIを構築することにより、じゃんけんアプリを作ってみました。
じゃんけんアプリの制作により、SwiftUIの書き方が少しだけわかるようになりました。