見出し画像

SwiftUIでいこう!- スタンフォード大学Lecture 4: Game Logic 2

初めに作っていたContentViewのコードをViewModelで置き換えてカードを表示できるようになりました。

神経衰弱ゲームなので、タップしてカードを裏返し、正解の判定などゲームとして遊べる部分の実装をしていきます。

構造体CardView()で以下カードの状態を決めています。

card.isFaceUp

の真偽で表、裏を表示させるようにしています。

  if card.isFaceUp{
               shape
                   .fill()
                   .foregroundColor(.white)
               
               shape
                   .stroke(lineWidth: 3)
               Text(card.content)
                   .font(.largeTitle)
           }else{
               shape
                   .fill()
           }


今ViewModelで組み替えていき該当部分

構造体Game<CardContent>の以下で

 mutating func choose(_ card:Card){
       let chooseIndex = index(of:card)
       cards[chooseIndex].isFaceUp.toggle()
       print("chosenCard = \(cards)")
   }
isFaceUp.toggle()

の部分で確かにコードが書かれているので実行されたら表示も変わっても良いのですが変わりません。

これについては監視状態を作らないといけません。

ObservableObject

の出番です。

class EmojiGame:ObservableObject{}

として、"model"についても

@Published private(set) var model:Game<String> = createMemoryGame()

とします。これで監視状態、modelがに変化があれば

 func choose(_  card:Game<String>.Card){
       model.choose(card)
   }

にも通知され更新されます。この更新により CardView()、ContentView()の順番に伝わり、表示が更新されるということです。

firstindexから

var arr = [6,8,0]
var result = arr.firstIndex(where:{$0 == 8})
result

とすると"1"と結果が出ます。"8"は配列arrの中でインデックスの"1"番目だということです。

カードを押してそのカードの真偽を反転させるコードを整理します。

mutating func choose()のコードを以下コメントアウトした部分の代わりに、firstindex関数を使ったものへと変更しています。。

    mutating func choose(_ card:Card){
//        let chooseIndex = index(of:card)
//        cards[chooseIndex].isFaceUp.toggle()
       if let chooseIndex = cards.firstIndex(where: {$0.id == card.id}){
           
           cards[chooseIndex].isFaceUp.toggle()
       }
       
       print("chosenCard = \(cards)")
   }
   
   
//    func index(of card:Card)->Int{
//        for index in 0..<cards.count{
//            if cards[index].id == card.id{
//                return index
//            }
//        }
//
//        return 0
//    }

最終的には関数index()を削除して関数 choose()のみで実装しています。

これで実行するとカードは反転しますが押すカード全て反転してしまい、同じカードかどうかの判定もできていません。ゲームとしての機能を実装していきます。

まず1枚目のカードを選んだ時のカードのインデックスを覚えさせる変数を定義します。

 private var indexOfTheOneAndOnlyFaceUpCard:Int?

そしてカードが

isFaceUp
isMatched

がfalseの時にchooseIndexにインデックスの数字が入っていくように条件を付け加えています。

   if let chooseIndex = cards.firstIndex(where: {$0.id == card.id}),
          !cards[chooseIndex].isFaceUp,
          !cards[chooseIndex].isMatched{

選んだカードが同じであった時の処理

 if let potentialMachiIndex = indexOfTheOneAndOnlyFaceUpCard{
               if cards[chooseIndex].content == cards[potentialMachiIndex].content{
                   cards[chooseIndex].isMatched = true
                   cards[potentialMachiIndex].isMatched = true
               }
               indexOfTheOneAndOnlyFaceUpCard = nil
  }


1枚目に選んだ時と2枚目に選んだカードが1枚目と違った時には

else{
           for index in cards.indices {
               cards[index].isFaceUp = false
           }
               indexOfTheOneAndOnlyFaceUpCard = chooseIndex
 }

ここで選んだカードのインデックスを"indexOfTheOneAndOnlyFaceUpCard"に代入しています。

cards.indicesで配列にそれぞれの添字にアクセスします。


もし同じカードであった場合はそのカードを消していきます。

struct CardView:View {}の

   var body: some View{
       ZStack{
           let shape =  RoundedRectangle(cornerRadius: 20.0)
           if card.isFaceUp{
            ・・・・・
           }else if card.isMatched{
               shape.opacity(0)
           }
           else{
               shape
                   .fill()
           }
       }
   }
else if card.isMatched{
   shape.opacity(0)
}

.opacity(0)にすることで見えなくしています。

まとめ。

    mutating func choose(_ card:Card){

       if let chooseIndex = cards.firstIndex(where: {$0.id == card.id}),
          !cards[chooseIndex].isFaceUp,
          !cards[chooseIndex].isMatched{
           if let potentialMachiIndex = indexOfTheOneAndOnlyFaceUpCard{
               if cards[chooseIndex].content == cards[potentialMachiIndex].content{
                   cards[chooseIndex].isMatched = true
                   cards[potentialMachiIndex].isMatched = true
               }
               indexOfTheOneAndOnlyFaceUpCard = nil
           }else{
               for index in cards.indices {
                   cards[index].isFaceUp = false
               }
               indexOfTheOneAndOnlyFaceUpCard = chooseIndex
           }
           
           
           cards[chooseIndex].isFaceUp.toggle()
       }
      
   }

この記事が気に入ったらサポートをしてみませんか?