reset a single gamecenter achievement - ios

In my app I have an achievement for 10 wins in a row. So when the user wins 5 games in a row I report the achievement 50% completed - this works fine. When the user loses some games I call my resetAchievment method which sets the percentage to 0 and reports the percentage again. However when I restart the app the percentage gets read from the GKAchivement and it still shows 50%.
- ( void ) resetAchievement
{
_gamekitAchievement.percentComplete=0.0f;
_counter = 0;
[self report];
}
- ( void ) report
{
_gamekitAchievement.showsCompletionBanner = YES;
[_gamekitAchievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error)
{
NSLog(#"reporting Achievment: %# failed, error: %#", _gamekitAchievement.identifier, [error localizedDescription]);
}
}];
}
Is it not possible to report a smaller percentage again - or am I doing something wrong?

I have no actual experience from GameKit at all but from reading the documentation and searching the web it seems you're only able to report progress and not regression(?) Not to mention the fact that you can only reset ALL achievements... Perhaps the following would still help you achieve (ahem) what you want:
Update all your local achievement data with + (void)loadAchievementsWithCompletionHandler:
Store this data in the userDefaults for safety
Do NOT reset the local achievement data
Reset all the achievements with + (void)resetAchievementsWithCompletionHandler:
Change the percentComplete to 0 on the achievement in question.
report progress of all the achievements from your local storage
Now, as I mention, having no hands-on experience with this framework the above might not be practical for a number of reasons I am unaware of (the way progress is presented to the player for instance). Guess it was worth a shot to share the idea anyways...

Short answer: It is not possible to report a smaller percentage again.
Long answer: A lower GameCenter score will not overwrite a higher one.
For example you have a high score of 10 points and it's recorded in GameCenter.
If in the next try you get 5 points and they are submitted to GC, your high score of 10 won't be affected.
Similarly if you try to 'reset' your score, it counts as submitting a new score of 0, so it won't make a difference.
This only applies to scores and achievements submitted to GameCenter, inside your app you can do anything you want (for example your own custom leaderboard or something)

If you think about it, 5 wins is not 50% of the way there, since they could lose the 6th, then win 10 in a row, in which case they played 16 total games and 5 wins was more like 30% of the way there. In this case, it is all or nothing, so don't report anything until they have all 10.

Please be aware that storing the progress towards an achievement in NSUserDefaults doesn't take different GameCenter users into account. That means, if Player A (logged into GameCenter) makes some progress and at 90 % progress another Player B on the same device logs into GameCenter with his own account, he starts with the progress made by Player A.
You might solve this by storing a whole NSDictionary with the Player IDs as keys into NSUserDefaults.

