サイトアイコン BergamotMagic

おそるおそるSwift 4-6 ハイローゲームを作る ~ハイスコアを表示する~

Swift5+Xcode11.7

今回のゴール

 前回作成したハイスコアを表示させるためのサブビューを作ります。

今回のゴールのプレビュー

ハイスコアを表示する画面を作成する

 練習も兼ねてハイスコアを表示するサブビューを作成し、画面を切り替える仕様にしました。最初に、サブビュー(ScoreBoardとしました)のファイルを作成します。

配列をビューに表示させるときのAny型問題

 サブビュー(ScoreBoard)に以下のようなコードを記述したところ、その配列はAny型のはずでString型とは限らないんじゃないの?という意味のエラーが表示されました。コードを入力するたびにSwiftから何か怒られるのではとビクビクしてしまいます。

import SwiftUI

struct ScoreBoard: View {
        @ObservedObject var processor = Processor()
    var body: some View {
        List(0 ..< processor.highScore.count) { item in
            HStack  {
                Text(String(item + 1))
                Spacer()
                Text(self.processor.highScore[item][0])
                Spacer()
                Text(self.processor.highScore[item][1])
                Spacer()
                Text(self.processor.highScore[item][2])
            }
        }
    }
}

struct ScoreBoard_Previews: PreviewProvider {
    static var previews: some View {
        ScoreBoard()
    }
}

配列に格納するときに型を指定する

 他にも方法はあるのでしょうが、今回は配列に値を格納するときにString型と明示することにしました。processorx.swiftの一部(下の図の39行目)を変更しました。

import Foundation

class Processor : ObservableObject {
    @Published var history :[Int] = [5] //history:抽選数字履歴保持用配列
    @Published var result: String = ""
    @Published var reward: Int = 1
    var randNum: Int = 0     //randNum:乱数
    let dateformatter = DateFormatter()
    var recordDate = ""
    var highScore:[[String]] {
        get {
            return UserDefaults.standard.array(forKey: "highScore") as? [[String]] ?? []
        }
        set {
            UserDefaults.standard.set(newValue, forKey: "highScore")
        }
    }

    
//    func judge(choice:String) -> String {
    func judge(choice:String) {
        randNum = Int.random(in:1...9)
        history.append(self.randNum)
        for (index, his) in history.enumerated() {
            print("history[\(index)]: \(his)")
        }
        print("endIndex:\(history.endIndex)")
        let prevNum:Int = history[history.endIndex - 2] //prevNum:1つ前の抽選数字
        print ("prevNum:\(prevNum)")
        let nowNum:Int = history[history.endIndex - 1]  //nowNum:今回の抽選数字
        print ("NowNum:\(nowNum)")
        if (nowNum == prevNum) || ((nowNum >= prevNum)&&(choice == "high")) || ((nowNum <= prevNum)&&( choice == "low")) {
            result = "Win"
            reward *= 2
        } else {
            result = "Lose! You Lost All Money!!"
            dateformatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMddHHmmss", options: 0, locale: Locale(identifier: "ja_JP"))
            recordDate = dateformatter.string(from: Date())
            highScore.append([recordDate,String(reward),String(history.endIndex - 1)])
            print (highScore)
            reward = 1
            history = [5]
        }
    }
    
    func num(times:Int) -> String {
        if history.endIndex >= times {
            return String(history[history.endIndex - times])
        } else {
            return "-"
        }
    }
    
    func reset() {
        UserDefaults.standard.removeObject(forKey: "highScore")
    }
    
}
配列を書き出した結果

サブビューへのリンクを貼る

 ビューの切り替えはさほど面倒ではなく、ビュー全体をNavigationViewと宣言して、NavigationLinkで行先のリンクを貼るだけです。NavigationViewの記述場所を誤ると、Viewの中にViewを作ってしまうのか、レイアウトが変になります。下の図のようにContentView.swiftを書き換えました。「ハイスコアへ」というのも味気がないので「高額当選記録へ」としました。

import SwiftUI

struct ContentView: View {
    @ObservedObject var processor = Processor()
    
    var body: some View {
        NavigationView {
            VStack {
                Text("High&Low Game!")
                    .font(/*@START_MENU_TOKEN@*/.largeTitle/*@END_MENU_TOKEN@*/)
                    .fontWeight(.heavy)
                    .foregroundColor(Color.white)
                    .background(/*@START_MENU_TOKEN@*/Color.orange/*@END_MENU_TOKEN@*/)
                Spacer()
                HStack {
                    Spacer()
                    Text("3回前")
                        .frame(width: 50.0)
                    Text("2回前")
                        .frame(width: 50.0)
                    Text("前回")
                        .frame(width: 50.0)
                    Text("今回")
                        .font(.title)
                        .frame(width: 80.0)
                    Spacer()
                }
                HStack {
                    Spacer()
                    Text(processor.num(times:4))
                        .frame(width: 50.0)
                    Text(processor.num(times:3))
                        .frame(width: 50.0)
                    Text(processor.num(times:2))
                        .frame(width: 50.0)
                    Text(processor.num(times:1))
                        .font(.largeTitle)
                        .frame(width: 80.0)
                    Spacer()
                }
                Spacer()
                HStack {
                    Spacer()
                    Button(action: {
                        self.processor.judge(choice: "high")
                    }) {
                        Text("High")
                            .font(.largeTitle)
                            .fontWeight(.bold)
                            .foregroundColor(Color.white)
                    }
                    .frame(width: 100.0)
                    .background(/*@START_MENU_TOKEN@*/Color.red/*@END_MENU_TOKEN@*/)
                    Spacer()
                    Button(action: {
                        self.processor.judge(choice: "low")
                    }) {
                        Text("Low")
                            .font(.largeTitle)
                            .fontWeight(.bold)
                            .foregroundColor(Color.white)
                    }
                    .frame(width: 100.0)
                    .background(Color.blue)
                    Spacer()
                }
                Spacer()
                Text(processor.result)
                    .font(.title)
                    .fontWeight(.heavy)
                    .foregroundColor(Color.orange)
                    .multilineTextAlignment(.center)
                Text("$\(processor.reward)")
                    .font(.largeTitle)
                    .fontWeight(.black)
                    .foregroundColor(Color.red)
                
                HStack {
                    Button(action: processor.reset) {
                        Text("ResetData")
                    }
                    Spacer()
                    NavigationLink(destination: ScoreBoard()) {
                        Text("高額当選記録へ")
                    }
                }
            }
        }
    }
}


struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

次回は

 実は配列を格納順にはき出しているだけで、スコア順に並んでいません。次回は、上位20位まできちんと並べて表示させてみます。

モバイルバージョンを終了