先日、NCMBのSwift SDKを使ってゲームのランキング機能を実装する - Qiitaという記事をアップしましたが、その後こんなツイートを拝見しました。
ランキングを時間軸で絞り込むことで、今月のランキングや先週のランキングなどを実現します。確かに、圧倒的な順位の人が君臨してしまうとやる気をなくしそうですが、週間ランキングなどがあれば順位変動が激しくて良さそうです。
ということで、Swift SDKを使ったランキング機能にも、過去30日と7日間でランキングを絞り込めるようにしてみました。この実装はNCMBのSwift SDKを使ってゲームのランキング機能を実装する - Qiitaを前提としています。また、コードはGitHub - NCMBMania/Swift_Ranking_Demo: Swift SDKを使って実装したランキング機能のデモですにアップしてあります。
変更点について
まずEnumで時間のレンジを定義しています。
enum RankingRange {
case All, Month, Week
}
そしてボタンを追加して、それぞれレンジを引数に送るようにします。
Button("過去30日", action: {
getRanking(range: RankingRange.Month)
})
Button("過去7日", action: {
getRanking(range: RankingRange.Week)
})
if rankings.count > 0 {
List {
ForEach(Array(rankings.enumerated()), id: \.offset) { i, ranking in
Text(listString(index: i, ranking: ranking))
}
}
}
func listString(index: Int, ranking: NCMBObject) -> String {
let displayName: String = ranking["displayName"] ?? ""
let score: Int = ranking["score"] ?? 0
return "\(index + 1)位 \(displayName)さん (\(score)点)"
}
ランキングの取得
ランキングの取得時には、指定されたレンジに応じて日時オブジェクトを作成しています。
func getRanking(range: RankingRange = .All) {
var date: Date?
let calendar = Calendar.current
let today = Date()
switch range {
case .Month:
date = calendar.date(byAdding: .day, value: -30, to: today)
break
case .Week:
date = calendar.date(byAdding: .day, value: -7, to: today)
break
default:
break
}
// 下に続く
そして、日付が指定されている場合のみ greaterThanOrEqualTo
を使って指定された日付以降のデータだけを対象とする絞り込みを行っています。
// ランキングデータ検索用のクエリオブジェクトを作成
var query = NCMBQuery.getQuery(className: "Ranking")
// 並び順はスコアの高い順です
query.order = ["-score"]
// 100件のデータを取得します
query.limit = 100
// 日付が指定されていれば、その日以降のデータに限定する
if date != nil {
query.where(field: "createDate", greaterThanOrEqualTo: date!)
}
// 検索実行
let results = query.find()
switch results {
case let .success(ary):
// 検索成功したら、それをrankingsに適用します
rankings = ary
case .failure(_): break
}
}
表示時の注意
ランキングの内容が変わるので、 rankings.indice
だとうまく反映されませんでした(最初に10件表示していると、次に2件に変わった時にも最初にi = 10になってしまう)。そこで、以下のようにForEachの内容を変えています。
// 元
List {
ForEach(rankings.indices) { i in
Text(listString(index: i))
}
}
// 変更後
List {
ForEach(Array(rankings.enumerated()), id: \.offset) { i, ranking in
Text(listString(index: i, ranking: ranking))
}
}
これに伴ってlistStringも多少変わっています。
// ランキングの順位、ゲームユーザ名、スコアを返します
func listString(index: Int, ranking: NCMBObject) -> String {
let displayName: String = ranking["displayName"] ?? ""
let score: Int = ranking["score"] ?? 0
return "\(index + 1)位 \(displayName)さん (\(score)点)"
}
まとめ
NCMBの以上、以下と言った検索のオペランドを使うことで、指定日以降のランキングを作ったり、先月だけのランキングを作ると言ったことも簡単に実現できます。ぜひSwiftを使ったゲーム開発に活かしてください。