What you'll want to do is save it NSUserdefaults. then, Call the NSUser default and check what number it is by using an IF statement.
-(void)checkAcheivement{
scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
if(scoreNumber == 10){
//Run code to save achievement in Game Center(_gamekit stuff)
}
//-(void)checkScoreFire{
//scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
//if(scoreNumber == 5){
//Run code to set up alert view for 5 wins below
//UIAlertView* message = [[UIAlertView alloc]
// initWithTitle: #"Alert"
// message: #"You are halfway to the Achievement!"
// delegate: self
// cancelButtonTitle: #"Dismiss"
// [message show];
//}
//to save score use this method:
-(void)saveScore{
scoreNumber = [NSUserDefaults standardUserDefaults] objectForKey:#"GamesWon"]
if(gameScore > scoreNumber){
[[NSUserDefaults standardUserDefaults]setInteger:scoreNumber forKey:#"GamesWon"];
}
This will only post the achievement if it is ten, i suggest not putting the achievement in until then, because it makes it more difficult. I also suggest setting up an AlertView to let the person know they are halfway there. You can do so with the code commented above with the checkScoreFive method. Remember to declare everything in the .h file as well.
IBOutlet UIAlertView *AlertView;
-(void)checkAcheivement;
-(void)checkScoreFire;
-(void)saveScore;
int gameScore;
int scoreNumber;

Related

google Play game Leaderboard in ios

I have used Google play game leaderboard in my iOS app.i am submitting score from my and fetch score from there. i am using following method to submit score
`[score submitScoreWithCompletionHandler: ^(GPGScoreReport *report, NSError *error) {
if (error) {
// Handle the error
} else {
// Analyze the report, if you'd like
}
}];`
and below code to present leaderboard
NSString *targetLeaderboardId = #"my id";
[[GPGLauncherController sharedInstance] presentLeaderboardWithLeaderboardId:targetLeaderboardId];
but fetching score takes to much time.is there any way to reload or refresh leaderboard data.
anyone have any idea!
Unfortunately, Google Play Games Services for iOS has been deprecated, so I would not recommend putting too much time into it. More information: https://android-developers.googleblog.com/2017/04/focusing-our-google-play-games-services.html

Get user visits count of window in appcelerator titanium

I am working on ios app,,User will login to the app.I have multiple screens in one screen i have a requirement is if user first time visits that screen i need to show the instructions screen.If screen visits count more than once no need to show the instructions.
I need to store that screens count for each user separately how can we achieve this in appcelerator titanium
Please help me thanks in advance.
You could use the open or focus event to pick up when someone hits the screen and then either:
If this is a connected app, and you're downloading the user profile on login, you could store a flag to say tutorialSeen or similar. Check this when the window opens / focuses or
if not connected or you want to store locally, store the flag in the Ti.App.Properties under a user profile.
(you could equally store a count value that increments when they hit the screen but since you just want the first time captured, I'd go with a) capture event, b) check property, c) if false, set to true and show tutorial, d) if true, skip.)
Hope that helps!
I think you do not need to store the user visit count if your only purpose is to show the Instruction window only when user login into the app for first time.
You can do it this way:
someController.js
function onLoginSuccess() {
// getInt() will return the value of INSTRUCTION_WINDOW property, you can name this property whatever you want.
// if this property does not exist, then it will return the value of the second parameter.
var showInstruction = Ti.App.Properties.getInt("INSTRUCTION_WINDOW", 1);
if (showInstruction) {
Alloy.createController('instructionWindow').getView().open();
} else {
Alloy.createController('nextWindow').getView().open();
}
}
// logout function can be anywhere
// remember to set the property to 1 if you want to show the instructions again after logout and then login.
function logout() {
Ti.App.Properties.setInt("INSTRUCTION_WINDOW", 1);
}
instructionWindow.js
$.instructionWindow.addEventListener('open', function () {
// after opening the instruction window, set this property to 0
// so it won't be shown up the next time the already logged-in user opens the app
Ti.App.Properties.setInt("INSTRUCTION_WINDOW", 0);
});
first you set the nsuserdefaults value #"1".
[[NSUserDefaults standardUserDefaults] setObject:#"1" forKey:#"showtheinstruction"];
[[NSUserDefaults standardUserDefaults] synchronize];
after this you have to compare this string and shows the instruction message.
NSString *str_savedValue = [[NSUserDefaults standardUserDefaults]
stringForKey:#"showtheinstruction"];
if (str_savedValue isEqualToString:#"1") {
// show the instruction window.
}
else
{
// don't show the instruction window.
}

Game Center leaderboard score request's completion handler is never called for players that have no score

My game implements a custom user interface that lists the local player's friends.
I also have a Game Center leaderboard.
When my game lists the players, it also tries to load their scores from the leaderboard, using this code:
GKLeaderboard *request = [[GKLeaderboard alloc] initWithPlayerIDs:myFriends];
request.timeScope = GKLeaderboardTimeScopeAllTime;
request.identifier = #"my_leaderboards";
if (request != nil) {
[request loadScoresWithCompletionHandler: ^(NSArray *scores, NSError *error) {
if (error != nil) {
NSLog(#"Error: %#",error.localizedDescription);
}
if (scores != nil) {
NSLog(#"WORKED: %#",scores);
}
}];
}
And it works just fine.
... except when one of the friends has no score (for instance, they never played the game in the first place). When one of the players in myFriends has no score entry in the leaderboard, the completion handler is never called. There is no error and no score reported, because it never fires in the first place.
I realised this when testing an account that has two friends. One friend has played the game (so they have a score), and the other has not. The completion handler never got called. Then, I unfriended the guy that had no score, and the completion handler worked fine, returning the score of the friend that did have a score.
I somewhat understand this behaviour - after all, I'm asking it to give me a score that does not exist. But is there a workaround? As in, tell it to return a 0 if there is no score?
iOS 7.
It cannot be helped, the completion handler indeed won't be called because there is no score entry in the leaderboards. Although I still don't understand why doesn't it just return an error saying so.
Since the custom friend list just shows statistics, I just put a loading icon in place for each statistic. If the handler is not called for more than 10 seconds, I assume that there is no score entry and just display a 0.

Strange behaviour with setCurrentPlaybackTime

I use: MPMoviePlayerController to show video.
Below I put list of thumbs from the video.
When pressing a thumb I want to jump to a specific place in the video using: setCurrentPlaybackTime.
I also have a timer updating the selected thumb according to the location of the video using: currentPlaybackTime.
My problem: when calling: setCurrentPlaybackTime, the player keeps giving the seconds before seeking to the specific second. It take few seconds to the player to reflect the new seconds. In the mean time the experience of the user is bad: Pressing a thumb shows it selected for a show time, then the timer updates to the previous thumb, then it jumps back to the thumb I selected.
I tried using (in the timer):
if (moviePlayer.playbackState != MPMoviePlaybackStatePlaying && !(moviePlayer.loadState & MPMovieLoadStatePlaythroughOK)) return;
In order to prevent from the timer to update the selected thumb as long the player is in a transition phase between showing the previous thumb and the new thumb, but it doesn't seem to work. The "playbackState" and "loadState" seems to be totally inconstant and unpredictable.
For solving this issue, this how I have implemented this nasty state coverage in one of my projects. This is nasty and fragile but worked good enough for me.
I used two flags and two time intervals;
BOOL seekInProgress_;
BOOL seekRecoveryInProgress_;
NSTimeInterval seekingTowards_;
NSTimeInterval seekingRecoverySince_;
All of the above should be defaulted to NO and 0.0.
When initiating the seek:
//are we supposed to seek?
if (movieController_.currentPlaybackTime != seekToTime)
{ //yes->
movieController_.currentPlaybackTime = seekToTime;
seekingTowards_ = seekToTime;
seekInProgress_ = YES;
}
Within the timer callback:
//are we currently seeking?
if (seekInProgress_)
{ //yes->did the playback-time change since the seeking has been triggered?
if (seekingTowards_ != movieController_.currentPlaybackTime)
{ //yes->we are now in seek-recovery state
seekingRecoverySince_ = movieController_.currentPlaybackTime;
seekRecoveryInProgress_ = YES;
seekInProgress_ = NO;
seekingTowards_ = 0.0;
}
}
//are we currently recovering from seeking?
else if (seekRecoveryInProgress_)
{ //yes->did the playback-time change since the seeking-recovery has been triggered?
if (seekingRecoverySince_ != movieController_.currentPlaybackTime)
{ //yes->seek recovery done!
seekRecoveryInProgress_ = NO;
seekingRecoverySince_ = 0.0;
}
}
In the end, MPMoviePlayerController simply is not really meant for such "micro-management". I had to throw in at least half a dozen flags for state coverage in all kinds of situations and I would never recommend to repeat this within other projects. Once you reach this level, it might be a great idea to think about using AVPlayer instead.

Posting scores for all GameCenter players

Can you post score in GameCenter for all players at once ? It seems that the API allows only to post for current player. I am trying to implement vote capability allowing current player to vote / score other players in GameCenter.
GKScore* gkScore = [[GKScore alloc] initWithCategory:category];
gkScore.value = score;
// ??? Score for current player ONLY - how to record score for other players ???
[gkScore reportScoreWithCompletionHandler:
^(NSError* error) {
....
BOOL success = (error == nil);
[delegate onScoresSubmitted:success];
}];
You can only post scores for the current player. This is for security purposes.
If multiple people are playing the same game, when they open up their app on their own device, that is when you submit the score.
With iOS 7, this is no longer true. But you can only do so when ending the game, using
endMatchInTurnWithMatchData:scores:achievements:completionHandler:

Resources