티스토리 뷰
플러터(Flutter)는 뛰어난 확장성과 다양한 플러그인 지원을 통해 모바일 게임 개발자들에게 많은 기능을 제공합니다. 이 중에서도 게이머들의 몰입과 도전을 자극하는 리더보드와 업적 시스템을 쉽게 구현할 수 있도록 하는 games_services
플러그인에 대해 알아보겠습니다. 이번 포스트에서는 리더보드와 업적 기능의 주요 설정 방법과 플러그인의 활용 팁을 다룹니다.
참고. Add achievements and leaderboards to your mobile game
플러터 게임 개발을 위한 games_services
플러그인: 리더보드와 업적을 위한 필수 기능
게임에서 업적과 리더보드는 사용자의 도전 의식을 고취시키는 필수 요소입니다. 업적 시스템은 특정 목표를 달성하면 보상을 주어 사용자의 성취감을 자극하며, 리더보드는 점수 경쟁을 통해 다른 사용자와 경쟁할 수 있는 기회를 제공합니다. 이러한 기능은 구글 플레이와 애플의 게임 서비스 플랫폼과 연동해 구현할 수 있으며, 플러터에서는 games_services
플러그인을 통해 쉽게 적용 가능합니다.
1. 플랫폼 서비스 활성화: iOS와 Android 설정
게임에 업적 및 리더보드 기능을 추가하기 위해선 먼저 iOS와 Android에서 플랫폼 설정을 해야 합니다.
iOS: Game Center 설정
- Xcode에서 플러터 프로젝트를 열고
ios/Runner.xcworkspace
를 선택합니다. Signing & Capabilities
탭에서+
버튼을 눌러 Game Center를 활성화합니다.- App Store Connect에서 게임을 등록하고, 리더보드와 업적 ID를 생성해 기록해 둡니다.
Android: Google Play Games Services 설정
- Google Play Console에서 게임을 등록하고, Play Games Services를 설정합니다.
- OAuth 인증 화면 설정 등 여러 단계를 거쳐 리더보드와 업적 ID를 생성해 기록합니다.
- 설정이 완료되면, Google Cloud Console에서 발급받은 XML 파일을
android/app/src/main/res/values/games-ids.xml
에 추가합니다.
2. 게임 서비스 로그인 설정
플러그인을 설치한 후 플레이어를 게임 서비스에 로그인시켜야 합니다. 이를 위해 games_services
의 signIn()
메서드를 호출합니다.
try {
await GamesServices.signIn();
} on PlatformException catch (e) {
// 로그인 실패 처리
}
로그인 시도는 앱 실행 직후가 아닌, 플레이어가 게임을 시작하는 시점에 실행하는 것이 좋습니다. 로그인 실패에 대비해 try-catch
블록으로 예외 처리를 추가하면 안정성이 향상됩니다.
3. 업적 해제하기
게임 내 특정 이벤트나 점수를 달성한 플레이어에게 업적을 부여하려면, 미리 등록해둔 업적 ID를 사용하여 다음과 같이 unlock()
메서드를 호출합니다.
await GamesServices.unlock(
achievement: Achievement(
androidID: 'your_android_id',
iOSID: 'your_ios_id',
),
);
플레이어는 Game Center 또는 Google Play Games에서 해당 업적을 확인할 수 있습니다. 앱 내 업적 UI를 직접 구현하려면 GamesServices.loadAchievements()
를 사용하여 업적 목록을 불러올 수 있습니다.
4. 리더보드 점수 제출 및 표시
게임 세션이 끝난 후, 플레이어의 점수를 리더보드에 제출하려면 submitScore()
메서드를 사용합니다.
await GamesServices.submitScore(
score: Score(
iOSLeaderboardID: 'app_store_leaderboard_id',
androidLeaderboardID: 'google_play_leaderboard_id',
value: 100, // 제출할 점수 값
),
);
점수 제출 후에는 리더보드 UI를 오버레이로 표시할 수도 있습니다. showLeaderboards()
메서드를 호출하면 리더보드가 게임 화면 위에 나타납니다.
5. 다음 단계: 추가 기능 활용하기
games_services
플러그인은 단순한 업적 해제와 리더보드 점수 제출 외에도 다양한 기능을 제공합니다. 예를 들어, 플레이어의 프로필 사진, 이름, 고유 ID 등을 불러오거나 게임 진행 상태를 저장할 수 있습니다. 이를 통해 게임의 완성도와 사용자 경험을 한층 높일 수 있습니다.
class GamesServicesController {
Future<void> awardAchievement({required String iOS, required String android}) async {
if (await signedIn) {
await GamesServices.unlock(
achievement: Achievement(androidID: android, iOSID: iOS),
);
}
}
Future<void> submitLeaderboardScore(int score) async {
if (await signedIn) {
await GamesServices.submitScore(
score: Score(iOSLeaderboardID: 'app_store_id', androidLeaderboardID: 'google_play_id', value: score),
);
}
}
}
결론: games_services
로 완성하는 게임 내 경쟁과 성취 요소
플러터로 게임을 개발하면서 경쟁과 성취 요소를 강화하려면 games_services
플러그인을 통해 업적과 리더보드를 추가하는 것이 필수적입니다. iOS와 Android의 게임 서비스 플랫폼과 연동하여 빠르고 쉽게 이 기능을 구현할 수 있으며, 사용자에게 몰입도 높은 게임 경험을 제공할 수 있습니다.
import 'dart:async';
import 'package:games_services/games_services.dart';
import 'package:logging/logging.dart';
/// Allows awarding achievements and leaderboard scores,
/// and also showing the platforms' UI overlays for achievements
/// and leaderboards.
///
/// A facade of `package:games_services`.
class GamesServicesController {
static final Logger _log = Logger('GamesServicesController');
final Completer<bool> _signedInCompleter = Completer();
Future<bool> get signedIn => _signedInCompleter.future;
/// Unlocks an achievement on Game Center / Play Games.
///
/// You must provide the achievement ids via the [iOS] and [android]
/// parameters.
///
/// Does nothing when the game isn't signed into the underlying
/// games service.
Future<void> awardAchievement(
{required String iOS, required String android}) async {
if (!await signedIn) {
_log.warning('Trying to award achievement when not logged in.');
return;
}
try {
await GamesServices.unlock(
achievement: Achievement(
androidID: android,
iOSID: iOS,
),
);
} catch (e) {
_log.severe('Cannot award achievement: $e');
}
}
/// Signs into the underlying games service.
Future<void> initialize() async {
try {
await GamesServices.signIn();
// The API is unclear so we're checking to be sure. The above call
// returns a String, not a boolean, and there's no documentation
// as to whether every non-error result means we're safely signed in.
final signedIn = await GamesServices.isSignedIn;
_signedInCompleter.complete(signedIn);
} catch (e) {
_log.severe('Cannot log into GamesServices: $e');
_signedInCompleter.complete(false);
}
}
/// Launches the platform's UI overlay with achievements.
Future<void> showAchievements() async {
if (!await signedIn) {
_log.severe('Trying to show achievements when not logged in.');
return;
}
try {
await GamesServices.showAchievements();
} catch (e) {
_log.severe('Cannot show achievements: $e');
}
}
/// Launches the platform's UI overlay with leaderboard(s).
Future<void> showLeaderboard() async {
if (!await signedIn) {
_log.severe('Trying to show leaderboard when not logged in.');
return;
}
try {
await GamesServices.showLeaderboards(
// TODO: When ready, change both these leaderboard IDs.
iOSLeaderboardID: 'some_id_from_app_store',
androidLeaderboardID: 'sOmE_iD_fRoM_gPlAy',
);
} catch (e) {
_log.severe('Cannot show leaderboard: $e');
}
}
/// Submits [score] to the leaderboard.
Future<void> submitLeaderboardScore(int score) async {
if (!await signedIn) {
_log.warning('Trying to submit leaderboard when not logged in.');
return;
}
_log.info('Submitting $score to leaderboard.');
try {
await GamesServices.submitScore(
score: Score(
// TODO: When ready, change these leaderboard IDs.
iOSLeaderboardID: 'some_id_from_app_store',
androidLeaderboardID: 'sOmE_iD_fRoM_gPlAy',
value: score,
),
);
} catch (e) {
_log.severe('Cannot submit leaderboard score: $e');
}
}
}
'Flutter Cookbook' 카테고리의 다른 글
Flutter 앱에서 구글 모바일 광고 구현하기: 시작부터 배너 광고까지 (2) | 2024.11.09 |
---|---|
Flutter로 Firestore를 활용한 멀티플레이어 게임 구현하기 (1) | 2024.11.08 |
Flutter에서 텍스트 필드 입력값 가져오기: TextEditingController 활용법 (2) | 2024.11.07 |
Flutter에서 텍스트 필드 변경 사항 감지하기: 실시간 입력 제어의 모든 것 (2) | 2024.11.06 |
Flutter에서 텍스트 필드 포커스 관리하기: 효과적인 사용자 경험 만들기 (2) | 2024.11.05 |