I am making a game in which the player can achieve a positive high score or a negative low score depending on the choices they make. The code that I've been using works great if there is only one leaderboard, but I'm having trouble when I try to add the second. TEHS is the leaderboard identifier for HighScore and TELS is the leaderboard identifier for LowScore.
I authenticate the local player:
-(void)authenticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
TEHS = leaderboardidentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
Scores are reported:
-(void)reportHighScore{
GKScore *highscore = [[GKScore alloc] initWithLeaderboardIdentifier:TEHS];
highscore.value = HighScoreNumber;
[GKScore reportScores:#[highscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
-(void)reportLowScore {
GKScore *lowscore = [[GKScore alloc] initWithLeaderboardIdentifier:TELS];
lowscore.value = LowScoreNumber;
[GKScore reportScores:#[lowscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
And, the leaderboards are shown when the player activates:
-(void)showLeaderboardAndAchievements:(BOOL)shouldShowLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
if (shouldShowLeaderboard) {
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = TEHS;
}
else{
gcViewController.viewState = GKGameCenterViewControllerStateAchievements;
}
[self presentViewController:gcViewController animated:YES completion:nil];
}
Either reportLowScore or reportHighScore will work when I change
gcViewController.leaderboardIdentifier = TEHS;
and
TEHS = leaderboardidentifier;
to match their respective identifier. So, right now, this code works for High Score (TEHS), and if I changed the above two to TELS, Low Score would work. I'm just not quite sure what I need to do to authenticateLocalPlayer and showLeaderboardAndAchievements to get both leaderboards to work.
I have a game on the App Store that has two leaderboards, one for points and one for levels cleared. Instead of having one method for each leaderboard I made one method for submitting scores. Here is that method:
-(void) submitScore:(int64_t)score Leaderboard: (NSString*)leaderboard
{
//1: Check if Game Center
// features are enabled
if (!_gameCenterFeaturesEnabled) {
return;
}
//2: Create a GKScore object
GKScore* gkScore =
[[GKScore alloc]
initWithLeaderboardIdentifier:leaderboard];
//3: Set the score value
gkScore.value = score;
//4: Send the score to Game Center
[gkScore reportScoreWithCompletionHandler:
^(NSError* error) {
[self setLastError:error];
BOOL success = (error == nil);
if ([_delegate
respondsToSelector:
#selector(onScoresSubmitted:)]) {
[_delegate onScoresSubmitted:success];
}
}];
}
When you want to submit your high scores all you have to do is add something like:
[[GCHelper sharedGameKitHelper] submitScore:myLowScore Leaderboard:TELS];
[[GCHelper sharedGameKitHelper] submitScore:myHighScore Leaderboard:TEHS];
GCHelper is the class that contains my submitScore:Leaderboard: method.
To view your leaderboards or achievements within your app try this:
- (void) presentLeaderboards {
GKGameCenterViewController* gameCenterController = [[GKGameCenterViewController alloc] init];
gameCenterController.viewState = GKGameCenterViewControllerStateLeaderboards;
gameCenterController.gameCenterDelegate = self;
[self presentViewController:gameCenterController animated:YES completion:nil];
}
- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController*) gameCenterViewController {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void) presentAchievements {
GKGameCenterViewController* gameCenterController = [[GKGameCenterViewController alloc] init];
gameCenterController.viewState = GKGameCenterViewControllerStateAchievements;
gameCenterController.gameCenterDelegate = self;
I hope this answers your question!
Related
So I have an App that has a Game A and Game B.
I have Game Centre implemented correctly for Game A (I used the AppCoda tutorial like I have for every game so far).
Now I'm having troubles getting it to submit the score if Game B is played. I need to the score to be submitted to the second leaderboard created in iTunes Connect.
This is my part of my ViewController that authenticates the User and uses the identifier for the leaderboard etc.
ViewController.h:
-(void)authenticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES; //added bool indentier to .h
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier; //added pointer to NSString to .h
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
Seems my Game B View Controller is scorings/submitting just like Game A, I figured I could just change the above code to this:(to allow for the second identifier):
-(void)authenticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES; //added bool indentier to .h
_gameCenterEnabled2 = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier; //added pointer to NSString to .h
}
}];
// Get the second leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier2, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier2 = leaderboardIdentifier2; //added pointer to NSString to .h
}
}];
}
else{
_gameCenterEnabled = NO;
_gameCenterEnabled2 = NO;
}
}
};
}
But for some reason, it won't send the score to the second leaderboard and I can't find any resources/tutorials on how to submit a score to a "non-default" leaderboard...
Ok, so I re-read the Apple Doc and found the solution.
Obviously there can only be ONE default leaderboard (which is authenticated and set in the code in my question)... This doesn't need changing like I originally thought. (I forgot it was used to set the default board).
So what I needed to do was set the Leaderboard identifier to the second leaderboard's identifier (this will be whatever ID you used in iTunes Connect when making the second leaderboard).
I did it in the Game B View Controller when reporting a score like this:
-(void)reportScore{
//set identifier manually as it's not the default leaderboard
GKScore *score = [[GKScore alloc] initWithLeaderboardIdentifier:#"The_GameB_Leaderboard"];
//GKScore *score = [[GKScore alloc] initWithLeaderboardIdentifier:_leaderboardIdentifier2];
score.value = ScoreNumber_B; //Game B HighScore
[GKScore reportScores:#[score] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
NSLog(#"Reported to Game Center...");
}
There's no need to change the -(void)authenticateLocalPlayer method unless you need to add the GameB bool like I did, in which case you can add it below the GameA Bool:
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES; //added bool indentier to .h
_gameCenterEnabled2 = YES; //GameB bool
.
.
.
}
I hope this helps.
I released my app yesterday and few units were sold so far. But I figured out that the leaderboard doesn't work properly. I can only see my own score when I'm done with my game. Is there some kind of delay until the leaderboard is updated or is it a problem on my implementation? I'd really appreciate if I have my implementation checked by someone who knows how to do it properly. On a side note, I already configured my leaderboard on itunes-connect and enabled it as well. I'm not sure if GKLocalPlayer's instance method loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) is the right method to use to load the correct leaderboardID. Do I manually have to declare my leaderboard ID on Xcode somewhere with the leaderboardID I created on itunes-connect? because I find it odd that I never get to use it on the actual implementation... I want this error fixed as soon as possible and I need you guys' help. Thanks.
(void)authenticateLocalPlayer {
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
NSLog(#"authenticated");
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"here");
NSLog(#"%#", [error description]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
- (void)reportScore:(NSNotification *) notification {
if (_gameCenterEnabled) {
NSDictionary *userInfo = notification.userInfo;
NSNumber *score = [userInfo objectForKey:#"highestScore"];
GKScore *gkscore = [[GKScore alloc]initWithLeaderboardIdentifier:_leaderboardIdentifier];
gkscore.value = [score integerValue];
[GKScore reportScores:#[gkscore] withCompletionHandler:^(NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
}];
}
}
- (void)showLeaderboard{
GKGameCenterViewController *gcViewController = [[GKGameCenterViewController alloc] init];
gcViewController.gameCenterDelegate = self;
gcViewController.viewState = GKGameCenterViewControllerStateLeaderboards;
gcViewController.leaderboardIdentifier = _leaderboardIdentifier;
[self presentViewController:gcViewController animated:YES completion:nil];
}
- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController
{
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
I am trying to implement game center in my new app, I am following a tutorial from
http://www.appcoda.com/ios-game-kit-framework/
I am following the same procedure but unfortunately I am not able to sove it here is my code
-(void)authenticateLocalPlayer{
GKLocalPlayer *localPlayer = [GKLocalPlayer localPlayer];
localPlayer.authenticateHandler = ^(UIViewController *viewController, NSError *error){
if (viewController != nil) {
[self presentViewController:viewController animated:YES completion:nil];
}
else{
if ([GKLocalPlayer localPlayer].authenticated) {
_gameCenterEnabled = YES;
// Get the default leaderboard identifier.
[[GKLocalPlayer localPlayer] loadDefaultLeaderboardIdentifierWithCompletionHandler:^(NSString *leaderboardIdentifier, NSError *error) {
if (error != nil) {
NSLog(#"%#", [error localizedDescription]);
}
else{
_leaderboardIdentifier = leaderboardIdentifier;
}
}];
}
else{
_gameCenterEnabled = NO;
}
}
};
}
I am on the first step and I am authenticating the player but when i build and run as described in the tutorial I see the errors on lines where it says "use of undeclared identifiers.
_gameCenterEnabled = YES; ------ Use of undeclared identifier '_gameCenterEnabled'
_leaderboardIdentifier = leaderboardIdentifier;----- Use of undeclared identifier 'leaderboardIdentifier'
_gameCenterEnabled = NO;---- Use of undeclared identifier '_gameCenterEnabled'
You have to declare _gameCenterEnabled and _leaderboardIdentifier as properties first.
#property(nonatomic, strong) NSString *leaderboardIdentifier;
#property(nonatomic, assign) BOOL gameCenterEnabled;
I am trying to upload my scores for my game to Gamecenter, however I cannot write code to do that without getting errors. Also, it says that there is no class method for reportScores:scores. I am not sure how to implement that into the Gamecenter Class.
-(void) reportScore: (int64_t) score forLeaderboardID: #"tap_amateur" identifier
{
GKScore *scoreReporter = [[GKScore alloc] initWithLeaderboardIdentifier:#"tap_amateur"];
scoreReporter.value = score;
scoreReporter.context = 0;
NSArray *scores = #[scoreReporter];
[GKLeaderboard reportScores:scores withCompletionHandler:^(NSError *error) {
}];
}
#end
Try changing:
[GKLeaderboard reportScores:scores withCompletionHandler:^(NSError *error) {
}];
to:
[GKLeaderboard reportScoreWithCompletionHandler:
^(NSError* error) {
[self setLastError:error];
BOOL success = (error == nil);
if ([_delegate
respondsToSelector:
#selector(onScoresSubmitted:)]) {
[_delegate onScoresSubmitted:success];
}
}];
Hi i Intigrate SpotifyLib CocoaLibSpotify iOS Library 17-20-26-630 into my Project. I open its SPLoginViewController using Bellow Method:-
-(void)OpenSpotify
{
NSError *error = nil;
[SPSession initializeSharedSessionWithApplicationKey:[NSData dataWithBytes:&g_appkey length:g_appkey_size]
userAgent:#"com.mycomp.spotify"
loadingPolicy:SPAsyncLoadingImmediate
error:&error];
if (error != nil) {
NSLog(#"CocoaLibSpotify init failed: %#", error);
abort();
}
[[SPSession sharedSession] setDelegate:self];
[self performSelector:#selector(showLogin) withObject:nil afterDelay:0.0];
}
-(void)showLogin
{
SPLoginViewController *controller = [SPLoginViewController loginControllerForSession:[SPSession sharedSession]];
controller.allowsCancel = YES;
//controller.view.frame=;
[self presentViewController:controller animated:YES completion:nil];
}
At First time that Appear Spotify Login Screen. After that I tap On Cancel Button, and Try to open again login screen then i got crash EXC_BAD_EXE at this line. sp_error createErrorCode = sp_session_create(&config, &_session);
UPDATE
I Found exet where is got BAD_EXC
in this method
+(void)dispatchToLibSpotifyThread:(dispatch_block_t)block waitUntilDone:(BOOL)wait {
NSLock *waitingLock = nil;
if (wait) waitingLock = [NSLock new];
// Make sure we only queue one thing at a time, and only
// when the runloop is ready for it.
[runloopReadyLock lockWhenCondition:1];
CFRunLoopPerformBlock(libspotify_runloop, kCFRunLoopDefaultMode, ^() {
[waitingLock lock];
if (block) { #autoreleasepool { block(); } }
[waitingLock unlock];
});
if (CFRunLoopIsWaiting(libspotify_runloop)) {
CFRunLoopSourceSignal(libspotify_runloop_source);
CFRunLoopWakeUp(libspotify_runloop);
}
[runloopReadyLock unlock]; // at hear when my debug poin reach after pass this i got bad_exc
if (wait) {
[waitingLock lock];
[waitingLock unlock];
}
}
after doing lots of search i got Solution i check that whether the session already exists then i put if condition like:-
-(void)OpenSpotify
{
SPSession *session = [SPSession sharedSession];
if (!session) {
NSError *error = nil;
[SPSession initializeSharedSessionWithApplicationKey:[NSData dataWithBytes:&g_appkey length:g_appkey_size]
userAgent:#"com.mycomp.spotify"
loadingPolicy:SPAsyncLoadingImmediate
error:&error];
if (error != nil) {
NSLog(#"CocoaLibSpotify init failed: %#", error);
abort();
}
[[SPSession sharedSession] setDelegate:self];
}
[self performSelector:#selector(showLogin) withObject:nil afterDelay:0.0];
}
-(void)showLogin
{
SPLoginViewController *controller = [SPLoginViewController loginControllerForSession:[SPSession sharedSession]];
controller.allowsCancel = YES;
[self presentViewController:controller animated:YES completion:nil];
}
Now no crash and working fine.