이 글에서는 앱 내에 GameCenter 리더보드(Leaderboard)를 구현해야 하는 이유와 실제 구현 방법을 단계별로 자세히 알아보겠습니다.
GameCenter가 다시 주목받고 있는 이유
점수판 없이도 아이폰 게임을 만들 수 있지만, 리더보드가 있으면 게임에 경쟁 요소가 더해져 전 세계 플레이어들과 실시간으로 겨루는 듯한 느낌을 줄 수 있습니다.
자체 백엔드 서버를 구축하고 관리하는 대신 GameCenter 리더보드를 활용하면 다음과 같은 장점이 있습니다.
- 트래픽이 아무리 몰려도 무한히 확장 가능
- 복잡한 로그인 페이지 없이 인증 처리 가능
- 사용자의 프로필 이미지, 이름, 같은 게임을 하는 친구 정보까지 자동으로 연동
특히 iOS 16부터 Apple은 GameCenter 개선에 더욱 힘을 쏟고 있습니다. 예를 들어 친구가 내 기록을 넘어섰을 때 푸시 알림을 보내는 등 앱 사용률을 높이는 기능들이 추가되었습니다.
저 역시 SwiftUI를 배우면서 직접 앱을 만들고 출시하며 공부해왔습니다. 제 경험상 직접 만들어 보는 것이 가장 좋은 학습 방법입니다.
그런데 이런 기능들을 다루는 최신 문서가 많지 않았습니다. SwiftUI 관련 문서는 물론이고 Swift의 async/await 문법을 적용한 자료도 거의 없었죠. 그래서 여러분 모두가 멋진 앱을 만들 수 있도록 내용을 정리하고 단순화했습니다. 앱 테스트에 초대해주신다면 언제든 참여할 준비가 되어 있습니다!
시작 전 준비 사항
- Apple Developer 유료 계정 필요
- Apple Developer 포털의 프로비저닝 프로파일 섹션에서 앱의 App ID 생성 필요
- iTunes Connect(App Store Connect) 포털에 앱 등록 필요
6단계로 iOS 리더보드 구현하기
바로 코드를 확인하고 싶으신 분들은 아래 리더보드 코드 로직 파일을 참고하세요. 전체 과정은 다음과 같습니다.
1단계: App Store Connect에서 리더보드 생성하기
App Store Connect 포털에서 앱 생성을 완료했다면, 해당 앱의 '서비스(Services)' 탭으로 이동하여 GameCenter 페이지에 진입합니다.
그다음 '+' 버튼을 눌러 새 리더보드를 추가합니다. 리더보드는 두 가지 유형 중 선택할 수 있습니다.
- 클래식(Classic): 점수가 초기화되지 않음
- 반복형(Recurring): 설정한 주기에 따라 점수가 초기화됨
대부분의 게임은 반복형 리더보드를 선호합니다. 도저히 따라잡을 수 없는 오래된 최고 점수들로 리더보드가 어수선해지는 것을 막을 수 있기 때문입니다.
여기서 입력하는 LeaderboardID가 코드에서 리더보드를 참조할 때마다 사용하게 되는 핵심 값입니다.
2단계: GameCenter 인증 설정하기
모든 기능이 정상 작동하려면 먼저 사용자를 GameCenter에 인증해야 합니다.
아래 코드를 사용하면 현재 사용자(GKLocalPlayer.local)가 인증되어 있는지 확인하고, 오류가 발생하면 이를 출력합니다.
func authenticateUser() {
GKLocalPlayer.local.authenticateHandler = { vc, error in
guard error == nil else {
print(error?.localizedDescription ?? "")
return
}
}
}
사용자가 인증되면 UI에 작은 팝업이 나타나고, 인증되지 않았다면 GameCenter 계정 로그인 화면으로 이동하게 됩니다.
3단계: UI에 리더보드 항목 표시하기
GameCenter ViewController 리더보드(GKLeaderboard)에서 데이터를 가져오려면 loadLeaderboards 메서드를 사용해야 합니다.
loadEntries 함수의 범위를 .global에서 .friends로 변경하면 친구들의 기록만 불러올 수 있습니다.
또한 각 플레이어를 순회하면서 loadPhoto를 호출하면 각 플레이어의 프로필 이미지도 가져올 수 있습니다.
NSRange(1...5)를 사용하면 표시할 플레이어 수를 조절할 수 있습니다. 이렇게 하면 리더보드에서 상위 5명의 사용자를 가져오며, 반복형 리더보드의 주기가 초기화되는 경우처럼 사용자가 없으면 아무것도 반환하지 않습니다.
async-await를 활용하면 리더보드 데이터를 가져오는 코드를 다음과 같이 작성할 수 있습니다.
func loadLeaderboard() async {
playersList.removeAll()
Task{
var playersListTemp : [Player] = []
let leaderboards = try await GKLeaderboard.loadLeaderboards(IDs: [leaderboardIdentifier])
if let leaderboard = leaderboards.filter ({ $0.baseLeaderboardID == self.leaderboardIdentifier }).first {
let allPlayers = try await leaderboard.loadEntries(for: .global, timeScope: .allTime, range: NSRange(1...5))
if allPlayers.1.count > 0 {
try await allPlayers.1.asyncForEach { leaderboardEntry in
var image = try await leaderboardEntry.player.loadPhoto(for: .small)
playersListTemp.append(Player(name: leaderboardEntry.player.displayName, score:leaderboardEntry.formattedScore, image: image))
print(playersListTemp)
playersListTemp.sort{
$0.score < $1.score
}
}
}
}
playersList = playersListTemp
}
}
4단계: SwiftUI에서 뷰가 나타날 때 함수 호출하기
뷰의 onAppear 라이프사이클 함수를 활용하면 화면이 나타날 때 인증과 데이터 로딩을 자동으로 실행할 수 있습니다. 물론 버튼 탭 시점에 실행하도록 구성해도 무방합니다.
.onAppear(){
if !GKLocalPlayer.local.isAuthenticated {
authenticateUser()
} else if playersList.count == 0 {
Task{
await loadLeaderboard()
}
}
}
5단계: 제출된 점수 불러오기
점수를 불러오려면 먼저 점수를 제출해야 합니다. 이때 submitScore 함수를 활용하면 됩니다.
flightsClimbed변수에는 제출하고 싶은 점수 값을 담습니다.- GameKit은 리더보드가 존재하는 동안 사용자의 최고 점수만 표시하도록 자동 처리합니다.
leaderboardId에는 App Store Connect 계정에서 직접 입력한 값을 넣습니다.
func leaderboard() async{
Task{
try await GKLeaderboard.submitScore(
flightsClimbed,
context: 0,
player: GKLocalPlayer.local,
leaderboardIDs: ["com.tfp.stairsteppermaster.flights"]
)
}
calculateAchievements()
}
6단계: GameCenter ViewController 포털 표시하기
GameCenter에 로그인하면 화면 우측 상단에 작은 아이콘이 나타납니다. 이 아이콘을 탭하면 GameCenter ViewController로 이동하는데, 디자인상 방해가 된다면 GKAccessPoint.shared.isActive = false로 숨길 수 있습니다.
GameCenter UI는 단순한 SwiftUI View가 아니라 UIKit의 ViewController이기 때문에, 먼저 UIViewControllerRepresentable을 생성해야 합니다. 그런 다음 별도의 버튼으로 GameCenter를 실행할 수 있습니다.
해당 파일을 프로젝트에 추가하면 GameCenterView(format: gameCenterViewControllerState) 한 줄만으로 GameCenter 포털을 표시할 수 있으며, gameCenterViewControllerState 값을 조정해 GameCenter 내 세부 페이지로 바로 이동할 수도 있습니다.
GameCenter 리더보드 사용 시 알아두어야 할 사항
- 시뮬레이터 디버깅: 특정 이유로 시뮬레이터에서 GameCenter 인증 속도가 매우 느립니다. 시뮬레이터 사용 시 목(mock) 데이터를 만들어두는 것이 효율적입니다.
- 챌린지(Challenges): 지원 중단(deprecated)으로 인해 프로그래밍 방식으로 친구에게 GameKit 챌린지를 보낼 수 없게 되었습니다. 대신 사용자의 GameCenter 대시보드에서 GameKit 업적(Achievements)을 대상으로 수동으로 챌린지를 진행해야 합니다. 또한 보낸 챌린지를 조회하는 방법도 없습니다.
- 업적(Achievements): 리더보드와 업적은 서로 다른 개념입니다. 업적은 계산 및 표시 방식이 다르지만 훨씬 간단하며, 아래와 같이 앱 안으로 가져올 수도 있습니다.
마무리
위에서 소개한 오픈소스 무료 앱인 Stair Master Climber(아이폰 건강 및 피트니스 앱)를 직접 사용해 보세요. 여러분의 의견을 듣고 함께 성장할 수 있기를 바랍니다.
궁금한 점이 있다면 언제든지 소셜 미디어나 이메일로 문의해 주세요.